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 "pbd/error.h"
32 #include "pbd/basename.h"
33 #include "pbd/pthread_utils.h"
34 #include "pbd/memento_command.h"
35 #include "pbd/unwind.h"
36 #include "pbd/whitespace.h"
37 #include "pbd/stateful_diff_command.h"
39 #include <gtkmm2ext/utils.h>
40 #include <gtkmm2ext/choice.h>
41 #include <gtkmm2ext/popup.h>
43 #include "ardour/audio_track.h"
44 #include "ardour/audioregion.h"
45 #include "ardour/boost_debug.h"
46 #include "ardour/dB.h"
47 #include "ardour/location.h"
48 #include "ardour/midi_region.h"
49 #include "ardour/midi_track.h"
50 #include "ardour/operations.h"
51 #include "ardour/playlist_factory.h"
52 #include "ardour/profile.h"
53 #include "ardour/quantize.h"
54 #include "ardour/legatize.h"
55 #include "ardour/region_factory.h"
56 #include "ardour/reverse.h"
57 #include "ardour/session.h"
58 #include "ardour/session_playlists.h"
59 #include "ardour/strip_silence.h"
60 #include "ardour/transient_detector.h"
61 #include "ardour/transpose.h"
63 #include "canvas/canvas.h"
66 #include "audio_region_view.h"
67 #include "audio_streamview.h"
68 #include "audio_time_axis.h"
69 #include "automation_region_view.h"
70 #include "automation_time_axis.h"
71 #include "control_point.h"
75 #include "editor_cursors.h"
76 #include "editor_drag.h"
77 #include "editor_regions.h"
78 #include "editor_routes.h"
79 #include "gui_thread.h"
80 #include "insert_remove_time_dialog.h"
81 #include "interthread_progress_window.h"
82 #include "item_counts.h"
84 #include "midi_region_view.h"
85 #include "mixer_strip.h"
86 #include "mouse_cursors.h"
87 #include "normalize_dialog.h"
89 #include "paste_context.h"
90 #include "patch_change_dialog.h"
91 #include "quantize_dialog.h"
92 #include "region_gain_line.h"
93 #include "rgb_macros.h"
94 #include "route_time_axis.h"
95 #include "selection.h"
96 #include "selection_templates.h"
97 #include "streamview.h"
98 #include "strip_silence_dialog.h"
99 #include "time_axis_view.h"
101 #include "transpose_dialog.h"
102 #include "transform_dialog.h"
103 #include "ui_config.h"
105 #include "pbd/i18n.h"
108 using namespace ARDOUR;
111 using namespace Gtkmm2ext;
112 using namespace Editing;
113 using Gtkmm2ext::Keyboard;
115 /***********************************************************************
117 ***********************************************************************/
120 Editor::undo (uint32_t n)
122 if (_drags->active ()) {
128 if (_session->undo_depth() == 0) {
129 undo_action->set_sensitive(false);
131 redo_action->set_sensitive(true);
132 begin_selection_op_history ();
137 Editor::redo (uint32_t n)
139 if (_drags->active ()) {
145 if (_session->redo_depth() == 0) {
146 redo_action->set_sensitive(false);
148 undo_action->set_sensitive(true);
149 begin_selection_op_history ();
154 Editor::split_regions_at (framepos_t where, RegionSelection& regions, const int32_t sub_num)
158 RegionSelection pre_selected_regions = selection->regions;
159 bool working_on_selection = !pre_selected_regions.empty();
161 list<boost::shared_ptr<Playlist> > used_playlists;
162 list<RouteTimeAxisView*> used_trackviews;
164 if (regions.empty()) {
168 begin_reversible_command (_("split"));
170 // if splitting a single region, and snap-to is using
171 // region boundaries, don't pay attention to them
173 if (regions.size() == 1) {
174 switch (_snap_type) {
175 case SnapToRegionStart:
176 case SnapToRegionSync:
177 case SnapToRegionEnd:
186 EditorFreeze(); /* Emit Signal */
189 for (RegionSelection::iterator a = regions.begin(); a != regions.end(); ) {
191 RegionSelection::iterator tmp;
193 /* XXX this test needs to be more complicated, to make sure we really
194 have something to split.
197 if (!(*a)->region()->covers (where)) {
205 boost::shared_ptr<Playlist> pl = (*a)->region()->playlist();
213 /* we haven't seen this playlist before */
215 /* remember used playlists so we can thaw them later */
216 used_playlists.push_back(pl);
218 TimeAxisView& tv = (*a)->get_time_axis_view();
219 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (&tv);
221 used_trackviews.push_back (rtv);
228 pl->clear_changes ();
229 pl->split_region ((*a)->region(), where, sub_num);
230 _session->add_command (new StatefulDiffCommand (pl));
236 latest_regionviews.clear ();
238 vector<sigc::connection> region_added_connections;
240 for (list<RouteTimeAxisView*>::iterator i = used_trackviews.begin(); i != used_trackviews.end(); ++i) {
241 region_added_connections.push_back ((*i)->view()->RegionViewAdded.connect (sigc::mem_fun(*this, &Editor::collect_new_region_view)));
244 while (used_playlists.size() > 0) {
245 list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
247 used_playlists.pop_front();
250 for (vector<sigc::connection>::iterator c = region_added_connections.begin(); c != region_added_connections.end(); ++c) {
255 EditorThaw(); /* Emit Signal */
258 if (working_on_selection) {
259 // IFF we were working on selected regions, try to reinstate the other region selections that existed before the freeze/thaw.
261 _ignore_follow_edits = true; // a split will change the region selection in mysterious ways; it's not practical or wanted to follow this edit
262 RegionSelectionAfterSplit rsas = Config->get_region_selection_after_split();
263 /* There are three classes of regions that we might want selected after
264 splitting selected regions:
265 - regions selected before the split operation, and unaffected by it
266 - newly-created regions before the split
267 - newly-created regions after the split
270 if (rsas & Existing) {
271 // region selections that existed before the split.
272 selection->add ( pre_selected_regions );
275 for (RegionSelection::iterator ri = latest_regionviews.begin(); ri != latest_regionviews.end(); ri++) {
276 if ((*ri)->region()->position() < where) {
277 // new regions created before the split
278 if (rsas & NewlyCreatedLeft) {
279 selection->add (*ri);
282 // new regions created after the split
283 if (rsas & NewlyCreatedRight) {
284 selection->add (*ri);
288 _ignore_follow_edits = false;
290 _ignore_follow_edits = true;
291 if( working_on_selection ) {
292 selection->add (latest_regionviews); //these are the new regions created after the split
294 _ignore_follow_edits = false;
297 commit_reversible_command ();
300 /** Move one extreme of the current range selection. If more than one range is selected,
301 * the start of the earliest range or the end of the latest range is moved.
303 * @param move_end true to move the end of the current range selection, false to move
305 * @param next true to move the extreme to the next region boundary, false to move to
309 Editor::move_range_selection_start_or_end_to_region_boundary (bool move_end, bool next)
311 if (selection->time.start() == selection->time.end_frame()) {
315 framepos_t start = selection->time.start ();
316 framepos_t end = selection->time.end_frame ();
318 /* the position of the thing we may move */
319 framepos_t pos = move_end ? end : start;
320 int dir = next ? 1 : -1;
322 /* so we don't find the current region again */
323 if (dir > 0 || pos > 0) {
327 framepos_t const target = get_region_boundary (pos, dir, true, false);
342 begin_reversible_selection_op (_("alter selection"));
343 selection->set_preserving_all_ranges (start, end);
344 commit_reversible_selection_op ();
348 Editor::nudge_forward_release (GdkEventButton* ev)
350 if (ev->state & Keyboard::PrimaryModifier) {
351 nudge_forward (false, true);
353 nudge_forward (false, false);
359 Editor::nudge_backward_release (GdkEventButton* ev)
361 if (ev->state & Keyboard::PrimaryModifier) {
362 nudge_backward (false, true);
364 nudge_backward (false, false);
371 Editor::nudge_forward (bool next, bool force_playhead)
374 framepos_t next_distance;
380 RegionSelection rs = get_regions_from_selection_and_entered ();
382 if (!force_playhead && !rs.empty()) {
384 begin_reversible_command (_("nudge regions forward"));
386 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
387 boost::shared_ptr<Region> r ((*i)->region());
389 distance = get_nudge_distance (r->position(), next_distance);
392 distance = next_distance;
396 r->set_position (r->position() + distance);
397 _session->add_command (new StatefulDiffCommand (r));
400 commit_reversible_command ();
403 } else if (!force_playhead && !selection->markers.empty()) {
406 bool in_command = false;
408 for (MarkerSelection::iterator i = selection->markers.begin(); i != selection->markers.end(); ++i) {
410 Location* loc = find_location_from_marker ((*i), is_start);
414 XMLNode& before (loc->get_state());
417 distance = get_nudge_distance (loc->start(), next_distance);
419 distance = next_distance;
421 if (max_framepos - distance > loc->start() + loc->length()) {
422 loc->set_start (loc->start() + distance);
424 loc->set_start (max_framepos - loc->length());
427 distance = get_nudge_distance (loc->end(), next_distance);
429 distance = next_distance;
431 if (max_framepos - distance > loc->end()) {
432 loc->set_end (loc->end() + distance);
434 loc->set_end (max_framepos);
436 if (loc->is_session_range()) {
437 _session->set_end_is_free (false);
441 begin_reversible_command (_("nudge location forward"));
444 XMLNode& after (loc->get_state());
445 _session->add_command (new MementoCommand<Location>(*loc, &before, &after));
450 commit_reversible_command ();
453 distance = get_nudge_distance (playhead_cursor->current_frame (), next_distance);
454 _session->request_locate (playhead_cursor->current_frame () + distance);
459 Editor::nudge_backward (bool next, bool force_playhead)
462 framepos_t next_distance;
468 RegionSelection rs = get_regions_from_selection_and_entered ();
470 if (!force_playhead && !rs.empty()) {
472 begin_reversible_command (_("nudge regions backward"));
474 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
475 boost::shared_ptr<Region> r ((*i)->region());
477 distance = get_nudge_distance (r->position(), next_distance);
480 distance = next_distance;
485 if (r->position() > distance) {
486 r->set_position (r->position() - distance);
490 _session->add_command (new StatefulDiffCommand (r));
493 commit_reversible_command ();
495 } else if (!force_playhead && !selection->markers.empty()) {
498 bool in_command = false;
500 for (MarkerSelection::iterator i = selection->markers.begin(); i != selection->markers.end(); ++i) {
502 Location* loc = find_location_from_marker ((*i), is_start);
506 XMLNode& before (loc->get_state());
509 distance = get_nudge_distance (loc->start(), next_distance);
511 distance = next_distance;
513 if (distance < loc->start()) {
514 loc->set_start (loc->start() - distance);
519 distance = get_nudge_distance (loc->end(), next_distance);
522 distance = next_distance;
525 if (distance < loc->end() - loc->length()) {
526 loc->set_end (loc->end() - distance);
528 loc->set_end (loc->length());
530 if (loc->is_session_range()) {
531 _session->set_end_is_free (false);
535 begin_reversible_command (_("nudge location forward"));
538 XMLNode& after (loc->get_state());
539 _session->add_command (new MementoCommand<Location>(*loc, &before, &after));
543 commit_reversible_command ();
548 distance = get_nudge_distance (playhead_cursor->current_frame (), next_distance);
550 if (playhead_cursor->current_frame () > distance) {
551 _session->request_locate (playhead_cursor->current_frame () - distance);
553 _session->goto_start();
559 Editor::nudge_forward_capture_offset ()
561 RegionSelection rs = get_regions_from_selection_and_entered ();
563 if (!_session || rs.empty()) {
567 begin_reversible_command (_("nudge forward"));
569 framepos_t const distance = _session->worst_output_latency();
571 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
572 boost::shared_ptr<Region> r ((*i)->region());
575 r->set_position (r->position() + distance);
576 _session->add_command(new StatefulDiffCommand (r));
579 commit_reversible_command ();
583 Editor::nudge_backward_capture_offset ()
585 RegionSelection rs = get_regions_from_selection_and_entered ();
587 if (!_session || rs.empty()) {
591 begin_reversible_command (_("nudge backward"));
593 framepos_t const distance = _session->worst_output_latency();
595 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
596 boost::shared_ptr<Region> r ((*i)->region());
600 if (r->position() > distance) {
601 r->set_position (r->position() - distance);
605 _session->add_command(new StatefulDiffCommand (r));
608 commit_reversible_command ();
611 struct RegionSelectionPositionSorter {
612 bool operator() (RegionView* a, RegionView* b) {
613 return a->region()->position() < b->region()->position();
618 Editor::sequence_regions ()
621 framepos_t r_end_prev;
629 RegionSelection rs = get_regions_from_selection_and_entered ();
630 rs.sort(RegionSelectionPositionSorter());
634 bool in_command = false;
636 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
637 boost::shared_ptr<Region> r ((*i)->region());
645 if(r->position_locked())
652 r->set_position(r_end_prev);
656 begin_reversible_command (_("sequence regions"));
659 _session->add_command (new StatefulDiffCommand (r));
661 r_end=r->position() + r->length();
667 commit_reversible_command ();
676 Editor::move_to_start ()
678 _session->goto_start ();
682 Editor::move_to_end ()
685 _session->request_locate (_session->current_end_frame());
689 Editor::build_region_boundary_cache ()
692 vector<RegionPoint> interesting_points;
693 boost::shared_ptr<Region> r;
694 TrackViewList tracks;
697 region_boundary_cache.clear ();
703 switch (_snap_type) {
704 case SnapToRegionStart:
705 interesting_points.push_back (Start);
707 case SnapToRegionEnd:
708 interesting_points.push_back (End);
710 case SnapToRegionSync:
711 interesting_points.push_back (SyncPoint);
713 case SnapToRegionBoundary:
714 interesting_points.push_back (Start);
715 interesting_points.push_back (End);
718 fatal << string_compose (_("build_region_boundary_cache called with snap_type = %1"), _snap_type) << endmsg;
719 abort(); /*NOTREACHED*/
723 TimeAxisView *ontrack = 0;
726 if (!selection->tracks.empty()) {
727 tlist = selection->tracks.filter_to_unique_playlists ();
729 tlist = track_views.filter_to_unique_playlists ();
732 while (pos < _session->current_end_frame() && !at_end) {
735 framepos_t lpos = max_framepos;
737 for (vector<RegionPoint>::iterator p = interesting_points.begin(); p != interesting_points.end(); ++p) {
739 if ((r = find_next_region (pos, *p, 1, tlist, &ontrack)) == 0) {
740 if (*p == interesting_points.back()) {
743 /* move to next point type */
749 rpos = r->first_frame();
753 rpos = r->last_frame();
757 rpos = r->sync_position ();
765 RouteTimeAxisView *rtav;
767 if (ontrack != 0 && (rtav = dynamic_cast<RouteTimeAxisView*>(ontrack)) != 0 ) {
768 if (rtav->track() != 0) {
769 speed = rtav->track()->speed();
773 rpos = track_frame_to_session_frame (rpos, speed);
779 /* prevent duplicates, but we don't use set<> because we want to be able
783 vector<framepos_t>::iterator ri;
785 for (ri = region_boundary_cache.begin(); ri != region_boundary_cache.end(); ++ri) {
791 if (ri == region_boundary_cache.end()) {
792 region_boundary_cache.push_back (rpos);
799 /* finally sort to be sure that the order is correct */
801 sort (region_boundary_cache.begin(), region_boundary_cache.end());
804 boost::shared_ptr<Region>
805 Editor::find_next_region (framepos_t frame, RegionPoint point, int32_t dir, TrackViewList& tracks, TimeAxisView **ontrack)
807 TrackViewList::iterator i;
808 framepos_t closest = max_framepos;
809 boost::shared_ptr<Region> ret;
813 framepos_t track_frame;
814 RouteTimeAxisView *rtav;
816 for (i = tracks.begin(); i != tracks.end(); ++i) {
819 boost::shared_ptr<Region> r;
822 if ( (rtav = dynamic_cast<RouteTimeAxisView*>(*i)) != 0 ) {
823 if (rtav->track()!=0)
824 track_speed = rtav->track()->speed();
827 track_frame = session_frame_to_track_frame(frame, track_speed);
829 if ((r = (*i)->find_next_region (track_frame, point, dir)) == 0) {
835 rpos = r->first_frame ();
839 rpos = r->last_frame ();
843 rpos = r->sync_position ();
847 // rpos is a "track frame", converting it to "_session frame"
848 rpos = track_frame_to_session_frame(rpos, track_speed);
851 distance = rpos - frame;
853 distance = frame - rpos;
856 if (distance < closest) {
868 Editor::find_next_region_boundary (framepos_t pos, int32_t dir, const TrackViewList& tracks)
870 framecnt_t distance = max_framepos;
871 framepos_t current_nearest = -1;
873 for (TrackViewList::const_iterator i = tracks.begin(); i != tracks.end(); ++i) {
874 framepos_t contender;
877 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*i);
883 if ((contender = rtv->find_next_region_boundary (pos, dir)) < 0) {
887 d = ::llabs (pos - contender);
890 current_nearest = contender;
895 return current_nearest;
899 Editor::get_region_boundary (framepos_t pos, int32_t dir, bool with_selection, bool only_onscreen)
904 if (with_selection && Config->get_region_boundaries_from_selected_tracks()) {
906 if (!selection->tracks.empty()) {
908 target = find_next_region_boundary (pos, dir, selection->tracks);
912 if (only_onscreen || Config->get_region_boundaries_from_onscreen_tracks()) {
913 get_onscreen_tracks (tvl);
914 target = find_next_region_boundary (pos, dir, tvl);
916 target = find_next_region_boundary (pos, dir, track_views);
922 if (only_onscreen || Config->get_region_boundaries_from_onscreen_tracks()) {
923 get_onscreen_tracks (tvl);
924 target = find_next_region_boundary (pos, dir, tvl);
926 target = find_next_region_boundary (pos, dir, track_views);
934 Editor::cursor_to_region_boundary (bool with_selection, int32_t dir)
936 framepos_t pos = playhead_cursor->current_frame ();
943 // so we don't find the current region again..
944 if (dir > 0 || pos > 0) {
948 if ((target = get_region_boundary (pos, dir, with_selection, false)) < 0) {
952 _session->request_locate (target);
956 Editor::cursor_to_next_region_boundary (bool with_selection)
958 cursor_to_region_boundary (with_selection, 1);
962 Editor::cursor_to_previous_region_boundary (bool with_selection)
964 cursor_to_region_boundary (with_selection, -1);
968 Editor::cursor_to_region_point (EditorCursor* cursor, RegionPoint point, int32_t dir)
970 boost::shared_ptr<Region> r;
971 framepos_t pos = cursor->current_frame ();
977 TimeAxisView *ontrack = 0;
979 // so we don't find the current region again..
983 if (!selection->tracks.empty()) {
985 r = find_next_region (pos, point, dir, selection->tracks, &ontrack);
987 } else if (clicked_axisview) {
990 t.push_back (clicked_axisview);
992 r = find_next_region (pos, point, dir, t, &ontrack);
996 r = find_next_region (pos, point, dir, track_views, &ontrack);
1005 pos = r->first_frame ();
1009 pos = r->last_frame ();
1013 pos = r->sync_position ();
1018 RouteTimeAxisView *rtav;
1020 if ( ontrack != 0 && (rtav = dynamic_cast<RouteTimeAxisView*>(ontrack)) != 0 ) {
1021 if (rtav->track() != 0) {
1022 speed = rtav->track()->speed();
1026 pos = track_frame_to_session_frame(pos, speed);
1028 if (cursor == playhead_cursor) {
1029 _session->request_locate (pos);
1031 cursor->set_position (pos);
1036 Editor::cursor_to_next_region_point (EditorCursor* cursor, RegionPoint point)
1038 cursor_to_region_point (cursor, point, 1);
1042 Editor::cursor_to_previous_region_point (EditorCursor* cursor, RegionPoint point)
1044 cursor_to_region_point (cursor, point, -1);
1048 Editor::cursor_to_selection_start (EditorCursor *cursor)
1052 switch (mouse_mode) {
1054 if (!selection->regions.empty()) {
1055 pos = selection->regions.start();
1060 if (!selection->time.empty()) {
1061 pos = selection->time.start ();
1069 if (cursor == playhead_cursor) {
1070 _session->request_locate (pos);
1072 cursor->set_position (pos);
1077 Editor::cursor_to_selection_end (EditorCursor *cursor)
1081 switch (mouse_mode) {
1083 if (!selection->regions.empty()) {
1084 pos = selection->regions.end_frame();
1089 if (!selection->time.empty()) {
1090 pos = selection->time.end_frame ();
1098 if (cursor == playhead_cursor) {
1099 _session->request_locate (pos);
1101 cursor->set_position (pos);
1106 Editor::selected_marker_to_region_boundary (bool with_selection, int32_t dir)
1116 if (selection->markers.empty()) {
1120 if (!mouse_frame (mouse, ignored)) {
1124 add_location_mark (mouse);
1127 if ((loc = find_location_from_marker (selection->markers.front(), ignored)) == 0) {
1131 framepos_t pos = loc->start();
1133 // so we don't find the current region again..
1134 if (dir > 0 || pos > 0) {
1138 if ((target = get_region_boundary (pos, dir, with_selection, false)) < 0) {
1142 loc->move_to (target);
1146 Editor::selected_marker_to_next_region_boundary (bool with_selection)
1148 selected_marker_to_region_boundary (with_selection, 1);
1152 Editor::selected_marker_to_previous_region_boundary (bool with_selection)
1154 selected_marker_to_region_boundary (with_selection, -1);
1158 Editor::selected_marker_to_region_point (RegionPoint point, int32_t dir)
1160 boost::shared_ptr<Region> r;
1165 if (!_session || selection->markers.empty()) {
1169 if ((loc = find_location_from_marker (selection->markers.front(), ignored)) == 0) {
1173 TimeAxisView *ontrack = 0;
1177 // so we don't find the current region again..
1181 if (!selection->tracks.empty()) {
1183 r = find_next_region (pos, point, dir, selection->tracks, &ontrack);
1187 r = find_next_region (pos, point, dir, track_views, &ontrack);
1196 pos = r->first_frame ();
1200 pos = r->last_frame ();
1204 pos = r->adjust_to_sync (r->first_frame());
1209 RouteTimeAxisView *rtav;
1211 if (ontrack != 0 && (rtav = dynamic_cast<RouteTimeAxisView*>(ontrack)) != 0) {
1212 if (rtav->track() != 0) {
1213 speed = rtav->track()->speed();
1217 pos = track_frame_to_session_frame(pos, speed);
1223 Editor::selected_marker_to_next_region_point (RegionPoint point)
1225 selected_marker_to_region_point (point, 1);
1229 Editor::selected_marker_to_previous_region_point (RegionPoint point)
1231 selected_marker_to_region_point (point, -1);
1235 Editor::selected_marker_to_selection_start ()
1241 if (!_session || selection->markers.empty()) {
1245 if ((loc = find_location_from_marker (selection->markers.front(), ignored)) == 0) {
1249 switch (mouse_mode) {
1251 if (!selection->regions.empty()) {
1252 pos = selection->regions.start();
1257 if (!selection->time.empty()) {
1258 pos = selection->time.start ();
1270 Editor::selected_marker_to_selection_end ()
1276 if (!_session || selection->markers.empty()) {
1280 if ((loc = find_location_from_marker (selection->markers.front(), ignored)) == 0) {
1284 switch (mouse_mode) {
1286 if (!selection->regions.empty()) {
1287 pos = selection->regions.end_frame();
1292 if (!selection->time.empty()) {
1293 pos = selection->time.end_frame ();
1305 Editor::scroll_playhead (bool forward)
1307 framepos_t pos = playhead_cursor->current_frame ();
1308 framecnt_t delta = (framecnt_t) floor (current_page_samples() / 0.8);
1311 if (pos == max_framepos) {
1315 if (pos < max_framepos - delta) {
1334 _session->request_locate (pos);
1338 Editor::cursor_align (bool playhead_to_edit)
1344 if (playhead_to_edit) {
1346 if (selection->markers.empty()) {
1350 _session->request_locate (selection->markers.front()->position(), _session->transport_rolling());
1353 /* move selected markers to playhead */
1355 for (MarkerSelection::iterator i = selection->markers.begin(); i != selection->markers.end(); ++i) {
1358 Location* loc = find_location_from_marker (*i, ignored);
1360 if (loc->is_mark()) {
1361 loc->set_start (playhead_cursor->current_frame ());
1363 loc->set (playhead_cursor->current_frame (),
1364 playhead_cursor->current_frame () + loc->length());
1371 Editor::scroll_backward (float pages)
1373 framepos_t const one_page = (framepos_t) rint (_visible_canvas_width * samples_per_pixel);
1374 framepos_t const cnt = (framepos_t) floor (pages * one_page);
1377 if (leftmost_frame < cnt) {
1380 frame = leftmost_frame - cnt;
1383 reset_x_origin (frame);
1387 Editor::scroll_forward (float pages)
1389 framepos_t const one_page = (framepos_t) rint (_visible_canvas_width * samples_per_pixel);
1390 framepos_t const cnt = (framepos_t) floor (pages * one_page);
1393 if (max_framepos - cnt < leftmost_frame) {
1394 frame = max_framepos - cnt;
1396 frame = leftmost_frame + cnt;
1399 reset_x_origin (frame);
1403 Editor::scroll_tracks_down ()
1405 double vert_value = vertical_adjustment.get_value() + vertical_adjustment.get_page_size();
1406 if (vert_value > vertical_adjustment.get_upper() - _visible_canvas_height) {
1407 vert_value = vertical_adjustment.get_upper() - _visible_canvas_height;
1410 vertical_adjustment.set_value (vert_value);
1414 Editor::scroll_tracks_up ()
1416 vertical_adjustment.set_value (vertical_adjustment.get_value() - vertical_adjustment.get_page_size());
1420 Editor::scroll_tracks_down_line ()
1422 double vert_value = vertical_adjustment.get_value() + 60;
1424 if (vert_value > vertical_adjustment.get_upper() - _visible_canvas_height) {
1425 vert_value = vertical_adjustment.get_upper() - _visible_canvas_height;
1428 vertical_adjustment.set_value (vert_value);
1432 Editor::scroll_tracks_up_line ()
1434 reset_y_origin (vertical_adjustment.get_value() - 60);
1438 Editor::scroll_down_one_track (bool skip_child_views)
1440 TrackViewList::reverse_iterator next = track_views.rend();
1441 const double top_of_trackviews = vertical_adjustment.get_value();
1443 for (TrackViewList::reverse_iterator t = track_views.rbegin(); t != track_views.rend(); ++t) {
1444 if ((*t)->hidden()) {
1448 /* If this is the upper-most visible trackview, we want to display
1449 * the one above it (next)
1451 * Note that covers_y_position() is recursive and includes child views
1453 std::pair<TimeAxisView*,double> res = (*t)->covers_y_position (top_of_trackviews);
1456 if (skip_child_views) {
1459 /* automation lane (one level, non-recursive)
1461 * - if no automation lane exists -> move to next tack
1462 * - if the first (here: bottom-most) matches -> move to next tack
1463 * - if no y-axis match is found -> the current track is at the top
1464 * -> move to last (here: top-most) automation lane
1466 TimeAxisView::Children kids = (*t)->get_child_list();
1467 TimeAxisView::Children::reverse_iterator nkid = kids.rend();
1469 for (TimeAxisView::Children::reverse_iterator ci = kids.rbegin(); ci != kids.rend(); ++ci) {
1470 if ((*ci)->hidden()) {
1474 std::pair<TimeAxisView*,double> dev;
1475 dev = (*ci)->covers_y_position (top_of_trackviews);
1477 /* some automation lane is currently at the top */
1478 if (ci == kids.rbegin()) {
1479 /* first (bottom-most) autmation lane is at the top.
1480 * -> move to next track
1489 if (nkid != kids.rend()) {
1490 ensure_time_axis_view_is_visible (**nkid, true);
1498 /* move to the track below the first one that covers the */
1500 if (next != track_views.rend()) {
1501 ensure_time_axis_view_is_visible (**next, true);
1509 Editor::scroll_up_one_track (bool skip_child_views)
1511 TrackViewList::iterator prev = track_views.end();
1512 double top_of_trackviews = vertical_adjustment.get_value ();
1514 for (TrackViewList::iterator t = track_views.begin(); t != track_views.end(); ++t) {
1516 if ((*t)->hidden()) {
1520 /* find the trackview at the top of the trackview group
1522 * Note that covers_y_position() is recursive and includes child views
1524 std::pair<TimeAxisView*,double> res = (*t)->covers_y_position (top_of_trackviews);
1527 if (skip_child_views) {
1530 /* automation lane (one level, non-recursive)
1532 * - if no automation lane exists -> move to prev tack
1533 * - if no y-axis match is found -> the current track is at the top -> move to prev track
1534 * (actually last automation lane of previous track, see below)
1535 * - if first (top-most) lane is at the top -> move to this track
1536 * - else move up one lane
1538 TimeAxisView::Children kids = (*t)->get_child_list();
1539 TimeAxisView::Children::iterator pkid = kids.end();
1541 for (TimeAxisView::Children::iterator ci = kids.begin(); ci != kids.end(); ++ci) {
1542 if ((*ci)->hidden()) {
1546 std::pair<TimeAxisView*,double> dev;
1547 dev = (*ci)->covers_y_position (top_of_trackviews);
1549 /* some automation lane is currently at the top */
1550 if (ci == kids.begin()) {
1551 /* first (top-most) autmation lane is at the top.
1552 * jump directly to this track's top
1554 ensure_time_axis_view_is_visible (**t, true);
1557 else if (pkid != kids.end()) {
1558 /* some other automation lane is at the top.
1559 * move up to prev automation lane.
1561 ensure_time_axis_view_is_visible (**pkid, true);
1564 assert(0); // not reached
1575 if (prev != track_views.end()) {
1576 // move to bottom-most automation-lane of the previous track
1577 TimeAxisView::Children kids = (*prev)->get_child_list();
1578 TimeAxisView::Children::reverse_iterator pkid = kids.rend();
1579 if (!skip_child_views) {
1580 // find the last visible lane
1581 for (TimeAxisView::Children::reverse_iterator ci = kids.rbegin(); ci != kids.rend(); ++ci) {
1582 if (!(*ci)->hidden()) {
1588 if (pkid != kids.rend()) {
1589 ensure_time_axis_view_is_visible (**pkid, true);
1591 ensure_time_axis_view_is_visible (**prev, true);
1600 Editor::scroll_left_step ()
1602 framepos_t xdelta = (current_page_samples() / 8);
1604 if (leftmost_frame > xdelta) {
1605 reset_x_origin (leftmost_frame - xdelta);
1613 Editor::scroll_right_step ()
1615 framepos_t xdelta = (current_page_samples() / 8);
1617 if (max_framepos - xdelta > leftmost_frame) {
1618 reset_x_origin (leftmost_frame + xdelta);
1620 reset_x_origin (max_framepos - current_page_samples());
1625 Editor::scroll_left_half_page ()
1627 framepos_t xdelta = (current_page_samples() / 2);
1628 if (leftmost_frame > xdelta) {
1629 reset_x_origin (leftmost_frame - xdelta);
1636 Editor::scroll_right_half_page ()
1638 framepos_t xdelta = (current_page_samples() / 2);
1639 if (max_framepos - xdelta > leftmost_frame) {
1640 reset_x_origin (leftmost_frame + xdelta);
1642 reset_x_origin (max_framepos - current_page_samples());
1649 Editor::tav_zoom_step (bool coarser)
1651 DisplaySuspender ds;
1655 if (selection->tracks.empty()) {
1658 ts = &selection->tracks;
1661 for (TrackViewList::iterator i = ts->begin(); i != ts->end(); ++i) {
1662 TimeAxisView *tv = (static_cast<TimeAxisView*>(*i));
1663 tv->step_height (coarser);
1668 Editor::tav_zoom_smooth (bool coarser, bool force_all)
1670 DisplaySuspender ds;
1674 if (selection->tracks.empty() || force_all) {
1677 ts = &selection->tracks;
1680 for (TrackViewList::iterator i = ts->begin(); i != ts->end(); ++i) {
1681 TimeAxisView *tv = (static_cast<TimeAxisView*>(*i));
1682 uint32_t h = tv->current_height ();
1687 if (h >= TimeAxisView::preset_height (HeightSmall)) {
1692 tv->set_height (h + 5);
1698 Editor::temporal_zoom_step_mouse_focus (bool coarser)
1700 Editing::ZoomFocus temp_focus = zoom_focus;
1701 zoom_focus = Editing::ZoomFocusMouse;
1702 temporal_zoom_step (coarser);
1703 zoom_focus = temp_focus;
1707 Editor::temporal_zoom_step (bool coarser)
1709 ENSURE_GUI_THREAD (*this, &Editor::temporal_zoom_step, coarser)
1711 framecnt_t nspp = samples_per_pixel;
1719 temporal_zoom (nspp);
1723 Editor::temporal_zoom (framecnt_t fpp)
1729 framepos_t current_page = current_page_samples();
1730 framepos_t current_leftmost = leftmost_frame;
1731 framepos_t current_rightmost;
1732 framepos_t current_center;
1733 framepos_t new_page_size;
1734 framepos_t half_page_size;
1735 framepos_t leftmost_after_zoom = 0;
1737 bool in_track_canvas;
1741 if (fpp == samples_per_pixel) {
1745 // Imposing an arbitrary limit to zoom out as too much zoom out produces
1746 // segfaults for lack of memory. If somebody decides this is not high enough I
1747 // believe it can be raisen to higher values but some limit must be in place.
1749 // This constant represents 1 day @ 48kHz on a 1600 pixel wide display
1750 // all of which is used for the editor track displays. The whole day
1751 // would be 4147200000 samples, so 2592000 samples per pixel.
1753 nfpp = min (fpp, (framecnt_t) 2592000);
1754 nfpp = max ((framecnt_t) 1, nfpp);
1756 new_page_size = (framepos_t) floor (_visible_canvas_width * nfpp);
1757 half_page_size = new_page_size / 2;
1759 switch (zoom_focus) {
1761 leftmost_after_zoom = current_leftmost;
1764 case ZoomFocusRight:
1765 current_rightmost = leftmost_frame + current_page;
1766 if (current_rightmost < new_page_size) {
1767 leftmost_after_zoom = 0;
1769 leftmost_after_zoom = current_rightmost - new_page_size;
1773 case ZoomFocusCenter:
1774 current_center = current_leftmost + (current_page/2);
1775 if (current_center < half_page_size) {
1776 leftmost_after_zoom = 0;
1778 leftmost_after_zoom = current_center - half_page_size;
1782 case ZoomFocusPlayhead:
1783 /* centre playhead */
1784 l = playhead_cursor->current_frame () - (new_page_size * 0.5);
1787 leftmost_after_zoom = 0;
1788 } else if (l > max_framepos) {
1789 leftmost_after_zoom = max_framepos - new_page_size;
1791 leftmost_after_zoom = (framepos_t) l;
1795 case ZoomFocusMouse:
1796 /* try to keep the mouse over the same point in the display */
1798 if (!mouse_frame (where, in_track_canvas)) {
1799 /* use playhead instead */
1800 where = playhead_cursor->current_frame ();
1802 if (where < half_page_size) {
1803 leftmost_after_zoom = 0;
1805 leftmost_after_zoom = where - half_page_size;
1810 l = - ((new_page_size * ((where - current_leftmost)/(double)current_page)) - where);
1813 leftmost_after_zoom = 0;
1814 } else if (l > max_framepos) {
1815 leftmost_after_zoom = max_framepos - new_page_size;
1817 leftmost_after_zoom = (framepos_t) l;
1824 /* try to keep the edit point in the same place */
1825 where = get_preferred_edit_position ();
1829 double l = - ((new_page_size * ((where - current_leftmost)/(double)current_page)) - where);
1832 leftmost_after_zoom = 0;
1833 } else if (l > max_framepos) {
1834 leftmost_after_zoom = max_framepos - new_page_size;
1836 leftmost_after_zoom = (framepos_t) l;
1840 /* edit point not defined */
1847 // leftmost_after_zoom = min (leftmost_after_zoom, _session->current_end_frame());
1849 reposition_and_zoom (leftmost_after_zoom, nfpp);
1853 Editor::calc_extra_zoom_edges(framepos_t &start, framepos_t &end)
1855 /* this func helps make sure we leave a little space
1856 at each end of the editor so that the zoom doesn't fit the region
1857 precisely to the screen.
1860 GdkScreen* screen = gdk_screen_get_default ();
1861 const gint pixwidth = gdk_screen_get_width (screen);
1862 const gint mmwidth = gdk_screen_get_width_mm (screen);
1863 const double pix_per_mm = (double) pixwidth/ (double) mmwidth;
1864 const double one_centimeter_in_pixels = pix_per_mm * 10.0;
1866 const framepos_t range = end - start;
1867 const framecnt_t new_fpp = (framecnt_t) ceil ((double) range / (double) _visible_canvas_width);
1868 const framepos_t extra_samples = (framepos_t) floor (one_centimeter_in_pixels * new_fpp);
1870 if (start > extra_samples) {
1871 start -= extra_samples;
1876 if (max_framepos - extra_samples > end) {
1877 end += extra_samples;
1884 Editor::temporal_zoom_region (bool both_axes)
1886 framepos_t start = max_framepos;
1888 set<TimeAxisView*> tracks;
1890 if ( !get_selection_extents(start, end) )
1893 calc_extra_zoom_edges (start, end);
1895 /* if we're zooming on both axes we need to save track heights etc.
1898 undo_visual_stack.push_back (current_visual_state (both_axes));
1900 PBD::Unwinder<bool> nsv (no_save_visual, true);
1902 temporal_zoom_by_frame (start, end);
1905 uint32_t per_track_height = (uint32_t) floor ((_visible_canvas_height - 10.0) / tracks.size());
1907 /* set visible track heights appropriately */
1909 for (set<TimeAxisView*>::iterator t = tracks.begin(); t != tracks.end(); ++t) {
1910 (*t)->set_height (per_track_height);
1913 /* hide irrelevant tracks */
1915 DisplaySuspender ds;
1917 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1918 if (find (tracks.begin(), tracks.end(), (*i)) == tracks.end()) {
1919 hide_track_in_display (*i);
1923 vertical_adjustment.set_value (0.0);
1926 redo_visual_stack.push_back (current_visual_state (both_axes));
1931 Editor::get_selection_extents (framepos_t &start, framepos_t &end) const
1933 start = max_framepos;
1937 //ToDo: if notes are selected, set extents to that selection
1939 //ToDo: if control points are selected, set extents to that selection
1941 if ( !selection->regions.empty() ) {
1942 RegionSelection rs = get_regions_from_selection_and_entered ();
1944 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
1946 if ((*i)->region()->position() < start) {
1947 start = (*i)->region()->position();
1950 if ((*i)->region()->last_frame() + 1 > end) {
1951 end = (*i)->region()->last_frame() + 1;
1955 } else if (!selection->time.empty()) {
1956 start = selection->time.start();
1957 end = selection->time.end_frame();
1959 ret = false; //no selection found
1962 if ((start == 0 && end == 0) || end < start) {
1971 Editor::temporal_zoom_selection (bool both_axes)
1973 if (!selection) return;
1975 //ToDo: if notes are selected, zoom to that
1977 //ToDo: if control points are selected, zoom to that
1979 //if region(s) are selected, zoom to that
1980 if ( !selection->regions.empty() )
1981 temporal_zoom_region (both_axes);
1983 //if a range is selected, zoom to that
1984 if (!selection->time.empty()) {
1986 framepos_t start, end;
1987 if (get_selection_extents (start, end)) {
1988 calc_extra_zoom_edges(start, end);
1989 temporal_zoom_by_frame (start, end);
1999 Editor::temporal_zoom_session ()
2001 ENSURE_GUI_THREAD (*this, &Editor::temporal_zoom_session)
2004 framecnt_t start = _session->current_start_frame();
2005 framecnt_t end = _session->current_end_frame();
2007 if (_session->actively_recording () ) {
2008 framepos_t cur = playhead_cursor->current_frame ();
2010 /* recording beyond the end marker; zoom out
2011 * by 5 seconds more so that if 'follow
2012 * playhead' is active we don't immediately
2015 end = cur + _session->frame_rate() * 5;
2019 if ((start == 0 && end == 0) || end < start) {
2023 calc_extra_zoom_edges(start, end);
2025 temporal_zoom_by_frame (start, end);
2030 Editor::temporal_zoom_by_frame (framepos_t start, framepos_t end)
2032 if (!_session) return;
2034 if ((start == 0 && end == 0) || end < start) {
2038 framepos_t range = end - start;
2040 const framecnt_t new_fpp = (framecnt_t) ceil ((double) range / (double) _visible_canvas_width);
2042 framepos_t new_page = range;
2043 framepos_t middle = (framepos_t) floor ((double) start + ((double) range / 2.0f));
2044 framepos_t new_leftmost = (framepos_t) floor ((double) middle - ((double) new_page / 2.0f));
2046 if (new_leftmost > middle) {
2050 if (new_leftmost < 0) {
2054 reposition_and_zoom (new_leftmost, new_fpp);
2058 Editor::temporal_zoom_to_frame (bool coarser, framepos_t frame)
2064 framecnt_t range_before = frame - leftmost_frame;
2068 if (samples_per_pixel <= 1) {
2071 new_spp = samples_per_pixel + (samples_per_pixel/2);
2073 range_before += range_before/2;
2075 if (samples_per_pixel >= 1) {
2076 new_spp = samples_per_pixel - (samples_per_pixel/2);
2078 /* could bail out here since we cannot zoom any finer,
2079 but leave that to the equality test below
2081 new_spp = samples_per_pixel;
2084 range_before -= range_before/2;
2087 if (new_spp == samples_per_pixel) {
2091 /* zoom focus is automatically taken as @param frame when this
2095 framepos_t new_leftmost = frame - (framepos_t)range_before;
2097 if (new_leftmost > frame) {
2101 if (new_leftmost < 0) {
2105 reposition_and_zoom (new_leftmost, new_spp);
2110 Editor::choose_new_marker_name(string &name) {
2112 if (!UIConfiguration::instance().get_name_new_markers()) {
2113 /* don't prompt user for a new name */
2117 ArdourPrompter dialog (true);
2119 dialog.set_prompt (_("New Name:"));
2121 dialog.set_title (_("New Location Marker"));
2123 dialog.set_name ("MarkNameWindow");
2124 dialog.set_size_request (250, -1);
2125 dialog.set_position (Gtk::WIN_POS_MOUSE);
2127 dialog.add_button (Stock::OK, RESPONSE_ACCEPT);
2128 dialog.set_initial_text (name);
2132 switch (dialog.run ()) {
2133 case RESPONSE_ACCEPT:
2139 dialog.get_result(name);
2146 Editor::add_location_from_selection ()
2150 if (selection->time.empty()) {
2154 if (_session == 0 || clicked_axisview == 0) {
2158 framepos_t start = selection->time[clicked_selection].start;
2159 framepos_t end = selection->time[clicked_selection].end;
2161 _session->locations()->next_available_name(rangename,"selection");
2162 Location *location = new Location (*_session, start, end, rangename, Location::IsRangeMarker);
2164 begin_reversible_command (_("add marker"));
2166 XMLNode &before = _session->locations()->get_state();
2167 _session->locations()->add (location, true);
2168 XMLNode &after = _session->locations()->get_state();
2169 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2171 commit_reversible_command ();
2175 Editor::add_location_mark (framepos_t where)
2179 select_new_marker = true;
2181 _session->locations()->next_available_name(markername,"mark");
2182 if (!choose_new_marker_name(markername)) {
2185 Location *location = new Location (*_session, where, where, markername, Location::IsMark);
2186 begin_reversible_command (_("add marker"));
2188 XMLNode &before = _session->locations()->get_state();
2189 _session->locations()->add (location, true);
2190 XMLNode &after = _session->locations()->get_state();
2191 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2193 commit_reversible_command ();
2197 Editor::set_session_start_from_playhead ()
2203 if ((loc = _session->locations()->session_range_location()) == 0) { //should never happen
2204 _session->set_session_extents ( _session->audible_frame(), _session->audible_frame() );
2206 XMLNode &before = loc->get_state();
2208 _session->set_session_extents ( _session->audible_frame(), loc->end() );
2210 XMLNode &after = loc->get_state();
2212 begin_reversible_command (_("Set session start"));
2214 _session->add_command (new MementoCommand<Location>(*loc, &before, &after));
2216 commit_reversible_command ();
2221 Editor::set_session_end_from_playhead ()
2227 if ((loc = _session->locations()->session_range_location()) == 0) { //should never happen
2228 _session->set_session_extents ( _session->audible_frame(), _session->audible_frame() );
2230 XMLNode &before = loc->get_state();
2232 _session->set_session_extents ( loc->start(), _session->audible_frame() );
2234 XMLNode &after = loc->get_state();
2236 begin_reversible_command (_("Set session start"));
2238 _session->add_command (new MementoCommand<Location>(*loc, &before, &after));
2240 commit_reversible_command ();
2243 _session->set_end_is_free (false);
2247 Editor::add_location_from_playhead_cursor ()
2249 add_location_mark (_session->audible_frame());
2253 Editor::remove_location_at_playhead_cursor ()
2257 XMLNode &before = _session->locations()->get_state();
2258 bool removed = false;
2260 //find location(s) at this time
2261 Locations::LocationList locs;
2262 _session->locations()->find_all_between (_session->audible_frame(), _session->audible_frame()+1, locs, Location::Flags(0));
2263 for (Locations::LocationList::iterator i = locs.begin(); i != locs.end(); ++i) {
2264 if ((*i)->is_mark()) {
2265 _session->locations()->remove (*i);
2272 begin_reversible_command (_("remove marker"));
2273 XMLNode &after = _session->locations()->get_state();
2274 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2275 commit_reversible_command ();
2280 /** Add a range marker around each selected region */
2282 Editor::add_locations_from_region ()
2284 RegionSelection rs = get_regions_from_selection_and_entered ();
2289 bool commit = false;
2291 XMLNode &before = _session->locations()->get_state();
2293 for (RegionSelection::iterator i = rs.begin (); i != rs.end (); ++i) {
2295 boost::shared_ptr<Region> region = (*i)->region ();
2297 Location *location = new Location (*_session, region->position(), region->last_frame(), region->name(), Location::IsRangeMarker);
2299 _session->locations()->add (location, true);
2304 begin_reversible_command (selection->regions.size () > 1 ? _("add markers") : _("add marker"));
2305 XMLNode &after = _session->locations()->get_state();
2306 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2307 commit_reversible_command ();
2311 /** Add a single range marker around all selected regions */
2313 Editor::add_location_from_region ()
2315 RegionSelection rs = get_regions_from_selection_and_entered ();
2321 XMLNode &before = _session->locations()->get_state();
2325 if (rs.size() > 1) {
2326 _session->locations()->next_available_name(markername, "regions");
2328 RegionView* rv = *(rs.begin());
2329 boost::shared_ptr<Region> region = rv->region();
2330 markername = region->name();
2333 if (!choose_new_marker_name(markername)) {
2337 // single range spanning all selected
2338 Location *location = new Location (*_session, selection->regions.start(), selection->regions.end_frame(), markername, Location::IsRangeMarker);
2339 _session->locations()->add (location, true);
2341 begin_reversible_command (_("add marker"));
2342 XMLNode &after = _session->locations()->get_state();
2343 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2344 commit_reversible_command ();
2350 Editor::jump_forward_to_mark ()
2356 framepos_t pos = _session->locations()->first_mark_after (playhead_cursor->current_frame());
2362 _session->request_locate (pos, _session->transport_rolling());
2366 Editor::jump_backward_to_mark ()
2372 framepos_t pos = _session->locations()->first_mark_before (playhead_cursor->current_frame());
2378 _session->request_locate (pos, _session->transport_rolling());
2384 framepos_t const pos = _session->audible_frame ();
2387 _session->locations()->next_available_name (markername, "mark");
2389 if (!choose_new_marker_name (markername)) {
2393 _session->locations()->add (new Location (*_session, pos, 0, markername, Location::IsMark), true);
2397 Editor::clear_markers ()
2400 begin_reversible_command (_("clear markers"));
2402 XMLNode &before = _session->locations()->get_state();
2403 _session->locations()->clear_markers ();
2404 XMLNode &after = _session->locations()->get_state();
2405 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2407 commit_reversible_command ();
2412 Editor::clear_ranges ()
2415 begin_reversible_command (_("clear ranges"));
2417 XMLNode &before = _session->locations()->get_state();
2419 _session->locations()->clear_ranges ();
2421 XMLNode &after = _session->locations()->get_state();
2422 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2424 commit_reversible_command ();
2429 Editor::clear_locations ()
2431 begin_reversible_command (_("clear locations"));
2433 XMLNode &before = _session->locations()->get_state();
2434 _session->locations()->clear ();
2435 XMLNode &after = _session->locations()->get_state();
2436 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2438 commit_reversible_command ();
2442 Editor::unhide_markers ()
2444 for (LocationMarkerMap::iterator i = location_markers.begin(); i != location_markers.end(); ++i) {
2445 Location *l = (*i).first;
2446 if (l->is_hidden() && l->is_mark()) {
2447 l->set_hidden(false, this);
2453 Editor::unhide_ranges ()
2455 for (LocationMarkerMap::iterator i = location_markers.begin(); i != location_markers.end(); ++i) {
2456 Location *l = (*i).first;
2457 if (l->is_hidden() && l->is_range_marker()) {
2458 l->set_hidden(false, this);
2463 /* INSERT/REPLACE */
2466 Editor::insert_region_list_selection (float times)
2468 RouteTimeAxisView *tv = 0;
2469 boost::shared_ptr<Playlist> playlist;
2471 if (clicked_routeview != 0) {
2472 tv = clicked_routeview;
2473 } else if (!selection->tracks.empty()) {
2474 if ((tv = dynamic_cast<RouteTimeAxisView*>(selection->tracks.front())) == 0) {
2477 } else if (entered_track != 0) {
2478 if ((tv = dynamic_cast<RouteTimeAxisView*>(entered_track)) == 0) {
2485 if ((playlist = tv->playlist()) == 0) {
2489 boost::shared_ptr<Region> region = _regions->get_single_selection ();
2494 begin_reversible_command (_("insert region"));
2495 playlist->clear_changes ();
2496 playlist->add_region ((RegionFactory::create (region, true)), get_preferred_edit_position(), times);
2497 if (Config->get_edit_mode() == Ripple)
2498 playlist->ripple (get_preferred_edit_position(), region->length() * times, boost::shared_ptr<Region>());
2500 _session->add_command(new StatefulDiffCommand (playlist));
2501 commit_reversible_command ();
2504 /* BUILT-IN EFFECTS */
2507 Editor::reverse_selection ()
2512 /* GAIN ENVELOPE EDITING */
2515 Editor::edit_envelope ()
2522 Editor::transition_to_rolling (bool fwd)
2528 if (_session->config.get_external_sync()) {
2529 switch (Config->get_sync_source()) {
2533 /* transport controlled by the master */
2538 if (_session->is_auditioning()) {
2539 _session->cancel_audition ();
2543 _session->request_transport_speed (fwd ? 1.0f : -1.0f);
2547 Editor::play_from_start ()
2549 _session->request_locate (_session->current_start_frame(), true);
2553 Editor::play_from_edit_point ()
2555 _session->request_locate (get_preferred_edit_position(), true);
2559 Editor::play_from_edit_point_and_return ()
2561 framepos_t start_frame;
2562 framepos_t return_frame;
2564 start_frame = get_preferred_edit_position ( EDIT_IGNORE_PHEAD );
2566 if (_session->transport_rolling()) {
2567 _session->request_locate (start_frame, false);
2571 /* don't reset the return frame if its already set */
2573 if ((return_frame = _session->requested_return_frame()) < 0) {
2574 return_frame = _session->audible_frame();
2577 if (start_frame >= 0) {
2578 _session->request_roll_at_and_return (start_frame, return_frame);
2583 Editor::play_selection ()
2585 framepos_t start, end;
2586 if (!get_selection_extents ( start, end))
2589 AudioRange ar (start, end, 0);
2590 list<AudioRange> lar;
2593 _session->request_play_range (&lar, true);
2597 Editor::get_preroll ()
2599 return Config->get_preroll_seconds() * _session->frame_rate();
2604 Editor::maybe_locate_with_edit_preroll ( framepos_t location )
2606 if ( _session->transport_rolling() || !UIConfiguration::instance().get_follow_edits() || _ignore_follow_edits || _session->config.get_external_sync() )
2609 location -= get_preroll();
2611 //don't try to locate before the beginning of time
2615 //if follow_playhead is on, keep the playhead on the screen
2616 if ( _follow_playhead )
2617 if ( location < leftmost_frame )
2618 location = leftmost_frame;
2620 _session->request_locate( location );
2624 Editor::play_with_preroll ()
2627 framepos_t preroll = get_preroll();
2629 framepos_t start, end;
2630 if (!get_selection_extents ( start, end))
2633 if (start > preroll)
2634 start = start - preroll;
2636 end = end + preroll; //"post-roll"
2638 AudioRange ar (start, end, 0);
2639 list<AudioRange> lar;
2642 _session->request_play_range (&lar, true);
2647 Editor::play_location (Location& location)
2649 if (location.start() <= location.end()) {
2653 _session->request_bounded_roll (location.start(), location.end());
2657 Editor::loop_location (Location& location)
2659 if (location.start() <= location.end()) {
2665 if ((tll = transport_loop_location()) != 0) {
2666 tll->set (location.start(), location.end());
2668 // enable looping, reposition and start rolling
2669 _session->request_locate (tll->start(), true);
2670 _session->request_play_loop (true);
2675 Editor::do_layer_operation (LayerOperation op)
2677 if (selection->regions.empty ()) {
2681 bool const multiple = selection->regions.size() > 1;
2685 begin_reversible_command (_("raise regions"));
2687 begin_reversible_command (_("raise region"));
2693 begin_reversible_command (_("raise regions to top"));
2695 begin_reversible_command (_("raise region to top"));
2701 begin_reversible_command (_("lower regions"));
2703 begin_reversible_command (_("lower region"));
2709 begin_reversible_command (_("lower regions to bottom"));
2711 begin_reversible_command (_("lower region"));
2716 set<boost::shared_ptr<Playlist> > playlists = selection->regions.playlists ();
2717 for (set<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
2718 (*i)->clear_owned_changes ();
2721 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
2722 boost::shared_ptr<Region> r = (*i)->region ();
2734 r->lower_to_bottom ();
2738 for (set<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
2739 vector<Command*> cmds;
2741 _session->add_commands (cmds);
2744 commit_reversible_command ();
2748 Editor::raise_region ()
2750 do_layer_operation (Raise);
2754 Editor::raise_region_to_top ()
2756 do_layer_operation (RaiseToTop);
2760 Editor::lower_region ()
2762 do_layer_operation (Lower);
2766 Editor::lower_region_to_bottom ()
2768 do_layer_operation (LowerToBottom);
2771 /** Show the region editor for the selected regions */
2773 Editor::show_region_properties ()
2775 selection->foreach_regionview (&RegionView::show_region_editor);
2778 /** Show the midi list editor for the selected MIDI regions */
2780 Editor::show_midi_list_editor ()
2782 selection->foreach_midi_regionview (&MidiRegionView::show_list_editor);
2786 Editor::rename_region ()
2788 RegionSelection rs = get_regions_from_selection_and_entered ();
2794 ArdourDialog d (_("Rename Region"), true, false);
2796 Label label (_("New name:"));
2799 hbox.set_spacing (6);
2800 hbox.pack_start (label, false, false);
2801 hbox.pack_start (entry, true, true);
2803 d.get_vbox()->set_border_width (12);
2804 d.get_vbox()->pack_start (hbox, false, false);
2806 d.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
2807 d.add_button(Gtk::Stock::OK, Gtk::RESPONSE_OK);
2809 d.set_size_request (300, -1);
2811 entry.set_text (rs.front()->region()->name());
2812 entry.select_region (0, -1);
2814 entry.signal_activate().connect (sigc::bind (sigc::mem_fun (d, &Dialog::response), RESPONSE_OK));
2820 int const ret = d.run();
2824 if (ret != RESPONSE_OK) {
2828 std::string str = entry.get_text();
2829 strip_whitespace_edges (str);
2831 rs.front()->region()->set_name (str);
2832 _regions->redisplay ();
2836 /** Start an audition of the first selected region */
2838 Editor::play_edit_range ()
2840 framepos_t start, end;
2842 if (get_edit_op_range (start, end)) {
2843 _session->request_bounded_roll (start, end);
2848 Editor::play_selected_region ()
2850 framepos_t start = max_framepos;
2853 RegionSelection rs = get_regions_from_selection_and_entered ();
2859 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
2860 if ((*i)->region()->position() < start) {
2861 start = (*i)->region()->position();
2863 if ((*i)->region()->last_frame() + 1 > end) {
2864 end = (*i)->region()->last_frame() + 1;
2868 _session->request_bounded_roll (start, end);
2872 Editor::audition_playlist_region_standalone (boost::shared_ptr<Region> region)
2874 _session->audition_region (region);
2878 Editor::region_from_selection ()
2880 if (clicked_axisview == 0) {
2884 if (selection->time.empty()) {
2888 framepos_t start = selection->time[clicked_selection].start;
2889 framepos_t end = selection->time[clicked_selection].end;
2891 TrackViewList tracks = get_tracks_for_range_action ();
2893 framepos_t selection_cnt = end - start + 1;
2895 for (TrackSelection::iterator i = tracks.begin(); i != tracks.end(); ++i) {
2896 boost::shared_ptr<Region> current;
2897 boost::shared_ptr<Playlist> pl;
2898 framepos_t internal_start;
2901 if ((pl = (*i)->playlist()) == 0) {
2905 if ((current = pl->top_region_at (start)) == 0) {
2909 internal_start = start - current->position();
2910 RegionFactory::region_name (new_name, current->name(), true);
2914 plist.add (ARDOUR::Properties::start, current->start() + internal_start);
2915 plist.add (ARDOUR::Properties::length, selection_cnt);
2916 plist.add (ARDOUR::Properties::name, new_name);
2917 plist.add (ARDOUR::Properties::layer, 0);
2919 boost::shared_ptr<Region> region (RegionFactory::create (current, plist));
2924 Editor::create_region_from_selection (vector<boost::shared_ptr<Region> >& new_regions)
2926 if (selection->time.empty() || selection->tracks.empty()) {
2930 framepos_t start, end;
2931 if (clicked_selection) {
2932 start = selection->time[clicked_selection].start;
2933 end = selection->time[clicked_selection].end;
2935 start = selection->time.start();
2936 end = selection->time.end_frame();
2939 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
2940 sort_track_selection (ts);
2942 for (TrackSelection::iterator i = ts.begin(); i != ts.end(); ++i) {
2943 boost::shared_ptr<Region> current;
2944 boost::shared_ptr<Playlist> playlist;
2945 framepos_t internal_start;
2948 if ((playlist = (*i)->playlist()) == 0) {
2952 if ((current = playlist->top_region_at(start)) == 0) {
2956 internal_start = start - current->position();
2957 RegionFactory::region_name (new_name, current->name(), true);
2961 plist.add (ARDOUR::Properties::start, current->start() + internal_start);
2962 plist.add (ARDOUR::Properties::length, end - start + 1);
2963 plist.add (ARDOUR::Properties::name, new_name);
2965 new_regions.push_back (RegionFactory::create (current, plist));
2970 Editor::split_multichannel_region ()
2972 RegionSelection rs = get_regions_from_selection_and_entered ();
2978 vector< boost::shared_ptr<Region> > v;
2980 for (list<RegionView*>::iterator x = rs.begin(); x != rs.end(); ++x) {
2981 (*x)->region()->separate_by_channel (*_session, v);
2986 Editor::new_region_from_selection ()
2988 region_from_selection ();
2989 cancel_selection ();
2993 add_if_covered (RegionView* rv, const AudioRange* ar, RegionSelection* rs)
2995 switch (rv->region()->coverage (ar->start, ar->end - 1)) {
2996 // n.b. -1 because AudioRange::end is one past the end, but coverage expects inclusive ranges
2997 case Evoral::OverlapNone:
3005 * - selected tracks, or if there are none...
3006 * - tracks containing selected regions, or if there are none...
3011 Editor::get_tracks_for_range_action () const
3015 if (selection->tracks.empty()) {
3017 /* use tracks with selected regions */
3019 RegionSelection rs = selection->regions;
3021 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3022 TimeAxisView* tv = &(*i)->get_time_axis_view();
3024 if (!t.contains (tv)) {
3030 /* no regions and no tracks: use all tracks */
3036 t = selection->tracks;
3039 return t.filter_to_unique_playlists();
3043 Editor::separate_regions_between (const TimeSelection& ts)
3045 bool in_command = false;
3046 boost::shared_ptr<Playlist> playlist;
3047 RegionSelection new_selection;
3049 TrackViewList tmptracks = get_tracks_for_range_action ();
3050 sort_track_selection (tmptracks);
3052 for (TrackSelection::iterator i = tmptracks.begin(); i != tmptracks.end(); ++i) {
3054 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> ((*i));
3060 if (!rtv->is_track()) {
3064 /* no edits to destructive tracks */
3066 if (rtv->track()->destructive()) {
3070 if ((playlist = rtv->playlist()) != 0) {
3072 playlist->clear_changes ();
3074 /* XXX need to consider musical time selections here at some point */
3076 double speed = rtv->track()->speed();
3078 for (list<AudioRange>::const_iterator t = ts.begin(); t != ts.end(); ++t) {
3080 sigc::connection c = rtv->view()->RegionViewAdded.connect (
3081 sigc::mem_fun(*this, &Editor::collect_new_region_view));
3083 latest_regionviews.clear ();
3085 playlist->partition ((framepos_t)((*t).start * speed),
3086 (framepos_t)((*t).end * speed), false);
3090 if (!latest_regionviews.empty()) {
3092 rtv->view()->foreach_regionview (sigc::bind (
3093 sigc::ptr_fun (add_if_covered),
3094 &(*t), &new_selection));
3097 begin_reversible_command (_("separate"));
3101 /* pick up changes to existing regions */
3103 vector<Command*> cmds;
3104 playlist->rdiff (cmds);
3105 _session->add_commands (cmds);
3107 /* pick up changes to the playlist itself (adds/removes)
3110 _session->add_command(new StatefulDiffCommand (playlist));
3117 // selection->set (new_selection);
3119 commit_reversible_command ();
3123 struct PlaylistState {
3124 boost::shared_ptr<Playlist> playlist;
3128 /** Take tracks from get_tracks_for_range_action and cut any regions
3129 * on those tracks so that the tracks are empty over the time
3133 Editor::separate_region_from_selection ()
3135 /* preferentially use *all* ranges in the time selection if we're in range mode
3136 to allow discontiguous operation, since get_edit_op_range() currently
3137 returns a single range.
3140 if (!selection->time.empty()) {
3142 separate_regions_between (selection->time);
3149 if (get_edit_op_range (start, end)) {
3151 AudioRange ar (start, end, 1);
3155 separate_regions_between (ts);
3161 Editor::separate_region_from_punch ()
3163 Location* loc = _session->locations()->auto_punch_location();
3165 separate_regions_using_location (*loc);
3170 Editor::separate_region_from_loop ()
3172 Location* loc = _session->locations()->auto_loop_location();
3174 separate_regions_using_location (*loc);
3179 Editor::separate_regions_using_location (Location& loc)
3181 if (loc.is_mark()) {
3185 AudioRange ar (loc.start(), loc.end(), 1);
3190 separate_regions_between (ts);
3193 /** Separate regions under the selected region */
3195 Editor::separate_under_selected_regions ()
3197 vector<PlaylistState> playlists;
3201 rs = get_regions_from_selection_and_entered();
3203 if (!_session || rs.empty()) {
3207 begin_reversible_command (_("separate region under"));
3209 list<boost::shared_ptr<Region> > regions_to_remove;
3211 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3212 // we can't just remove the region(s) in this loop because
3213 // this removes them from the RegionSelection, and they thus
3214 // disappear from underneath the iterator, and the ++i above
3215 // SEGVs in a puzzling fashion.
3217 // so, first iterate over the regions to be removed from rs and
3218 // add them to the regions_to_remove list, and then
3219 // iterate over the list to actually remove them.
3221 regions_to_remove.push_back ((*i)->region());
3224 for (list<boost::shared_ptr<Region> >::iterator rl = regions_to_remove.begin(); rl != regions_to_remove.end(); ++rl) {
3226 boost::shared_ptr<Playlist> playlist = (*rl)->playlist();
3229 // is this check necessary?
3233 vector<PlaylistState>::iterator i;
3235 //only take state if this is a new playlist.
3236 for (i = playlists.begin(); i != playlists.end(); ++i) {
3237 if ((*i).playlist == playlist) {
3242 if (i == playlists.end()) {
3244 PlaylistState before;
3245 before.playlist = playlist;
3246 before.before = &playlist->get_state();
3248 playlist->freeze ();
3249 playlists.push_back(before);
3252 //Partition on the region bounds
3253 playlist->partition ((*rl)->first_frame() - 1, (*rl)->last_frame() + 1, true);
3255 //Re-add region that was just removed due to the partition operation
3256 playlist->add_region( (*rl), (*rl)->first_frame() );
3259 vector<PlaylistState>::iterator pl;
3261 for (pl = playlists.begin(); pl != playlists.end(); ++pl) {
3262 (*pl).playlist->thaw ();
3263 _session->add_command(new MementoCommand<Playlist>(*(*pl).playlist, (*pl).before, &(*pl).playlist->get_state()));
3266 commit_reversible_command ();
3270 Editor::crop_region_to_selection ()
3272 if (!selection->time.empty()) {
3274 crop_region_to (selection->time.start(), selection->time.end_frame());
3281 if (get_edit_op_range (start, end)) {
3282 crop_region_to (start, end);
3289 Editor::crop_region_to (framepos_t start, framepos_t end)
3291 vector<boost::shared_ptr<Playlist> > playlists;
3292 boost::shared_ptr<Playlist> playlist;
3295 if (selection->tracks.empty()) {
3296 ts = track_views.filter_to_unique_playlists();
3298 ts = selection->tracks.filter_to_unique_playlists ();
3301 sort_track_selection (ts);
3303 for (TrackSelection::iterator i = ts.begin(); i != ts.end(); ++i) {
3305 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> ((*i));
3311 boost::shared_ptr<Track> t = rtv->track();
3313 if (t != 0 && ! t->destructive()) {
3315 if ((playlist = rtv->playlist()) != 0) {
3316 playlists.push_back (playlist);
3321 if (playlists.empty()) {
3326 framepos_t new_start;
3328 framecnt_t new_length;
3329 bool in_command = false;
3331 for (vector<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
3333 /* Only the top regions at start and end have to be cropped */
3334 boost::shared_ptr<Region> region_at_start = (*i)->top_region_at(start);
3335 boost::shared_ptr<Region> region_at_end = (*i)->top_region_at(end);
3337 vector<boost::shared_ptr<Region> > regions;
3339 if (region_at_start != 0) {
3340 regions.push_back (region_at_start);
3342 if (region_at_end != 0) {
3343 regions.push_back (region_at_end);
3346 /* now adjust lengths */
3347 for (vector<boost::shared_ptr<Region> >::iterator i = regions.begin(); i != regions.end(); ++i) {
3349 pos = (*i)->position();
3350 new_start = max (start, pos);
3351 if (max_framepos - pos > (*i)->length()) {
3352 new_end = pos + (*i)->length() - 1;
3354 new_end = max_framepos;
3356 new_end = min (end, new_end);
3357 new_length = new_end - new_start + 1;
3360 begin_reversible_command (_("trim to selection"));
3363 (*i)->clear_changes ();
3364 (*i)->trim_to (new_start, new_length);
3365 _session->add_command (new StatefulDiffCommand (*i));
3370 commit_reversible_command ();
3375 Editor::region_fill_track ()
3377 boost::shared_ptr<Playlist> playlist;
3378 RegionSelection regions = get_regions_from_selection_and_entered ();
3379 RegionSelection foo;
3381 framepos_t const end = _session->current_end_frame ();
3383 if (regions.empty () || regions.end_frame () + 1 >= end) {
3387 framepos_t const start_frame = regions.start ();
3388 framepos_t const end_frame = regions.end_frame ();
3389 framecnt_t const gap = end_frame - start_frame + 1;
3391 begin_reversible_command (Operations::region_fill);
3393 selection->clear_regions ();
3395 for (RegionSelection::iterator i = regions.begin(); i != regions.end(); ++i) {
3397 boost::shared_ptr<Region> r ((*i)->region());
3399 TimeAxisView& tv = (*i)->get_time_axis_view();
3400 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (&tv);
3401 latest_regionviews.clear ();
3402 sigc::connection c = rtv->view()->RegionViewAdded.connect (sigc::mem_fun(*this, &Editor::collect_new_region_view));
3404 framepos_t const position = end_frame + (r->first_frame() - start_frame + 1);
3405 playlist = (*i)->region()->playlist();
3406 playlist->clear_changes ();
3407 playlist->duplicate_until (r, position, gap, end);
3408 _session->add_command(new StatefulDiffCommand (playlist));
3412 foo.insert (foo.end(), latest_regionviews.begin(), latest_regionviews.end());
3416 selection->set (foo);
3419 commit_reversible_command ();
3423 Editor::set_region_sync_position ()
3425 set_sync_point (get_preferred_edit_position (), get_regions_from_selection_and_edit_point ());
3429 Editor::set_sync_point (framepos_t where, const RegionSelection& rs)
3431 bool in_command = false;
3433 for (RegionSelection::const_iterator r = rs.begin(); r != rs.end(); ++r) {
3435 if (!(*r)->region()->covers (where)) {
3439 boost::shared_ptr<Region> region ((*r)->region());
3442 begin_reversible_command (_("set sync point"));
3446 region->clear_changes ();
3447 region->set_sync_position (where);
3448 _session->add_command(new StatefulDiffCommand (region));
3452 commit_reversible_command ();
3456 /** Remove the sync positions of the selection */
3458 Editor::remove_region_sync ()
3460 RegionSelection rs = get_regions_from_selection_and_entered ();
3466 begin_reversible_command (_("remove region sync"));
3468 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3470 (*i)->region()->clear_changes ();
3471 (*i)->region()->clear_sync_position ();
3472 _session->add_command(new StatefulDiffCommand ((*i)->region()));
3475 commit_reversible_command ();
3479 Editor::naturalize_region ()
3481 RegionSelection rs = get_regions_from_selection_and_entered ();
3487 if (rs.size() > 1) {
3488 begin_reversible_command (_("move regions to original position"));
3490 begin_reversible_command (_("move region to original position"));
3493 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3494 (*i)->region()->clear_changes ();
3495 (*i)->region()->move_to_natural_position ();
3496 _session->add_command (new StatefulDiffCommand ((*i)->region()));
3499 commit_reversible_command ();
3503 Editor::align_regions (RegionPoint what)
3505 RegionSelection const rs = get_regions_from_selection_and_edit_point ();
3511 begin_reversible_command (_("align selection"));
3513 framepos_t const position = get_preferred_edit_position ();
3515 for (RegionSelection::const_iterator i = rs.begin(); i != rs.end(); ++i) {
3516 align_region_internal ((*i)->region(), what, position);
3519 commit_reversible_command ();
3522 struct RegionSortByTime {
3523 bool operator() (const RegionView* a, const RegionView* b) {
3524 return a->region()->position() < b->region()->position();
3529 Editor::align_regions_relative (RegionPoint point)
3531 RegionSelection const rs = get_regions_from_selection_and_edit_point ();
3537 framepos_t const position = get_preferred_edit_position ();
3539 framepos_t distance = 0;
3543 list<RegionView*> sorted;
3544 rs.by_position (sorted);
3546 boost::shared_ptr<Region> r ((*sorted.begin())->region());
3551 if (position > r->position()) {
3552 distance = position - r->position();
3554 distance = r->position() - position;
3560 if (position > r->last_frame()) {
3561 distance = position - r->last_frame();
3562 pos = r->position() + distance;
3564 distance = r->last_frame() - position;
3565 pos = r->position() - distance;
3571 pos = r->adjust_to_sync (position);
3572 if (pos > r->position()) {
3573 distance = pos - r->position();
3575 distance = r->position() - pos;
3581 if (pos == r->position()) {
3585 begin_reversible_command (_("align selection (relative)"));
3587 /* move first one specially */
3589 r->clear_changes ();
3590 r->set_position (pos);
3591 _session->add_command(new StatefulDiffCommand (r));
3593 /* move rest by the same amount */
3597 for (list<RegionView*>::iterator i = sorted.begin(); i != sorted.end(); ++i) {
3599 boost::shared_ptr<Region> region ((*i)->region());
3601 region->clear_changes ();
3604 region->set_position (region->position() + distance);
3606 region->set_position (region->position() - distance);
3609 _session->add_command(new StatefulDiffCommand (region));
3613 commit_reversible_command ();
3617 Editor::align_region (boost::shared_ptr<Region> region, RegionPoint point, framepos_t position)
3619 begin_reversible_command (_("align region"));
3620 align_region_internal (region, point, position);
3621 commit_reversible_command ();
3625 Editor::align_region_internal (boost::shared_ptr<Region> region, RegionPoint point, framepos_t position)
3627 region->clear_changes ();
3631 region->set_position (region->adjust_to_sync (position));
3635 if (position > region->length()) {
3636 region->set_position (position - region->length());
3641 region->set_position (position);
3645 _session->add_command(new StatefulDiffCommand (region));
3649 Editor::trim_region_front ()
3655 Editor::trim_region_back ()
3657 trim_region (false);
3661 Editor::trim_region (bool front)
3663 framepos_t where = get_preferred_edit_position();
3664 RegionSelection rs = get_regions_from_selection_and_edit_point ();
3670 begin_reversible_command (front ? _("trim front") : _("trim back"));
3672 for (list<RegionView*>::const_iterator i = rs.by_layer().begin(); i != rs.by_layer().end(); ++i) {
3673 if (!(*i)->region()->locked()) {
3675 (*i)->region()->clear_changes ();
3678 (*i)->region()->trim_front (where);
3679 maybe_locate_with_edit_preroll ( where );
3681 (*i)->region()->trim_end (where);
3682 maybe_locate_with_edit_preroll ( where );
3685 _session->add_command (new StatefulDiffCommand ((*i)->region()));
3689 commit_reversible_command ();
3692 /** Trim the end of the selected regions to the position of the edit cursor */
3694 Editor::trim_region_to_loop ()
3696 Location* loc = _session->locations()->auto_loop_location();
3700 trim_region_to_location (*loc, _("trim to loop"));
3704 Editor::trim_region_to_punch ()
3706 Location* loc = _session->locations()->auto_punch_location();
3710 trim_region_to_location (*loc, _("trim to punch"));
3714 Editor::trim_region_to_location (const Location& loc, const char* str)
3716 RegionSelection rs = get_regions_from_selection_and_entered ();
3717 bool in_command = false;
3719 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
3720 RegionView* rv = (*x);
3722 /* require region to span proposed trim */
3723 switch (rv->region()->coverage (loc.start(), loc.end())) {
3724 case Evoral::OverlapInternal:
3730 RouteTimeAxisView* tav = dynamic_cast<RouteTimeAxisView*> (&rv->get_time_axis_view());
3739 if (tav->track() != 0) {
3740 speed = tav->track()->speed();
3743 start = session_frame_to_track_frame (loc.start(), speed);
3744 end = session_frame_to_track_frame (loc.end(), speed);
3746 rv->region()->clear_changes ();
3747 rv->region()->trim_to (start, (end - start));
3750 begin_reversible_command (str);
3753 _session->add_command(new StatefulDiffCommand (rv->region()));
3757 commit_reversible_command ();
3762 Editor::trim_region_to_previous_region_end ()
3764 return trim_to_region(false);
3768 Editor::trim_region_to_next_region_start ()
3770 return trim_to_region(true);
3774 Editor::trim_to_region(bool forward)
3776 RegionSelection rs = get_regions_from_selection_and_entered ();
3777 bool in_command = false;
3779 boost::shared_ptr<Region> next_region;
3781 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
3783 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*x);
3789 AudioTimeAxisView* atav = dynamic_cast<AudioTimeAxisView*> (&arv->get_time_axis_view());
3797 if (atav->track() != 0) {
3798 speed = atav->track()->speed();
3802 boost::shared_ptr<Region> region = arv->region();
3803 boost::shared_ptr<Playlist> playlist (region->playlist());
3805 region->clear_changes ();
3809 next_region = playlist->find_next_region (region->first_frame(), Start, 1);
3815 region->trim_end((framepos_t) ( (next_region->first_frame() - 1) * speed));
3816 arv->region_changed (PropertyChange (ARDOUR::Properties::length));
3820 next_region = playlist->find_next_region (region->first_frame(), Start, 0);
3826 region->trim_front((framepos_t) ((next_region->last_frame() + 1) * speed));
3828 arv->region_changed (ARDOUR::bounds_change);
3832 begin_reversible_command (_("trim to region"));
3835 _session->add_command(new StatefulDiffCommand (region));
3839 commit_reversible_command ();
3844 Editor::unfreeze_route ()
3846 if (clicked_routeview == 0 || !clicked_routeview->is_track()) {
3850 clicked_routeview->track()->unfreeze ();
3854 Editor::_freeze_thread (void* arg)
3856 return static_cast<Editor*>(arg)->freeze_thread ();
3860 Editor::freeze_thread ()
3862 /* create event pool because we may need to talk to the session */
3863 SessionEvent::create_per_thread_pool ("freeze events", 64);
3864 /* create per-thread buffers for process() tree to use */
3865 clicked_routeview->audio_track()->freeze_me (*current_interthread_info);
3866 current_interthread_info->done = true;
3871 Editor::freeze_route ()
3877 /* stop transport before we start. this is important */
3879 _session->request_transport_speed (0.0);
3881 /* wait for just a little while, because the above call is asynchronous */
3883 Glib::usleep (250000);
3885 if (clicked_routeview == 0 || !clicked_routeview->is_audio_track()) {
3889 if (!clicked_routeview->track()->bounceable (clicked_routeview->track()->main_outs(), true)) {
3891 _("This track/bus cannot be frozen because the signal adds or loses channels before reaching the outputs.\n"
3892 "This is typically caused by plugins that generate stereo output from mono input or vice versa.")
3894 d.set_title (_("Cannot freeze"));
3899 if (clicked_routeview->track()->has_external_redirects()) {
3900 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"
3901 "Freezing will only process the signal as far as the first send/insert/return."),
3902 clicked_routeview->track()->name()), true, MESSAGE_INFO, BUTTONS_NONE, true);
3904 d.add_button (_("Freeze anyway"), Gtk::RESPONSE_OK);
3905 d.add_button (_("Don't freeze"), Gtk::RESPONSE_CANCEL);
3906 d.set_title (_("Freeze Limits"));
3908 int response = d.run ();
3911 case Gtk::RESPONSE_CANCEL:
3918 InterThreadInfo itt;
3919 current_interthread_info = &itt;
3921 InterthreadProgressWindow ipw (current_interthread_info, _("Freeze"), _("Cancel Freeze"));
3923 pthread_create_and_store (X_("freezer"), &itt.thread, _freeze_thread, this);
3925 CursorContext::Handle cursor_ctx = CursorContext::create(*this, _cursors->wait);
3927 while (!itt.done && !itt.cancel) {
3928 gtk_main_iteration ();
3931 pthread_join (itt.thread, 0);
3932 current_interthread_info = 0;
3936 Editor::bounce_range_selection (bool replace, bool enable_processing)
3938 if (selection->time.empty()) {
3942 TrackSelection views = selection->tracks;
3944 for (TrackViewList::iterator i = views.begin(); i != views.end(); ++i) {
3946 if (enable_processing) {
3948 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*i);
3950 if (rtv && rtv->track() && replace && enable_processing && !rtv->track()->bounceable (rtv->track()->main_outs(), false)) {
3952 _("You can't perform this operation because the processing of the signal "
3953 "will cause one or more of the tracks to end up with a region with more channels than this track has inputs.\n\n"
3954 "You can do this without processing, which is a different operation.")
3956 d.set_title (_("Cannot bounce"));
3963 framepos_t start = selection->time[clicked_selection].start;
3964 framepos_t end = selection->time[clicked_selection].end;
3965 framepos_t cnt = end - start + 1;
3966 bool in_command = false;
3968 for (TrackViewList::iterator i = views.begin(); i != views.end(); ++i) {
3970 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*i);
3976 boost::shared_ptr<Playlist> playlist;
3978 if ((playlist = rtv->playlist()) == 0) {
3982 InterThreadInfo itt;
3984 playlist->clear_changes ();
3985 playlist->clear_owned_changes ();
3987 boost::shared_ptr<Region> r;
3989 if (enable_processing) {
3990 r = rtv->track()->bounce_range (start, start+cnt, itt, rtv->track()->main_outs(), false);
3992 r = rtv->track()->bounce_range (start, start+cnt, itt, boost::shared_ptr<Processor>(), false);
4000 list<AudioRange> ranges;
4001 ranges.push_back (AudioRange (start, start+cnt, 0));
4002 playlist->cut (ranges); // discard result
4003 playlist->add_region (r, start);
4007 begin_reversible_command (_("bounce range"));
4010 vector<Command*> cmds;
4011 playlist->rdiff (cmds);
4012 _session->add_commands (cmds);
4014 _session->add_command (new StatefulDiffCommand (playlist));
4018 commit_reversible_command ();
4022 /** Delete selected regions, automation points or a time range */
4026 //special case: if the user is pointing in the editor/mixer strip, they may be trying to delete a plugin.
4027 //we need this because the editor-mixer strip is in the editor window, so it doesn't get the bindings from the mix window
4028 bool deleted = false;
4029 if ( current_mixer_strip && current_mixer_strip == MixerStrip::entered_mixer_strip() )
4030 deleted = current_mixer_strip->delete_processors ();
4036 /** Cut selected regions, automation points or a time range */
4043 /** Copy selected regions, automation points or a time range */
4051 /** @return true if a Cut, Copy or Clear is possible */
4053 Editor::can_cut_copy () const
4055 if (!selection->time.empty() || !selection->regions.empty() || !selection->points.empty())
4062 /** Cut, copy or clear selected regions, automation points or a time range.
4063 * @param op Operation (Delete, Cut, Copy or Clear)
4066 Editor::cut_copy (CutCopyOp op)
4068 /* only cancel selection if cut/copy is successful.*/
4074 opname = _("delete");
4083 opname = _("clear");
4087 /* if we're deleting something, and the mouse is still pressed,
4088 the thing we started a drag for will be gone when we release
4089 the mouse button(s). avoid this. see part 2 at the end of
4093 if (op == Delete || op == Cut || op == Clear) {
4094 if (_drags->active ()) {
4099 if ( op != Delete ) //"Delete" doesn't change copy/paste buf
4100 cut_buffer->clear ();
4102 if (entered_marker) {
4104 /* cut/delete op while pointing at a marker */
4107 Location* loc = find_location_from_marker (entered_marker, ignored);
4109 if (_session && loc) {
4110 entered_marker = NULL;
4111 Glib::signal_idle().connect (sigc::bind (sigc::mem_fun(*this, &Editor::really_remove_marker), loc));
4118 switch (mouse_mode) {
4121 begin_reversible_command (opname + ' ' + X_("MIDI"));
4123 commit_reversible_command ();
4129 bool did_edit = false;
4131 if (!selection->regions.empty() || !selection->points.empty()) {
4132 begin_reversible_command (opname + ' ' + _("objects"));
4135 if (!selection->regions.empty()) {
4136 cut_copy_regions (op, selection->regions);
4138 if (op == Cut || op == Delete) {
4139 selection->clear_regions ();
4143 if (!selection->points.empty()) {
4144 cut_copy_points (op);
4146 if (op == Cut || op == Delete) {
4147 selection->clear_points ();
4150 } else if (selection->time.empty()) {
4151 framepos_t start, end;
4152 /* no time selection, see if we can get an edit range
4155 if (get_edit_op_range (start, end)) {
4156 selection->set (start, end);
4158 } else if (!selection->time.empty()) {
4159 begin_reversible_command (opname + ' ' + _("range"));
4162 cut_copy_ranges (op);
4164 if (op == Cut || op == Delete) {
4165 selection->clear_time ();
4170 /* reset repeated paste state */
4173 commit_reversible_command ();
4176 if (op == Delete || op == Cut || op == Clear) {
4182 struct AutomationRecord {
4183 AutomationRecord () : state (0) , line(NULL) {}
4184 AutomationRecord (XMLNode* s, const AutomationLine* l) : state (s) , line (l) {}
4186 XMLNode* state; ///< state before any operation
4187 const AutomationLine* line; ///< line this came from
4188 boost::shared_ptr<Evoral::ControlList> copy; ///< copied events for the cut buffer
4190 struct PointsSelectionPositionSorter {
4191 bool operator() (ControlPoint* a, ControlPoint* b) {
4192 return (*(a->model()))->when < (*(b->model()))->when;
4195 /** Cut, copy or clear selected automation points.
4196 * @param op Operation (Cut, Copy or Clear)
4199 Editor::cut_copy_points (Editing::CutCopyOp op, Evoral::Beats earliest, bool midi)
4201 if (selection->points.empty ()) {
4205 /* XXX: not ideal, as there may be more than one track involved in the point selection */
4206 _last_cut_copy_source_track = &selection->points.front()->line().trackview;
4208 /* Keep a record of the AutomationLists that we end up using in this operation */
4209 typedef std::map<boost::shared_ptr<AutomationList>, AutomationRecord> Lists;
4212 /* user could select points in any order */
4213 selection->points.sort(PointsSelectionPositionSorter ());
4215 /* Go through all selected points, making an AutomationRecord for each distinct AutomationList */
4216 for (PointSelection::iterator sel_point = selection->points.begin(); sel_point != selection->points.end(); ++sel_point) {
4217 const AutomationLine& line = (*sel_point)->line();
4218 const boost::shared_ptr<AutomationList> al = line.the_list();
4219 if (lists.find (al) == lists.end ()) {
4220 /* We haven't seen this list yet, so make a record for it. This includes
4221 taking a copy of its current state, in case this is needed for undo later.
4223 lists[al] = AutomationRecord (&al->get_state (), &line);
4227 if (op == Cut || op == Copy) {
4228 /* This operation will involve putting things in the cut buffer, so create an empty
4229 ControlList for each of our source lists to put the cut buffer data in.
4231 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
4232 i->second.copy = i->first->create (i->first->parameter (), i->first->descriptor());
4235 /* Add all selected points to the relevant copy ControlLists */
4236 framepos_t start = std::numeric_limits<framepos_t>::max();
4237 for (PointSelection::iterator sel_point = selection->points.begin(); sel_point != selection->points.end(); ++sel_point) {
4238 boost::shared_ptr<AutomationList> al = (*sel_point)->line().the_list();
4239 AutomationList::const_iterator ctrl_evt = (*sel_point)->model ();
4241 lists[al].copy->fast_simple_add ((*ctrl_evt)->when, (*ctrl_evt)->value);
4243 /* Update earliest MIDI start time in beats */
4244 earliest = std::min(earliest, Evoral::Beats((*ctrl_evt)->when));
4246 /* Update earliest session start time in frames */
4247 start = std::min(start, (*sel_point)->line().session_position(ctrl_evt));
4251 /* Snap start time backwards, so copy/paste is snap aligned. */
4253 if (earliest == Evoral::Beats::max()) {
4254 earliest = Evoral::Beats(); // Weird... don't offset
4256 earliest.round_down_to_beat();
4258 if (start == std::numeric_limits<double>::max()) {
4259 start = 0; // Weird... don't offset
4261 snap_to(start, RoundDownMaybe);
4264 const double line_offset = midi ? earliest.to_double() : start;
4265 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
4266 /* Correct this copy list so that it is relative to the earliest
4267 start time, so relative ordering between points is preserved
4268 when copying from several lists and the paste starts at the
4269 earliest copied piece of data. */
4270 boost::shared_ptr<Evoral::ControlList> &al_cpy = i->second.copy;
4271 for (AutomationList::iterator ctrl_evt = al_cpy->begin(); ctrl_evt != al_cpy->end(); ++ctrl_evt) {
4272 (*ctrl_evt)->when -= line_offset;
4275 /* And add it to the cut buffer */
4276 cut_buffer->add (al_cpy);
4280 if (op == Delete || op == Cut) {
4281 /* This operation needs to remove things from the main AutomationList, so do that now */
4283 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
4284 i->first->freeze ();
4287 /* Remove each selected point from its AutomationList */
4288 for (PointSelection::iterator sel_point = selection->points.begin(); sel_point != selection->points.end(); ++sel_point) {
4289 AutomationLine& line = (*sel_point)->line ();
4290 boost::shared_ptr<AutomationList> al = line.the_list();
4294 if (dynamic_cast<AudioRegionGainLine*> (&line)) {
4295 /* removing of first and last gain point in region gain lines is prohibited*/
4296 if (line.is_last_point (*(*sel_point)) || line.is_first_point (*(*sel_point))) {
4302 al->erase ((*sel_point)->model ());
4306 /* Thaw the lists and add undo records for them */
4307 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
4308 boost::shared_ptr<AutomationList> al = i->first;
4310 _session->add_command (new MementoCommand<AutomationList> (*al.get(), i->second.state, &(al->get_state ())));
4315 /** Cut, copy or clear selected automation points.
4316 * @param op Operation (Cut, Copy or Clear)
4319 Editor::cut_copy_midi (CutCopyOp op)
4321 Evoral::Beats earliest = Evoral::Beats::max();
4322 for (MidiRegionSelection::iterator i = selection->midi_regions.begin(); i != selection->midi_regions.end(); ++i) {
4323 MidiRegionView* mrv = dynamic_cast<MidiRegionView*>(*i);
4325 if (!mrv->selection().empty()) {
4326 earliest = std::min(earliest, (*mrv->selection().begin())->note()->time());
4328 mrv->cut_copy_clear (op);
4330 /* XXX: not ideal, as there may be more than one track involved in the selection */
4331 _last_cut_copy_source_track = &mrv->get_time_axis_view();
4335 if (!selection->points.empty()) {
4336 cut_copy_points (op, earliest, true);
4337 if (op == Cut || op == Delete) {
4338 selection->clear_points ();
4343 struct lt_playlist {
4344 bool operator () (const PlaylistState& a, const PlaylistState& b) {
4345 return a.playlist < b.playlist;
4349 struct PlaylistMapping {
4351 boost::shared_ptr<Playlist> pl;
4353 PlaylistMapping (TimeAxisView* tvp) : tv (tvp) {}
4356 /** Remove `clicked_regionview' */
4358 Editor::remove_clicked_region ()
4360 if (clicked_routeview == 0 || clicked_regionview == 0) {
4364 begin_reversible_command (_("remove region"));
4366 boost::shared_ptr<Playlist> playlist = clicked_routeview->playlist();
4368 playlist->clear_changes ();
4369 playlist->clear_owned_changes ();
4370 playlist->remove_region (clicked_regionview->region());
4371 if (Config->get_edit_mode() == Ripple)
4372 playlist->ripple (clicked_regionview->region()->position(), -clicked_regionview->region()->length(), boost::shared_ptr<Region>());
4374 /* We might have removed regions, which alters other regions' layering_index,
4375 so we need to do a recursive diff here.
4377 vector<Command*> cmds;
4378 playlist->rdiff (cmds);
4379 _session->add_commands (cmds);
4381 _session->add_command(new StatefulDiffCommand (playlist));
4382 commit_reversible_command ();
4386 /** Remove the selected regions */
4388 Editor::remove_selected_regions ()
4390 RegionSelection rs = get_regions_from_selection_and_entered ();
4392 if (!_session || rs.empty()) {
4396 list<boost::shared_ptr<Region> > regions_to_remove;
4398 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
4399 // we can't just remove the region(s) in this loop because
4400 // this removes them from the RegionSelection, and they thus
4401 // disappear from underneath the iterator, and the ++i above
4402 // SEGVs in a puzzling fashion.
4404 // so, first iterate over the regions to be removed from rs and
4405 // add them to the regions_to_remove list, and then
4406 // iterate over the list to actually remove them.
4408 regions_to_remove.push_back ((*i)->region());
4411 vector<boost::shared_ptr<Playlist> > playlists;
4413 for (list<boost::shared_ptr<Region> >::iterator rl = regions_to_remove.begin(); rl != regions_to_remove.end(); ++rl) {
4415 boost::shared_ptr<Playlist> playlist = (*rl)->playlist();
4418 // is this check necessary?
4422 /* get_regions_from_selection_and_entered() guarantees that
4423 the playlists involved are unique, so there is no need
4427 playlists.push_back (playlist);
4429 playlist->clear_changes ();
4430 playlist->clear_owned_changes ();
4431 playlist->freeze ();
4432 playlist->remove_region (*rl);
4433 if (Config->get_edit_mode() == Ripple)
4434 playlist->ripple ((*rl)->position(), -(*rl)->length(), boost::shared_ptr<Region>());
4438 vector<boost::shared_ptr<Playlist> >::iterator pl;
4439 bool in_command = false;
4441 for (pl = playlists.begin(); pl != playlists.end(); ++pl) {
4444 /* We might have removed regions, which alters other regions' layering_index,
4445 so we need to do a recursive diff here.
4449 begin_reversible_command (_("remove region"));
4452 vector<Command*> cmds;
4453 (*pl)->rdiff (cmds);
4454 _session->add_commands (cmds);
4456 _session->add_command(new StatefulDiffCommand (*pl));
4460 commit_reversible_command ();
4464 /** Cut, copy or clear selected regions.
4465 * @param op Operation (Cut, Copy or Clear)
4468 Editor::cut_copy_regions (CutCopyOp op, RegionSelection& rs)
4470 /* we can't use a std::map here because the ordering is important, and we can't trivially sort
4471 a map when we want ordered access to both elements. i think.
4474 vector<PlaylistMapping> pmap;
4476 framepos_t first_position = max_framepos;
4478 typedef set<boost::shared_ptr<Playlist> > FreezeList;
4479 FreezeList freezelist;
4481 /* get ordering correct before we cut/copy */
4483 rs.sort_by_position_and_track ();
4485 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
4487 first_position = min ((framepos_t) (*x)->region()->position(), first_position);
4489 if (op == Cut || op == Clear || op == Delete) {
4490 boost::shared_ptr<Playlist> pl = (*x)->region()->playlist();
4493 FreezeList::iterator fl;
4495 // only take state if this is a new playlist.
4496 for (fl = freezelist.begin(); fl != freezelist.end(); ++fl) {
4502 if (fl == freezelist.end()) {
4503 pl->clear_changes();
4504 pl->clear_owned_changes ();
4506 freezelist.insert (pl);
4511 TimeAxisView* tv = &(*x)->get_time_axis_view();
4512 vector<PlaylistMapping>::iterator z;
4514 for (z = pmap.begin(); z != pmap.end(); ++z) {
4515 if ((*z).tv == tv) {
4520 if (z == pmap.end()) {
4521 pmap.push_back (PlaylistMapping (tv));
4525 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ) {
4527 boost::shared_ptr<Playlist> pl = (*x)->region()->playlist();
4530 /* region not yet associated with a playlist (e.g. unfinished
4537 TimeAxisView& tv = (*x)->get_time_axis_view();
4538 boost::shared_ptr<Playlist> npl;
4539 RegionSelection::iterator tmp;
4546 vector<PlaylistMapping>::iterator z;
4548 for (z = pmap.begin(); z != pmap.end(); ++z) {
4549 if ((*z).tv == &tv) {
4554 assert (z != pmap.end());
4557 npl = PlaylistFactory::create (pl->data_type(), *_session, "cutlist", true);
4565 boost::shared_ptr<Region> r = (*x)->region();
4566 boost::shared_ptr<Region> _xx;
4572 pl->remove_region (r);
4573 if (Config->get_edit_mode() == Ripple)
4574 pl->ripple (r->position(), -r->length(), boost::shared_ptr<Region>());
4578 _xx = RegionFactory::create (r);
4579 npl->add_region (_xx, r->position() - first_position);
4580 pl->remove_region (r);
4581 if (Config->get_edit_mode() == Ripple)
4582 pl->ripple (r->position(), -r->length(), boost::shared_ptr<Region>());
4586 /* copy region before adding, so we're not putting same object into two different playlists */
4587 npl->add_region (RegionFactory::create (r), r->position() - first_position);
4591 pl->remove_region (r);
4592 if (Config->get_edit_mode() == Ripple)
4593 pl->ripple (r->position(), -r->length(), boost::shared_ptr<Region>());
4602 list<boost::shared_ptr<Playlist> > foo;
4604 /* the pmap is in the same order as the tracks in which selected regions occurred */
4606 for (vector<PlaylistMapping>::iterator i = pmap.begin(); i != pmap.end(); ++i) {
4609 foo.push_back ((*i).pl);
4614 cut_buffer->set (foo);
4618 _last_cut_copy_source_track = 0;
4620 _last_cut_copy_source_track = pmap.front().tv;
4624 for (FreezeList::iterator pl = freezelist.begin(); pl != freezelist.end(); ++pl) {
4627 /* We might have removed regions, which alters other regions' layering_index,
4628 so we need to do a recursive diff here.
4630 vector<Command*> cmds;
4631 (*pl)->rdiff (cmds);
4632 _session->add_commands (cmds);
4634 _session->add_command (new StatefulDiffCommand (*pl));
4639 Editor::cut_copy_ranges (CutCopyOp op)
4641 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4643 /* Sort the track selection now, so that it if is used, the playlists
4644 selected by the calls below to cut_copy_clear are in the order that
4645 their tracks appear in the editor. This makes things like paste
4646 of ranges work properly.
4649 sort_track_selection (ts);
4652 if (!entered_track) {
4655 ts.push_back (entered_track);
4658 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4659 (*i)->cut_copy_clear (*selection, op);
4664 Editor::paste (float times, bool from_context)
4666 DEBUG_TRACE (DEBUG::CutNPaste, "paste to preferred edit pos\n");
4668 paste_internal (get_preferred_edit_position (EDIT_IGNORE_NONE, from_context), times, get_grid_music_divisions (0));
4672 Editor::mouse_paste ()
4677 if (!mouse_frame (where, ignored)) {
4682 paste_internal (where, 1, get_grid_music_divisions (0));
4686 Editor::paste_internal (framepos_t position, float times, const int32_t sub_num)
4688 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("apparent paste position is %1\n", position));
4690 if (cut_buffer->empty(internal_editing())) {
4694 if (position == max_framepos) {
4695 position = get_preferred_edit_position();
4696 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("preferred edit position is %1\n", position));
4699 if (position == last_paste_pos) {
4700 /* repeated paste in the same position */
4703 /* paste in new location, reset repeated paste state */
4705 last_paste_pos = position;
4708 /* get everything in the correct order */
4711 if (!selection->tracks.empty()) {
4712 /* If there is a track selection, paste into exactly those tracks and
4713 only those tracks. This allows the user to be explicit and override
4714 the below "do the reasonable thing" logic. */
4715 ts = selection->tracks.filter_to_unique_playlists ();
4716 sort_track_selection (ts);
4718 /* Figure out which track to base the paste at. */
4719 TimeAxisView* base_track = NULL;
4720 if (_edit_point == Editing::EditAtMouse && entered_track) {
4721 /* With the mouse edit point, paste onto the track under the mouse. */
4722 base_track = entered_track;
4723 } else if (_edit_point == Editing::EditAtMouse && entered_regionview) {
4724 /* With the mouse edit point, paste onto the track of the region under the mouse. */
4725 base_track = &entered_regionview->get_time_axis_view();
4726 } else if (_last_cut_copy_source_track) {
4727 /* Paste to the track that the cut/copy came from (see mantis #333). */
4728 base_track = _last_cut_copy_source_track;
4730 /* This is "impossible" since we've copied... well, do nothing. */
4734 /* Walk up to parent if necessary, so base track is a route. */
4735 while (base_track->get_parent()) {
4736 base_track = base_track->get_parent();
4739 /* Add base track and all tracks below it. The paste logic will select
4740 the appropriate object types from the cut buffer in relative order. */
4741 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4742 if ((*i)->order() >= base_track->order()) {
4747 /* Sort tracks so the nth track of type T will pick the nth object of type T. */
4748 sort_track_selection (ts);
4750 /* Add automation children of each track in order, for pasting several lines. */
4751 for (TrackViewList::iterator i = ts.begin(); i != ts.end();) {
4752 /* Add any automation children for pasting several lines */
4753 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*i++);
4758 typedef RouteTimeAxisView::AutomationTracks ATracks;
4759 const ATracks& atracks = rtv->automation_tracks();
4760 for (ATracks::const_iterator a = atracks.begin(); a != atracks.end(); ++a) {
4761 i = ts.insert(i, a->second.get());
4766 /* We now have a list of trackviews starting at base_track, including
4767 automation children, in the order shown in the editor, e.g. R1,
4768 R1.A1, R1.A2, R2, R2.A1, ... */
4771 begin_reversible_command (Operations::paste);
4773 if (ts.size() == 1 && cut_buffer->lines.size() == 1 &&
4774 dynamic_cast<AutomationTimeAxisView*>(ts.front())) {
4775 /* Only one line copied, and one automation track selected. Do a
4776 "greedy" paste from one automation type to another. */
4778 PasteContext ctx(paste_count, times, ItemCounts(), true);
4779 ts.front()->paste (position, *cut_buffer, ctx, sub_num);
4783 /* Paste into tracks */
4785 PasteContext ctx(paste_count, times, ItemCounts(), false);
4786 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4787 (*i)->paste (position, *cut_buffer, ctx, sub_num);
4791 commit_reversible_command ();
4795 Editor::duplicate_some_regions (RegionSelection& regions, float times)
4797 if (regions.empty ()) {
4801 boost::shared_ptr<Playlist> playlist;
4802 RegionSelection sel = regions; // clear (below) may clear the argument list if its the current region selection
4803 RegionSelection foo;
4805 framepos_t const start_frame = regions.start ();
4806 framepos_t const end_frame = regions.end_frame ();
4807 framecnt_t const gap = end_frame - start_frame + 1;
4809 begin_reversible_command (Operations::duplicate_region);
4811 selection->clear_regions ();
4813 for (RegionSelection::iterator i = sel.begin(); i != sel.end(); ++i) {
4815 boost::shared_ptr<Region> r ((*i)->region());
4817 TimeAxisView& tv = (*i)->get_time_axis_view();
4818 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (&tv);
4819 latest_regionviews.clear ();
4820 sigc::connection c = rtv->view()->RegionViewAdded.connect (sigc::mem_fun(*this, &Editor::collect_new_region_view));
4822 framepos_t const position = end_frame + (r->first_frame() - start_frame + 1);
4823 playlist = (*i)->region()->playlist();
4824 playlist->clear_changes ();
4825 playlist->duplicate (r, position, gap, times);
4826 _session->add_command(new StatefulDiffCommand (playlist));
4830 foo.insert (foo.end(), latest_regionviews.begin(), latest_regionviews.end());
4834 selection->set (foo);
4837 commit_reversible_command ();
4841 Editor::duplicate_selection (float times)
4843 if (selection->time.empty() || selection->tracks.empty()) {
4847 boost::shared_ptr<Playlist> playlist;
4849 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4851 bool in_command = false;
4853 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4854 if ((playlist = (*i)->playlist()) == 0) {
4857 playlist->clear_changes ();
4859 if (clicked_selection) {
4860 playlist->duplicate_range (selection->time[clicked_selection], times);
4862 playlist->duplicate_ranges (selection->time, times);
4866 begin_reversible_command (_("duplicate range selection"));
4869 _session->add_command (new StatefulDiffCommand (playlist));
4874 // now "move" range selection to after the current range selection
4875 framecnt_t distance = 0;
4877 if (clicked_selection) {
4878 distance = selection->time[clicked_selection].end -
4879 selection->time[clicked_selection].start;
4881 distance = selection->time.end_frame() - selection->time.start();
4884 selection->move_time (distance);
4886 commit_reversible_command ();
4890 /** Reset all selected points to the relevant default value */
4892 Editor::reset_point_selection ()
4894 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
4895 ARDOUR::AutomationList::iterator j = (*i)->model ();
4896 (*j)->value = (*i)->line().the_list()->default_value ();
4901 Editor::center_playhead ()
4903 float const page = _visible_canvas_width * samples_per_pixel;
4904 center_screen_internal (playhead_cursor->current_frame (), page);
4908 Editor::center_edit_point ()
4910 float const page = _visible_canvas_width * samples_per_pixel;
4911 center_screen_internal (get_preferred_edit_position(), page);
4914 /** Caller must begin and commit a reversible command */
4916 Editor::clear_playlist (boost::shared_ptr<Playlist> playlist)
4918 playlist->clear_changes ();
4920 _session->add_command (new StatefulDiffCommand (playlist));
4924 Editor::nudge_track (bool use_edit, bool forwards)
4926 boost::shared_ptr<Playlist> playlist;
4927 framepos_t distance;
4928 framepos_t next_distance;
4932 start = get_preferred_edit_position();
4937 if ((distance = get_nudge_distance (start, next_distance)) == 0) {
4941 if (selection->tracks.empty()) {
4945 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4946 bool in_command = false;
4948 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4950 if ((playlist = (*i)->playlist()) == 0) {
4954 playlist->clear_changes ();
4955 playlist->clear_owned_changes ();
4957 playlist->nudge_after (start, distance, forwards);
4960 begin_reversible_command (_("nudge track"));
4963 vector<Command*> cmds;
4965 playlist->rdiff (cmds);
4966 _session->add_commands (cmds);
4968 _session->add_command (new StatefulDiffCommand (playlist));
4972 commit_reversible_command ();
4977 Editor::remove_last_capture ()
4979 vector<string> choices;
4986 if (Config->get_verify_remove_last_capture()) {
4987 prompt = _("Do you really want to destroy the last capture?"
4988 "\n(This is destructive and cannot be undone)");
4990 choices.push_back (_("No, do nothing."));
4991 choices.push_back (_("Yes, destroy it."));
4993 Gtkmm2ext::Choice prompter (_("Destroy last capture"), prompt, choices);
4995 if (prompter.run () == 1) {
4996 _session->remove_last_capture ();
4997 _regions->redisplay ();
5001 _session->remove_last_capture();
5002 _regions->redisplay ();
5007 Editor::normalize_region ()
5013 RegionSelection rs = get_regions_from_selection_and_entered ();
5019 NormalizeDialog dialog (rs.size() > 1);
5021 if (dialog.run () == RESPONSE_CANCEL) {
5025 CursorContext::Handle cursor_ctx = CursorContext::create(*this, _cursors->wait);
5028 /* XXX: should really only count audio regions here */
5029 int const regions = rs.size ();
5031 /* Make a list of the selected audio regions' maximum amplitudes, and also
5032 obtain the maximum amplitude of them all.
5034 list<double> max_amps;
5036 for (RegionSelection::const_iterator i = rs.begin(); i != rs.end(); ++i) {
5037 AudioRegionView const * arv = dynamic_cast<AudioRegionView const *> (*i);
5039 dialog.descend (1.0 / regions);
5040 double const a = arv->audio_region()->maximum_amplitude (&dialog);
5043 /* the user cancelled the operation */
5047 max_amps.push_back (a);
5048 max_amp = max (max_amp, a);
5053 list<double>::const_iterator a = max_amps.begin ();
5054 bool in_command = false;
5056 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
5057 AudioRegionView* const arv = dynamic_cast<AudioRegionView*> (*r);
5062 arv->region()->clear_changes ();
5064 double const amp = dialog.normalize_individually() ? *a : max_amp;
5066 arv->audio_region()->normalize (amp, dialog.target ());
5069 begin_reversible_command (_("normalize"));
5072 _session->add_command (new StatefulDiffCommand (arv->region()));
5078 commit_reversible_command ();
5084 Editor::reset_region_scale_amplitude ()
5090 RegionSelection rs = get_regions_from_selection_and_entered ();
5096 bool in_command = false;
5098 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
5099 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
5102 arv->region()->clear_changes ();
5103 arv->audio_region()->set_scale_amplitude (1.0f);
5106 begin_reversible_command ("reset gain");
5109 _session->add_command (new StatefulDiffCommand (arv->region()));
5113 commit_reversible_command ();
5118 Editor::adjust_region_gain (bool up)
5120 RegionSelection rs = get_regions_from_selection_and_entered ();
5122 if (!_session || rs.empty()) {
5126 bool in_command = false;
5128 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
5129 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
5134 arv->region()->clear_changes ();
5136 double dB = accurate_coefficient_to_dB (arv->audio_region()->scale_amplitude ());
5144 arv->audio_region()->set_scale_amplitude (dB_to_coefficient (dB));
5147 begin_reversible_command ("adjust region gain");
5150 _session->add_command (new StatefulDiffCommand (arv->region()));
5154 commit_reversible_command ();
5160 Editor::reverse_region ()
5166 Reverse rev (*_session);
5167 apply_filter (rev, _("reverse regions"));
5171 Editor::strip_region_silence ()
5177 RegionSelection rs = get_regions_from_selection_and_entered ();
5183 std::list<RegionView*> audio_only;
5185 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5186 AudioRegionView* const arv = dynamic_cast<AudioRegionView*> (*i);
5188 audio_only.push_back (arv);
5192 assert (!audio_only.empty());
5194 StripSilenceDialog d (_session, audio_only);
5195 int const r = d.run ();
5199 if (r == Gtk::RESPONSE_OK) {
5200 ARDOUR::AudioIntervalMap silences;
5201 d.silences (silences);
5202 StripSilence s (*_session, silences, d.fade_length());
5204 apply_filter (s, _("strip silence"), &d);
5209 Editor::apply_midi_note_edit_op_to_region (MidiOperator& op, MidiRegionView& mrv)
5211 Evoral::Sequence<Evoral::Beats>::Notes selected;
5212 mrv.selection_as_notelist (selected, true);
5214 vector<Evoral::Sequence<Evoral::Beats>::Notes> v;
5215 v.push_back (selected);
5217 framepos_t pos_frames = mrv.midi_region()->position() - mrv.midi_region()->start();
5218 Evoral::Beats pos_beats = _session->tempo_map().framewalk_to_beats(0, pos_frames);
5220 return op (mrv.midi_region()->model(), pos_beats, v);
5224 Editor::apply_midi_note_edit_op (MidiOperator& op, const RegionSelection& rs)
5230 bool in_command = false;
5232 for (RegionSelection::const_iterator r = rs.begin(); r != rs.end(); ) {
5233 RegionSelection::const_iterator tmp = r;
5236 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*r);
5239 Command* cmd = apply_midi_note_edit_op_to_region (op, *mrv);
5242 begin_reversible_command (op.name ());
5246 _session->add_command (cmd);
5254 commit_reversible_command ();
5259 Editor::fork_region ()
5261 RegionSelection rs = get_regions_from_selection_and_entered ();
5267 CursorContext::Handle cursor_ctx = CursorContext::create(*this, _cursors->wait);
5268 bool in_command = false;
5272 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
5273 RegionSelection::iterator tmp = r;
5276 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*>(*r);
5280 boost::shared_ptr<Playlist> playlist = mrv->region()->playlist();
5281 boost::shared_ptr<MidiSource> new_source = _session->create_midi_source_by_stealing_name (mrv->midi_view()->track());
5282 boost::shared_ptr<MidiRegion> newregion = mrv->midi_region()->clone (new_source);
5285 begin_reversible_command (_("Fork Region(s)"));
5288 playlist->clear_changes ();
5289 playlist->replace_region (mrv->region(), newregion, mrv->region()->position());
5290 _session->add_command(new StatefulDiffCommand (playlist));
5292 error << string_compose (_("Could not unlink %1"), mrv->region()->name()) << endmsg;
5300 commit_reversible_command ();
5305 Editor::quantize_region ()
5308 quantize_regions(get_regions_from_selection_and_entered ());
5313 Editor::quantize_regions (const RegionSelection& rs)
5315 if (rs.n_midi_regions() == 0) {
5319 if (!quantize_dialog) {
5320 quantize_dialog = new QuantizeDialog (*this);
5323 quantize_dialog->present ();
5324 const int r = quantize_dialog->run ();
5325 quantize_dialog->hide ();
5327 if (r == Gtk::RESPONSE_OK) {
5328 Quantize quant (quantize_dialog->snap_start(),
5329 quantize_dialog->snap_end(),
5330 quantize_dialog->start_grid_size(),
5331 quantize_dialog->end_grid_size(),
5332 quantize_dialog->strength(),
5333 quantize_dialog->swing(),
5334 quantize_dialog->threshold());
5336 apply_midi_note_edit_op (quant, rs);
5341 Editor::legatize_region (bool shrink_only)
5344 legatize_regions(get_regions_from_selection_and_entered (), shrink_only);
5349 Editor::legatize_regions (const RegionSelection& rs, bool shrink_only)
5351 if (rs.n_midi_regions() == 0) {
5355 Legatize legatize(shrink_only);
5356 apply_midi_note_edit_op (legatize, rs);
5360 Editor::transform_region ()
5363 transform_regions(get_regions_from_selection_and_entered ());
5368 Editor::transform_regions (const RegionSelection& rs)
5370 if (rs.n_midi_regions() == 0) {
5377 const int r = td.run();
5380 if (r == Gtk::RESPONSE_OK) {
5381 Transform transform(td.get());
5382 apply_midi_note_edit_op(transform, rs);
5387 Editor::transpose_region ()
5390 transpose_regions(get_regions_from_selection_and_entered ());
5395 Editor::transpose_regions (const RegionSelection& rs)
5397 if (rs.n_midi_regions() == 0) {
5402 int const r = d.run ();
5404 if (r == RESPONSE_ACCEPT) {
5405 Transpose transpose(d.semitones ());
5406 apply_midi_note_edit_op (transpose, rs);
5411 Editor::insert_patch_change (bool from_context)
5413 RegionSelection rs = get_regions_from_selection_and_entered ();
5419 const framepos_t p = get_preferred_edit_position (EDIT_IGNORE_NONE, from_context);
5421 /* XXX: bit of a hack; use the MIDNAM from the first selected region;
5422 there may be more than one, but the PatchChangeDialog can only offer
5423 one set of patch menus.
5425 MidiRegionView* first = dynamic_cast<MidiRegionView*> (rs.front ());
5427 Evoral::PatchChange<Evoral::Beats> empty (Evoral::Beats(), 0, 0, 0);
5428 PatchChangeDialog d (0, _session, empty, first->instrument_info(), Gtk::Stock::ADD);
5430 if (d.run() == RESPONSE_CANCEL) {
5434 for (RegionSelection::iterator i = rs.begin (); i != rs.end(); ++i) {
5435 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*i);
5437 if (p >= mrv->region()->first_frame() && p <= mrv->region()->last_frame()) {
5438 mrv->add_patch_change (p - mrv->region()->position(), d.patch ());
5445 Editor::apply_filter (Filter& filter, string command, ProgressReporter* progress)
5447 RegionSelection rs = get_regions_from_selection_and_entered ();
5453 CursorContext::Handle cursor_ctx = CursorContext::create(*this, _cursors->wait);
5454 bool in_command = false;
5459 int const N = rs.size ();
5461 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
5462 RegionSelection::iterator tmp = r;
5465 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
5467 boost::shared_ptr<Playlist> playlist = arv->region()->playlist();
5470 progress->descend (1.0 / N);
5473 if (arv->audio_region()->apply (filter, progress) == 0) {
5475 playlist->clear_changes ();
5476 playlist->clear_owned_changes ();
5479 begin_reversible_command (command);
5483 if (filter.results.empty ()) {
5485 /* no regions returned; remove the old one */
5486 playlist->remove_region (arv->region ());
5490 std::vector<boost::shared_ptr<Region> >::iterator res = filter.results.begin ();
5492 /* first region replaces the old one */
5493 playlist->replace_region (arv->region(), *res, (*res)->position());
5497 while (res != filter.results.end()) {
5498 playlist->add_region (*res, (*res)->position());
5504 /* We might have removed regions, which alters other regions' layering_index,
5505 so we need to do a recursive diff here.
5507 vector<Command*> cmds;
5508 playlist->rdiff (cmds);
5509 _session->add_commands (cmds);
5511 _session->add_command(new StatefulDiffCommand (playlist));
5515 progress->ascend ();
5524 commit_reversible_command ();
5529 Editor::external_edit_region ()
5535 Editor::reset_region_gain_envelopes ()
5537 RegionSelection rs = get_regions_from_selection_and_entered ();
5539 if (!_session || rs.empty()) {
5543 bool in_command = false;
5545 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5546 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
5548 boost::shared_ptr<AutomationList> alist (arv->audio_region()->envelope());
5549 XMLNode& before (alist->get_state());
5551 arv->audio_region()->set_default_envelope ();
5554 begin_reversible_command (_("reset region gain"));
5557 _session->add_command (new MementoCommand<AutomationList>(*arv->audio_region()->envelope().get(), &before, &alist->get_state()));
5562 commit_reversible_command ();
5567 Editor::set_region_gain_visibility (RegionView* rv)
5569 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (rv);
5571 arv->update_envelope_visibility();
5576 Editor::set_gain_envelope_visibility ()
5582 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5583 AudioTimeAxisView* v = dynamic_cast<AudioTimeAxisView*>(*i);
5585 v->audio_view()->foreach_regionview (sigc::mem_fun (this, &Editor::set_region_gain_visibility));
5591 Editor::toggle_gain_envelope_active ()
5593 if (_ignore_region_action) {
5597 RegionSelection rs = get_regions_from_selection_and_entered ();
5599 if (!_session || rs.empty()) {
5603 bool in_command = false;
5605 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5606 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
5608 arv->region()->clear_changes ();
5609 arv->audio_region()->set_envelope_active (!arv->audio_region()->envelope_active());
5612 begin_reversible_command (_("region gain envelope active"));
5615 _session->add_command (new StatefulDiffCommand (arv->region()));
5620 commit_reversible_command ();
5625 Editor::toggle_region_lock ()
5627 if (_ignore_region_action) {
5631 RegionSelection rs = get_regions_from_selection_and_entered ();
5633 if (!_session || rs.empty()) {
5637 begin_reversible_command (_("toggle region lock"));
5639 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5640 (*i)->region()->clear_changes ();
5641 (*i)->region()->set_locked (!(*i)->region()->locked());
5642 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5645 commit_reversible_command ();
5649 Editor::toggle_region_video_lock ()
5651 if (_ignore_region_action) {
5655 RegionSelection rs = get_regions_from_selection_and_entered ();
5657 if (!_session || rs.empty()) {
5661 begin_reversible_command (_("Toggle Video Lock"));
5663 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5664 (*i)->region()->clear_changes ();
5665 (*i)->region()->set_video_locked (!(*i)->region()->video_locked());
5666 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5669 commit_reversible_command ();
5673 Editor::toggle_region_lock_style ()
5675 if (_ignore_region_action) {
5679 RegionSelection rs = get_regions_from_selection_and_entered ();
5681 if (!_session || rs.empty()) {
5685 begin_reversible_command (_("region lock style"));
5687 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5688 (*i)->region()->clear_changes ();
5689 PositionLockStyle const ns = (*i)->region()->position_lock_style() == AudioTime ? MusicTime : AudioTime;
5690 (*i)->region()->set_position_lock_style (ns);
5691 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5694 commit_reversible_command ();
5698 Editor::toggle_opaque_region ()
5700 if (_ignore_region_action) {
5704 RegionSelection rs = get_regions_from_selection_and_entered ();
5706 if (!_session || rs.empty()) {
5710 begin_reversible_command (_("change region opacity"));
5712 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5713 (*i)->region()->clear_changes ();
5714 (*i)->region()->set_opaque (!(*i)->region()->opaque());
5715 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5718 commit_reversible_command ();
5722 Editor::toggle_record_enable ()
5724 bool new_state = false;
5726 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5727 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5730 if (!rtav->is_track())
5734 new_state = !rtav->track()->rec_enable_control()->get_value();
5738 rtav->track()->rec_enable_control()->set_value (new_state, Controllable::UseGroup);
5743 Editor::toggle_solo ()
5745 bool new_state = false;
5747 boost::shared_ptr<ControlList> cl (new ControlList);
5749 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5750 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5757 new_state = !rtav->route()->soloed ();
5761 cl->push_back (rtav->route()->solo_control());
5764 _session->set_controls (cl, new_state ? 1.0 : 0.0, Controllable::UseGroup);
5768 Editor::toggle_mute ()
5770 bool new_state = false;
5772 boost::shared_ptr<RouteList> rl (new RouteList);
5774 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5775 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5782 new_state = !rtav->route()->muted();
5786 rl->push_back (rtav->route());
5789 _session->set_controls (route_list_to_control_list (rl, &Stripable::mute_control), new_state, Controllable::UseGroup);
5793 Editor::toggle_solo_isolate ()
5799 Editor::fade_range ()
5801 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
5803 begin_reversible_command (_("fade range"));
5805 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
5806 (*i)->fade_range (selection->time);
5809 commit_reversible_command ();
5814 Editor::set_fade_length (bool in)
5816 RegionSelection rs = get_regions_from_selection_and_entered ();
5822 /* we need a region to measure the offset from the start */
5824 RegionView* rv = rs.front ();
5826 framepos_t pos = get_preferred_edit_position();
5830 if (pos > rv->region()->last_frame() || pos < rv->region()->first_frame()) {
5831 /* edit point is outside the relevant region */
5836 if (pos <= rv->region()->position()) {
5840 len = pos - rv->region()->position();
5841 cmd = _("set fade in length");
5843 if (pos >= rv->region()->last_frame()) {
5847 len = rv->region()->last_frame() - pos;
5848 cmd = _("set fade out length");
5851 bool in_command = false;
5853 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5854 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5860 boost::shared_ptr<AutomationList> alist;
5862 alist = tmp->audio_region()->fade_in();
5864 alist = tmp->audio_region()->fade_out();
5867 XMLNode &before = alist->get_state();
5870 tmp->audio_region()->set_fade_in_length (len);
5871 tmp->audio_region()->set_fade_in_active (true);
5873 tmp->audio_region()->set_fade_out_length (len);
5874 tmp->audio_region()->set_fade_out_active (true);
5878 begin_reversible_command (cmd);
5881 XMLNode &after = alist->get_state();
5882 _session->add_command(new MementoCommand<AutomationList>(*alist, &before, &after));
5886 commit_reversible_command ();
5891 Editor::set_fade_in_shape (FadeShape shape)
5893 RegionSelection rs = get_regions_from_selection_and_entered ();
5898 bool in_command = false;
5900 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5901 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5907 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_in();
5908 XMLNode &before = alist->get_state();
5910 tmp->audio_region()->set_fade_in_shape (shape);
5913 begin_reversible_command (_("set fade in shape"));
5916 XMLNode &after = alist->get_state();
5917 _session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
5921 commit_reversible_command ();
5926 Editor::set_fade_out_shape (FadeShape shape)
5928 RegionSelection rs = get_regions_from_selection_and_entered ();
5933 bool in_command = false;
5935 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5936 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5942 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_out();
5943 XMLNode &before = alist->get_state();
5945 tmp->audio_region()->set_fade_out_shape (shape);
5948 begin_reversible_command (_("set fade out shape"));
5951 XMLNode &after = alist->get_state();
5952 _session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
5956 commit_reversible_command ();
5961 Editor::set_fade_in_active (bool yn)
5963 RegionSelection rs = get_regions_from_selection_and_entered ();
5968 bool in_command = false;
5970 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5971 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5978 boost::shared_ptr<AudioRegion> ar (tmp->audio_region());
5980 ar->clear_changes ();
5981 ar->set_fade_in_active (yn);
5984 begin_reversible_command (_("set fade in active"));
5987 _session->add_command (new StatefulDiffCommand (ar));
5991 commit_reversible_command ();
5996 Editor::set_fade_out_active (bool yn)
5998 RegionSelection rs = get_regions_from_selection_and_entered ();
6003 bool in_command = false;
6005 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
6006 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
6012 boost::shared_ptr<AudioRegion> ar (tmp->audio_region());
6014 ar->clear_changes ();
6015 ar->set_fade_out_active (yn);
6018 begin_reversible_command (_("set fade out active"));
6021 _session->add_command(new StatefulDiffCommand (ar));
6025 commit_reversible_command ();
6030 Editor::toggle_region_fades (int dir)
6032 if (_ignore_region_action) {
6036 boost::shared_ptr<AudioRegion> ar;
6039 RegionSelection rs = get_regions_from_selection_and_entered ();
6045 RegionSelection::iterator i;
6046 for (i = rs.begin(); i != rs.end(); ++i) {
6047 if ((ar = boost::dynamic_pointer_cast<AudioRegion>((*i)->region())) != 0) {
6049 yn = ar->fade_out_active ();
6051 yn = ar->fade_in_active ();
6057 if (i == rs.end()) {
6061 /* XXX should this undo-able? */
6062 bool in_command = false;
6064 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
6065 if ((ar = boost::dynamic_pointer_cast<AudioRegion>((*i)->region())) == 0) {
6068 ar->clear_changes ();
6070 if (dir == 1 || dir == 0) {
6071 ar->set_fade_in_active (!yn);
6074 if (dir == -1 || dir == 0) {
6075 ar->set_fade_out_active (!yn);
6078 begin_reversible_command (_("toggle fade active"));
6081 _session->add_command(new StatefulDiffCommand (ar));
6085 commit_reversible_command ();
6090 /** Update region fade visibility after its configuration has been changed */
6092 Editor::update_region_fade_visibility ()
6094 bool _fade_visibility = _session->config.get_show_region_fades ();
6096 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
6097 AudioTimeAxisView* v = dynamic_cast<AudioTimeAxisView*>(*i);
6099 if (_fade_visibility) {
6100 v->audio_view()->show_all_fades ();
6102 v->audio_view()->hide_all_fades ();
6109 Editor::set_edit_point ()
6114 if (!mouse_frame (where, ignored)) {
6120 if (selection->markers.empty()) {
6122 mouse_add_new_marker (where);
6127 Location* loc = find_location_from_marker (selection->markers.front(), ignored);
6130 loc->move_to (where);
6136 Editor::set_playhead_cursor ()
6138 if (entered_marker) {
6139 _session->request_locate (entered_marker->position(), _session->transport_rolling());
6144 if (!mouse_frame (where, ignored)) {
6151 _session->request_locate (where, _session->transport_rolling());
6155 if (UIConfiguration::instance().get_follow_edits() && (!_session || !_session->config.get_external_sync())) {
6156 cancel_time_selection();
6161 Editor::split_region ()
6163 if (_drags->active ()) {
6167 //if a range is selected, separate it
6168 if ( !selection->time.empty()) {
6169 separate_regions_between (selection->time);
6173 //if no range was selected, try to find some regions to split
6174 if (current_mouse_mode() == MouseObject) { //don't try this for Internal Edit, Stretch, Draw, etc.
6176 RegionSelection rs = get_regions_from_selection_and_edit_point ();
6178 framepos_t where = get_preferred_edit_position ();
6184 if (snap_musical()) {
6185 split_regions_at (where, rs, get_grid_music_divisions (0));
6187 split_regions_at (where, rs, 0);
6193 Editor::select_next_route()
6195 if (selection->tracks.empty()) {
6196 selection->set (track_views.front());
6200 TimeAxisView* current = selection->tracks.front();
6204 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
6206 if (*i == current) {
6208 if (i != track_views.end()) {
6211 current = (*(track_views.begin()));
6212 //selection->set (*(track_views.begin()));
6218 rui = dynamic_cast<RouteUI *>(current);
6220 } while (current->hidden() || (rui == NULL) || !rui->route()->active());
6222 selection->set (current);
6224 ensure_time_axis_view_is_visible (*current, false);
6228 Editor::select_prev_route()
6230 if (selection->tracks.empty()) {
6231 selection->set (track_views.front());
6235 TimeAxisView* current = selection->tracks.front();
6239 for (TrackViewList::reverse_iterator i = track_views.rbegin(); i != track_views.rend(); ++i) {
6241 if (*i == current) {
6243 if (i != track_views.rend()) {
6246 current = *(track_views.rbegin());
6251 rui = dynamic_cast<RouteUI *>(current);
6253 } while (current->hidden() || (rui == NULL) || !rui->route()->active());
6255 selection->set (current);
6257 ensure_time_axis_view_is_visible (*current, false);
6261 Editor::set_loop_from_selection (bool play)
6263 if (_session == 0) {
6267 framepos_t start, end;
6268 if (!get_selection_extents ( start, end))
6271 set_loop_range (start, end, _("set loop range from selection"));
6274 _session->request_play_loop (true, true);
6279 Editor::set_loop_from_region (bool play)
6281 framepos_t start, end;
6282 if (!get_selection_extents ( start, end))
6285 set_loop_range (start, end, _("set loop range from region"));
6288 _session->request_locate (start, true);
6289 _session->request_play_loop (true);
6294 Editor::set_punch_from_selection ()
6296 if (_session == 0) {
6300 framepos_t start, end;
6301 if (!get_selection_extents ( start, end))
6304 set_punch_range (start, end, _("set punch range from selection"));
6308 Editor::set_session_extents_from_selection ()
6310 if (_session == 0) {
6314 framepos_t start, end;
6315 if (!get_selection_extents ( start, end))
6319 if ((loc = _session->locations()->session_range_location()) == 0) {
6320 _session->set_session_extents (start, end); // this will create a new session range; no need for UNDO
6322 XMLNode &before = loc->get_state();
6324 _session->set_session_extents (start, end);
6326 XMLNode &after = loc->get_state();
6328 begin_reversible_command (_("set session start/end from selection"));
6330 _session->add_command (new MementoCommand<Location>(*loc, &before, &after));
6332 commit_reversible_command ();
6335 _session->set_end_is_free (false);
6339 Editor::set_punch_start_from_edit_point ()
6343 framepos_t start = 0;
6344 framepos_t end = max_framepos;
6346 //use the existing punch end, if any
6347 Location* tpl = transport_punch_location();
6352 if ((_edit_point == EditAtPlayhead) && _session->transport_rolling()) {
6353 start = _session->audible_frame();
6355 start = get_preferred_edit_position();
6358 //snap the selection start/end
6361 //if there's not already a sensible selection endpoint, go "forever"
6362 if ( start > end ) {
6366 set_punch_range (start, end, _("set punch start from EP"));
6372 Editor::set_punch_end_from_edit_point ()
6376 framepos_t start = 0;
6377 framepos_t end = max_framepos;
6379 //use the existing punch start, if any
6380 Location* tpl = transport_punch_location();
6382 start = tpl->start();
6385 if ((_edit_point == EditAtPlayhead) && _session->transport_rolling()) {
6386 end = _session->audible_frame();
6388 end = get_preferred_edit_position();
6391 //snap the selection start/end
6394 set_punch_range (start, end, _("set punch end from EP"));
6400 Editor::set_loop_start_from_edit_point ()
6404 framepos_t start = 0;
6405 framepos_t end = max_framepos;
6407 //use the existing loop end, if any
6408 Location* tpl = transport_loop_location();
6413 if ((_edit_point == EditAtPlayhead) && _session->transport_rolling()) {
6414 start = _session->audible_frame();
6416 start = get_preferred_edit_position();
6419 //snap the selection start/end
6422 //if there's not already a sensible selection endpoint, go "forever"
6423 if ( start > end ) {
6427 set_loop_range (start, end, _("set loop start from EP"));
6433 Editor::set_loop_end_from_edit_point ()
6437 framepos_t start = 0;
6438 framepos_t end = max_framepos;
6440 //use the existing loop start, if any
6441 Location* tpl = transport_loop_location();
6443 start = tpl->start();
6446 if ((_edit_point == EditAtPlayhead) && _session->transport_rolling()) {
6447 end = _session->audible_frame();
6449 end = get_preferred_edit_position();
6452 //snap the selection start/end
6455 set_loop_range (start, end, _("set loop end from EP"));
6460 Editor::set_punch_from_region ()
6462 framepos_t start, end;
6463 if (!get_selection_extents ( start, end))
6466 set_punch_range (start, end, _("set punch range from region"));
6470 Editor::pitch_shift_region ()
6472 RegionSelection rs = get_regions_from_selection_and_entered ();
6474 RegionSelection audio_rs;
6475 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
6476 if (dynamic_cast<AudioRegionView*> (*i)) {
6477 audio_rs.push_back (*i);
6481 if (audio_rs.empty()) {
6485 pitch_shift (audio_rs, 1.2);
6489 Editor::set_tempo_from_region ()
6491 RegionSelection rs = get_regions_from_selection_and_entered ();
6493 if (!_session || rs.empty()) {
6497 RegionView* rv = rs.front();
6499 define_one_bar (rv->region()->position(), rv->region()->last_frame() + 1);
6503 Editor::use_range_as_bar ()
6505 framepos_t start, end;
6506 if (get_edit_op_range (start, end)) {
6507 define_one_bar (start, end);
6512 Editor::define_one_bar (framepos_t start, framepos_t end)
6514 framepos_t length = end - start;
6516 const Meter& m (_session->tempo_map().meter_at_frame (start));
6518 /* length = 1 bar */
6520 /* We're going to deliver a constant tempo here,
6521 so we can use frames per beat to determine length.
6522 now we want frames per beat.
6523 we have frames per bar, and beats per bar, so ...
6526 /* XXXX METER MATH */
6528 double frames_per_beat = length / m.divisions_per_bar();
6530 /* beats per minute = */
6532 double beats_per_minute = (_session->frame_rate() * 60.0) / frames_per_beat;
6534 /* now decide whether to:
6536 (a) set global tempo
6537 (b) add a new tempo marker
6541 const TempoSection& t (_session->tempo_map().tempo_section_at_frame (start));
6543 bool do_global = false;
6545 if ((_session->tempo_map().n_tempos() == 1) && (_session->tempo_map().n_meters() == 1)) {
6547 /* only 1 tempo & 1 meter: ask if the user wants to set the tempo
6548 at the start, or create a new marker
6551 vector<string> options;
6552 options.push_back (_("Cancel"));
6553 options.push_back (_("Add new marker"));
6554 options.push_back (_("Set global tempo"));
6557 _("Define one bar"),
6558 _("Do you want to set the global tempo or add a new tempo marker?"),
6562 c.set_default_response (2);
6578 /* more than 1 tempo and/or meter section already, go ahead do the "usual":
6579 if the marker is at the region starter, change it, otherwise add
6584 begin_reversible_command (_("set tempo from region"));
6585 XMLNode& before (_session->tempo_map().get_state());
6588 _session->tempo_map().change_initial_tempo (beats_per_minute, t.note_type());
6589 } else if (t.frame() == start) {
6590 _session->tempo_map().change_existing_tempo_at (start, beats_per_minute, t.note_type());
6592 const Tempo tempo (beats_per_minute, t.note_type());
6593 _session->tempo_map().add_tempo (tempo, 0.0, start, TempoSection::Constant, AudioTime);
6596 XMLNode& after (_session->tempo_map().get_state());
6598 _session->add_command (new MementoCommand<TempoMap>(_session->tempo_map(), &before, &after));
6599 commit_reversible_command ();
6603 Editor::split_region_at_transients ()
6605 AnalysisFeatureList positions;
6607 RegionSelection rs = get_regions_from_selection_and_entered ();
6609 if (!_session || rs.empty()) {
6613 begin_reversible_command (_("split regions"));
6615 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ) {
6617 RegionSelection::iterator tmp;
6622 boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion> ((*i)->region());
6625 ar->transients (positions);
6626 split_region_at_points ((*i)->region(), positions, true);
6633 commit_reversible_command ();
6638 Editor::split_region_at_points (boost::shared_ptr<Region> r, AnalysisFeatureList& positions, bool can_ferret, bool select_new)
6640 bool use_rhythmic_rodent = false;
6642 boost::shared_ptr<Playlist> pl = r->playlist();
6644 list<boost::shared_ptr<Region> > new_regions;
6650 if (positions.empty()) {
6654 if (positions.size() > 20 && can_ferret) {
6655 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);
6656 MessageDialog msg (msgstr,
6659 Gtk::BUTTONS_OK_CANCEL);
6662 msg.add_button (_("Call for the Ferret!"), RESPONSE_APPLY);
6663 msg.set_secondary_text (_("Press OK to continue with this split operation\nor ask the Ferret dialog to tune the analysis"));
6665 msg.set_secondary_text (_("Press OK to continue with this split operation"));
6668 msg.set_title (_("Excessive split?"));
6671 int response = msg.run();
6677 case RESPONSE_APPLY:
6678 use_rhythmic_rodent = true;
6685 if (use_rhythmic_rodent) {
6686 show_rhythm_ferret ();
6690 AnalysisFeatureList::const_iterator x;
6692 pl->clear_changes ();
6693 pl->clear_owned_changes ();
6695 x = positions.begin();
6697 if (x == positions.end()) {
6702 pl->remove_region (r);
6706 framepos_t rstart = r->first_frame ();
6707 framepos_t rend = r->last_frame ();
6709 while (x != positions.end()) {
6711 /* deal with positons that are out of scope of present region bounds */
6712 if (*x <= rstart || *x > rend) {
6717 /* file start = original start + how far we from the initial position ? */
6719 framepos_t file_start = r->start() + pos;
6721 /* length = next position - current position */
6723 framepos_t len = (*x) - pos - rstart;
6725 /* XXX we do we really want to allow even single-sample regions?
6726 * shouldn't we have some kind of lower limit on region size?
6735 if (RegionFactory::region_name (new_name, r->name())) {
6739 /* do NOT announce new regions 1 by one, just wait till they are all done */
6743 plist.add (ARDOUR::Properties::start, file_start);
6744 plist.add (ARDOUR::Properties::length, len);
6745 plist.add (ARDOUR::Properties::name, new_name);
6746 plist.add (ARDOUR::Properties::layer, 0);
6747 // TODO set transients_offset
6749 boost::shared_ptr<Region> nr = RegionFactory::create (r->sources(), plist, false);
6750 /* because we set annouce to false, manually add the new region to the
6753 RegionFactory::map_add (nr);
6755 pl->add_region (nr, rstart + pos);
6758 new_regions.push_front(nr);
6767 RegionFactory::region_name (new_name, r->name());
6769 /* Add the final region */
6772 plist.add (ARDOUR::Properties::start, r->start() + pos);
6773 plist.add (ARDOUR::Properties::length, r->last_frame() - (r->position() + pos) + 1);
6774 plist.add (ARDOUR::Properties::name, new_name);
6775 plist.add (ARDOUR::Properties::layer, 0);
6777 boost::shared_ptr<Region> nr = RegionFactory::create (r->sources(), plist, false);
6778 /* because we set annouce to false, manually add the new region to the
6781 RegionFactory::map_add (nr);
6782 pl->add_region (nr, r->position() + pos);
6785 new_regions.push_front(nr);
6790 /* We might have removed regions, which alters other regions' layering_index,
6791 so we need to do a recursive diff here.
6793 vector<Command*> cmds;
6795 _session->add_commands (cmds);
6797 _session->add_command (new StatefulDiffCommand (pl));
6801 for (list<boost::shared_ptr<Region> >::iterator i = new_regions.begin(); i != new_regions.end(); ++i){
6802 set_selected_regionview_from_region_list ((*i), Selection::Add);
6808 Editor::place_transient()
6814 RegionSelection rs = get_regions_from_selection_and_edit_point ();
6820 framepos_t where = get_preferred_edit_position();
6822 begin_reversible_command (_("place transient"));
6824 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6825 (*r)->region()->add_transient(where);
6828 commit_reversible_command ();
6832 Editor::remove_transient(ArdourCanvas::Item* item)
6838 ArdourCanvas::Line* _line = reinterpret_cast<ArdourCanvas::Line*> (item);
6841 AudioRegionView* _arv = reinterpret_cast<AudioRegionView*> (item->get_data ("regionview"));
6842 _arv->remove_transient (*(float*) _line->get_data ("position"));
6846 Editor::snap_regions_to_grid ()
6848 list <boost::shared_ptr<Playlist > > used_playlists;
6850 RegionSelection rs = get_regions_from_selection_and_entered ();
6852 if (!_session || rs.empty()) {
6856 begin_reversible_command (_("snap regions to grid"));
6858 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6860 boost::shared_ptr<Playlist> pl = (*r)->region()->playlist();
6862 if (!pl->frozen()) {
6863 /* we haven't seen this playlist before */
6865 /* remember used playlists so we can thaw them later */
6866 used_playlists.push_back(pl);
6870 framepos_t start_frame = (*r)->region()->first_frame ();
6871 snap_to (start_frame);
6872 (*r)->region()->set_position (start_frame);
6875 while (used_playlists.size() > 0) {
6876 list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
6878 used_playlists.pop_front();
6881 commit_reversible_command ();
6885 Editor::close_region_gaps ()
6887 list <boost::shared_ptr<Playlist > > used_playlists;
6889 RegionSelection rs = get_regions_from_selection_and_entered ();
6891 if (!_session || rs.empty()) {
6895 Dialog dialog (_("Close Region Gaps"));
6898 table.set_spacings (12);
6899 table.set_border_width (12);
6900 Label* l = manage (left_aligned_label (_("Crossfade length")));
6901 table.attach (*l, 0, 1, 0, 1);
6903 SpinButton spin_crossfade (1, 0);
6904 spin_crossfade.set_range (0, 15);
6905 spin_crossfade.set_increments (1, 1);
6906 spin_crossfade.set_value (5);
6907 table.attach (spin_crossfade, 1, 2, 0, 1);
6909 table.attach (*manage (new Label (_("ms"))), 2, 3, 0, 1);
6911 l = manage (left_aligned_label (_("Pull-back length")));
6912 table.attach (*l, 0, 1, 1, 2);
6914 SpinButton spin_pullback (1, 0);
6915 spin_pullback.set_range (0, 100);
6916 spin_pullback.set_increments (1, 1);
6917 spin_pullback.set_value(30);
6918 table.attach (spin_pullback, 1, 2, 1, 2);
6920 table.attach (*manage (new Label (_("ms"))), 2, 3, 1, 2);
6922 dialog.get_vbox()->pack_start (table);
6923 dialog.add_button (Stock::CANCEL, RESPONSE_CANCEL);
6924 dialog.add_button (_("Ok"), RESPONSE_ACCEPT);
6927 if (dialog.run () == RESPONSE_CANCEL) {
6931 framepos_t crossfade_len = spin_crossfade.get_value();
6932 framepos_t pull_back_frames = spin_pullback.get_value();
6934 crossfade_len = lrintf (crossfade_len * _session->frame_rate()/1000);
6935 pull_back_frames = lrintf (pull_back_frames * _session->frame_rate()/1000);
6937 /* Iterate over the region list and make adjacent regions overlap by crossfade_len_ms */
6939 begin_reversible_command (_("close region gaps"));
6942 boost::shared_ptr<Region> last_region;
6944 rs.sort_by_position_and_track();
6946 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6948 boost::shared_ptr<Playlist> pl = (*r)->region()->playlist();
6950 if (!pl->frozen()) {
6951 /* we haven't seen this playlist before */
6953 /* remember used playlists so we can thaw them later */
6954 used_playlists.push_back(pl);
6958 framepos_t position = (*r)->region()->position();
6960 if (idx == 0 || position < last_region->position()){
6961 last_region = (*r)->region();
6966 (*r)->region()->trim_front( (position - pull_back_frames));
6967 last_region->trim_end( (position - pull_back_frames + crossfade_len));
6969 last_region = (*r)->region();
6974 while (used_playlists.size() > 0) {
6975 list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
6977 used_playlists.pop_front();
6980 commit_reversible_command ();
6984 Editor::tab_to_transient (bool forward)
6986 AnalysisFeatureList positions;
6988 RegionSelection rs = get_regions_from_selection_and_entered ();
6994 framepos_t pos = _session->audible_frame ();
6996 if (!selection->tracks.empty()) {
6998 /* don't waste time searching for transients in duplicate playlists.
7001 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
7003 for (TrackViewList::iterator t = ts.begin(); t != ts.end(); ++t) {
7005 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*t);
7008 boost::shared_ptr<Track> tr = rtv->track();
7010 boost::shared_ptr<Playlist> pl = tr->playlist ();
7012 framepos_t result = pl->find_next_transient (pos, forward ? 1 : -1);
7015 positions.push_back (result);
7028 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
7029 (*r)->region()->get_transients (positions);
7033 TransientDetector::cleanup_transients (positions, _session->frame_rate(), 3.0);
7036 AnalysisFeatureList::iterator x;
7038 for (x = positions.begin(); x != positions.end(); ++x) {
7044 if (x != positions.end ()) {
7045 _session->request_locate (*x);
7049 AnalysisFeatureList::reverse_iterator x;
7051 for (x = positions.rbegin(); x != positions.rend(); ++x) {
7057 if (x != positions.rend ()) {
7058 _session->request_locate (*x);
7064 Editor::playhead_forward_to_grid ()
7070 framepos_t pos = playhead_cursor->current_frame ();
7071 if (pos < max_framepos - 1) {
7073 snap_to_internal (pos, RoundUpAlways, false);
7074 _session->request_locate (pos);
7080 Editor::playhead_backward_to_grid ()
7086 framepos_t pos = playhead_cursor->current_frame ();
7089 snap_to_internal (pos, RoundDownAlways, false);
7090 _session->request_locate (pos);
7095 Editor::set_track_height (Height h)
7097 TrackSelection& ts (selection->tracks);
7099 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
7100 (*x)->set_height_enum (h);
7105 Editor::toggle_tracks_active ()
7107 TrackSelection& ts (selection->tracks);
7109 bool target = false;
7115 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
7116 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*x);
7120 target = !rtv->_route->active();
7123 rtv->_route->set_active (target, this);
7129 Editor::remove_tracks ()
7131 /* this will delete GUI objects that may be the subject of an event
7132 handler in which this method is called. Defer actual deletion to the
7133 next idle callback, when all event handling is finished.
7135 Glib::signal_idle().connect (sigc::mem_fun (*this, &Editor::idle_remove_tracks));
7139 Editor::idle_remove_tracks ()
7141 Session::StateProtector sp (_session);
7143 return false; /* do not call again */
7147 Editor::_remove_tracks ()
7149 TrackSelection& ts (selection->tracks);
7155 vector<string> choices;
7159 const char* trackstr;
7161 vector<boost::shared_ptr<Route> > routes;
7162 bool special_bus = false;
7164 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
7165 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*x);
7169 if (rtv->is_track()) {
7174 routes.push_back (rtv->_route);
7176 if (rtv->route()->is_master() || rtv->route()->is_monitor()) {
7181 if (special_bus && !Config->get_allow_special_bus_removal()) {
7182 MessageDialog msg (_("That would be bad news ...."),
7186 msg.set_secondary_text (string_compose (_(
7187 "Removing the master or monitor bus is such a bad idea\n\
7188 that %1 is not going to allow it.\n\
7190 If you really want to do this sort of thing\n\
7191 edit your ardour.rc file to set the\n\
7192 \"allow-special-bus-removal\" option to be \"yes\""), PROGRAM_NAME));
7199 if (ntracks + nbusses == 0) {
7203 trackstr = P_("track", "tracks", ntracks);
7204 busstr = P_("bus", "busses", nbusses);
7208 prompt = string_compose (_("Do you really want to remove %1 %2 and %3 %4?\n"
7209 "(You may also lose the playlists associated with the %2)\n\n"
7210 "This action cannot be undone, and the session file will be overwritten!"),
7211 ntracks, trackstr, nbusses, busstr);
7213 prompt = string_compose (_("Do you really want to remove %1 %2?\n"
7214 "(You may also lose the playlists associated with the %2)\n\n"
7215 "This action cannot be undone, and the session file will be overwritten!"),
7218 } else if (nbusses) {
7219 prompt = string_compose (_("Do you really want to remove %1 %2?\n\n"
7220 "This action cannot be undone, and the session file will be overwritten"),
7224 choices.push_back (_("No, do nothing."));
7225 if (ntracks + nbusses > 1) {
7226 choices.push_back (_("Yes, remove them."));
7228 choices.push_back (_("Yes, remove it."));
7233 title = string_compose (_("Remove %1"), trackstr);
7235 title = string_compose (_("Remove %1"), busstr);
7238 Choice prompter (title, prompt, choices);
7240 if (prompter.run () != 1) {
7245 DisplaySuspender ds;
7246 boost::shared_ptr<RouteList> rl (new RouteList);
7247 for (vector<boost::shared_ptr<Route> >::iterator x = routes.begin(); x != routes.end(); ++x) {
7250 _session->remove_routes (rl);
7252 /* TrackSelection and RouteList leave scope,
7253 * destructors are called,
7254 * diskstream drops references, save_state is called (again for every track)
7259 Editor::do_insert_time ()
7261 if (selection->tracks.empty()) {
7265 InsertRemoveTimeDialog d (*this);
7266 int response = d.run ();
7268 if (response != RESPONSE_OK) {
7272 if (d.distance() == 0) {
7277 get_preferred_edit_position (EDIT_IGNORE_MOUSE),
7279 d.intersected_region_action (),
7283 d.move_glued_markers(),
7284 d.move_locked_markers(),
7290 Editor::insert_time (
7291 framepos_t pos, framecnt_t frames, InsertTimeOption opt,
7292 bool all_playlists, bool ignore_music_glue, bool markers_too, bool glued_markers_too, bool locked_markers_too, bool tempo_too
7296 if (Config->get_edit_mode() == Lock) {
7299 bool in_command = false;
7301 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
7303 for (TrackViewList::iterator x = ts.begin(); x != ts.end(); ++x) {
7307 /* don't operate on any playlist more than once, which could
7308 * happen if "all playlists" is enabled, but there is more
7309 * than 1 track using playlists "from" a given track.
7312 set<boost::shared_ptr<Playlist> > pl;
7314 if (all_playlists) {
7315 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*x);
7316 if (rtav && rtav->track ()) {
7317 vector<boost::shared_ptr<Playlist> > all = _session->playlists->playlists_for_track (rtav->track ());
7318 for (vector<boost::shared_ptr<Playlist> >::iterator p = all.begin(); p != all.end(); ++p) {
7323 if ((*x)->playlist ()) {
7324 pl.insert ((*x)->playlist ());
7328 for (set<boost::shared_ptr<Playlist> >::iterator i = pl.begin(); i != pl.end(); ++i) {
7330 (*i)->clear_changes ();
7331 (*i)->clear_owned_changes ();
7333 if (opt == SplitIntersected) {
7334 /* non musical split */
7335 (*i)->split (pos, 0);
7338 (*i)->shift (pos, frames, (opt == MoveIntersected), ignore_music_glue);
7341 begin_reversible_command (_("insert time"));
7344 vector<Command*> cmds;
7346 _session->add_commands (cmds);
7348 _session->add_command (new StatefulDiffCommand (*i));
7352 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*x);
7355 begin_reversible_command (_("insert time"));
7358 rtav->route ()->shift (pos, frames);
7365 XMLNode& before (_session->locations()->get_state());
7366 Locations::LocationList copy (_session->locations()->list());
7368 for (Locations::LocationList::iterator i = copy.begin(); i != copy.end(); ++i) {
7370 Locations::LocationList::const_iterator tmp;
7372 if ((*i)->position_lock_style() == AudioTime || glued_markers_too) {
7373 bool const was_locked = (*i)->locked ();
7374 if (locked_markers_too) {
7378 if ((*i)->start() >= pos) {
7379 // move end first, in case we're moving by more than the length of the range
7380 if (!(*i)->is_mark()) {
7381 (*i)->set_end ((*i)->end() + frames);
7383 (*i)->set_start ((*i)->start() + frames);
7395 begin_reversible_command (_("insert time"));
7398 XMLNode& after (_session->locations()->get_state());
7399 _session->add_command (new MementoCommand<Locations>(*_session->locations(), &before, &after));
7405 begin_reversible_command (_("insert time"));
7408 XMLNode& before (_session->tempo_map().get_state());
7409 _session->tempo_map().insert_time (pos, frames);
7410 XMLNode& after (_session->tempo_map().get_state());
7411 _session->add_command (new MementoCommand<TempoMap>(_session->tempo_map(), &before, &after));
7415 commit_reversible_command ();
7420 Editor::do_remove_time ()
7422 if (selection->tracks.empty()) {
7426 framepos_t pos = get_preferred_edit_position (EDIT_IGNORE_MOUSE);
7427 InsertRemoveTimeDialog d (*this, true);
7429 int response = d.run ();
7431 if (response != RESPONSE_OK) {
7435 framecnt_t distance = d.distance();
7437 if (distance == 0) {
7447 d.move_glued_markers(),
7448 d.move_locked_markers(),
7454 Editor::remove_time (framepos_t pos, framecnt_t frames, InsertTimeOption opt,
7455 bool ignore_music_glue, bool markers_too, bool glued_markers_too, bool locked_markers_too, bool tempo_too)
7457 if (Config->get_edit_mode() == Lock) {
7458 error << (_("Cannot insert or delete time when in Lock edit.")) << endmsg;
7461 bool in_command = false;
7463 for (TrackSelection::iterator x = selection->tracks.begin(); x != selection->tracks.end(); ++x) {
7465 boost::shared_ptr<Playlist> pl = (*x)->playlist();
7469 XMLNode &before = pl->get_state();
7471 std::list<AudioRange> rl;
7472 AudioRange ar(pos, pos+frames, 0);
7475 pl->shift (pos, -frames, true, ignore_music_glue);
7478 begin_reversible_command (_("remove time"));
7481 XMLNode &after = pl->get_state();
7483 _session->add_command (new MementoCommand<Playlist> (*pl, &before, &after));
7487 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*x);
7490 begin_reversible_command (_("remove time"));
7493 rtav->route ()->shift (pos, -frames);
7497 std::list<Location*> loc_kill_list;
7502 XMLNode& before (_session->locations()->get_state());
7503 Locations::LocationList copy (_session->locations()->list());
7505 for (Locations::LocationList::iterator i = copy.begin(); i != copy.end(); ++i) {
7506 if ((*i)->position_lock_style() == AudioTime || glued_markers_too) {
7508 bool const was_locked = (*i)->locked ();
7509 if (locked_markers_too) {
7513 if (!(*i)->is_mark()) { // it's a range; have to handle both start and end
7514 if ((*i)->end() >= pos
7515 && (*i)->end() < pos+frames
7516 && (*i)->start() >= pos
7517 && (*i)->end() < pos+frames) { // range is completely enclosed; kill it
7519 loc_kill_list.push_back(*i);
7520 } else { // only start or end is included, try to do the right thing
7521 // move start before moving end, to avoid trying to move the end to before the start
7522 // if we're removing more time than the length of the range
7523 if ((*i)->start() >= pos && (*i)->start() < pos+frames) {
7524 // start is within cut
7525 (*i)->set_start (pos); // bring the start marker to the beginning of the cut
7527 } else if ((*i)->start() >= pos+frames) {
7528 // start (and thus entire range) lies beyond end of cut
7529 (*i)->set_start ((*i)->start() - frames); // slip the start marker back
7532 if ((*i)->end() >= pos && (*i)->end() < pos+frames) {
7533 // end is inside cut
7534 (*i)->set_end (pos); // bring the end to the cut
7536 } else if ((*i)->end() >= pos+frames) {
7537 // end is beyond end of cut
7538 (*i)->set_end ((*i)->end() - frames); // slip the end marker back
7543 } else if ((*i)->start() >= pos && (*i)->start() < pos+frames ) {
7544 loc_kill_list.push_back(*i);
7546 } else if ((*i)->start() >= pos) {
7547 (*i)->set_start ((*i)->start() -frames);
7557 for (list<Location*>::iterator i = loc_kill_list.begin(); i != loc_kill_list.end(); ++i) {
7558 _session->locations()->remove( *i );
7563 begin_reversible_command (_("remove time"));
7566 XMLNode& after (_session->locations()->get_state());
7567 _session->add_command (new MementoCommand<Locations>(*_session->locations(), &before, &after));
7572 XMLNode& before (_session->tempo_map().get_state());
7574 if (_session->tempo_map().remove_time (pos, frames) ) {
7576 begin_reversible_command (_("remove time"));
7579 XMLNode& after (_session->tempo_map().get_state());
7580 _session->add_command (new MementoCommand<TempoMap>(_session->tempo_map(), &before, &after));
7585 commit_reversible_command ();
7590 Editor::fit_selection ()
7592 if (!selection->tracks.empty()) {
7593 fit_tracks (selection->tracks);
7597 /* no selected tracks - use tracks with selected regions */
7599 if (!selection->regions.empty()) {
7600 for (RegionSelection::iterator r = selection->regions.begin(); r != selection->regions.end(); ++r) {
7601 tvl.push_back (&(*r)->get_time_axis_view ());
7607 } else if (internal_editing()) {
7608 /* no selected tracks, or regions, but in internal edit mode, so follow the mouse and use
7611 if (entered_track) {
7612 tvl.push_back (entered_track);
7621 Editor::fit_tracks (TrackViewList & tracks)
7623 if (tracks.empty()) {
7627 uint32_t child_heights = 0;
7628 int visible_tracks = 0;
7630 for (TrackSelection::iterator t = tracks.begin(); t != tracks.end(); ++t) {
7632 if (!(*t)->marked_for_display()) {
7636 child_heights += (*t)->effective_height() - (*t)->current_height();
7640 /* compute the per-track height from:
7642 total canvas visible height -
7643 height that will be taken by visible children of selected
7644 tracks - height of the ruler/hscroll area
7646 uint32_t h = (uint32_t) floor ((trackviews_height() - child_heights) / visible_tracks);
7647 double first_y_pos = DBL_MAX;
7649 if (h < TimeAxisView::preset_height (HeightSmall)) {
7650 MessageDialog msg (_("There are too many tracks to fit in the current window"));
7651 /* too small to be displayed */
7655 undo_visual_stack.push_back (current_visual_state (true));
7656 PBD::Unwinder<bool> nsv (no_save_visual, true);
7658 /* build a list of all tracks, including children */
7661 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
7663 TimeAxisView::Children c = (*i)->get_child_list ();
7664 for (TimeAxisView::Children::iterator j = c.begin(); j != c.end(); ++j) {
7665 all.push_back (j->get());
7670 // find selection range.
7671 // if someone knows how to user TrackViewList::iterator for this
7673 int selected_top = -1;
7674 int selected_bottom = -1;
7676 for (TrackViewList::iterator t = all.begin(); t != all.end(); ++t, ++i) {
7677 if ((*t)->marked_for_display ()) {
7678 if (tracks.contains(*t)) {
7679 if (selected_top == -1) {
7682 selected_bottom = i;
7688 for (TrackViewList::iterator t = all.begin(); t != all.end(); ++t, ++i) {
7689 if ((*t)->marked_for_display ()) {
7690 if (tracks.contains(*t)) {
7691 (*t)->set_height (h);
7692 first_y_pos = std::min ((*t)->y_position (), first_y_pos);
7694 if (i > selected_top && i < selected_bottom) {
7695 hide_track_in_display (*t);
7702 set the controls_layout height now, because waiting for its size
7703 request signal handler will cause the vertical adjustment setting to fail
7706 controls_layout.property_height () = _full_canvas_height;
7707 vertical_adjustment.set_value (first_y_pos);
7709 redo_visual_stack.push_back (current_visual_state (true));
7711 visible_tracks_selector.set_text (_("Sel"));
7715 Editor::save_visual_state (uint32_t n)
7717 while (visual_states.size() <= n) {
7718 visual_states.push_back (0);
7721 if (visual_states[n] != 0) {
7722 delete visual_states[n];
7725 visual_states[n] = current_visual_state (true);
7730 Editor::goto_visual_state (uint32_t n)
7732 if (visual_states.size() <= n) {
7736 if (visual_states[n] == 0) {
7740 use_visual_state (*visual_states[n]);
7744 Editor::start_visual_state_op (uint32_t n)
7746 save_visual_state (n);
7748 PopUp* pup = new PopUp (WIN_POS_MOUSE, 1000, true);
7750 snprintf (buf, sizeof (buf), _("Saved view %u"), n+1);
7751 pup->set_text (buf);
7756 Editor::cancel_visual_state_op (uint32_t n)
7758 goto_visual_state (n);
7762 Editor::toggle_region_mute ()
7764 if (_ignore_region_action) {
7768 RegionSelection rs = get_regions_from_selection_and_entered ();
7774 if (rs.size() > 1) {
7775 begin_reversible_command (_("mute regions"));
7777 begin_reversible_command (_("mute region"));
7780 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
7782 (*i)->region()->playlist()->clear_changes ();
7783 (*i)->region()->set_muted (!(*i)->region()->muted ());
7784 _session->add_command (new StatefulDiffCommand ((*i)->region()));
7788 commit_reversible_command ();
7792 Editor::combine_regions ()
7794 /* foreach track with selected regions, take all selected regions
7795 and join them into a new region containing the subregions (as a
7799 typedef set<RouteTimeAxisView*> RTVS;
7802 if (selection->regions.empty()) {
7806 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
7807 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(&(*i)->get_time_axis_view());
7810 tracks.insert (rtv);
7814 begin_reversible_command (_("combine regions"));
7816 vector<RegionView*> new_selection;
7818 for (RTVS::iterator i = tracks.begin(); i != tracks.end(); ++i) {
7821 if ((rv = (*i)->combine_regions ()) != 0) {
7822 new_selection.push_back (rv);
7826 selection->clear_regions ();
7827 for (vector<RegionView*>::iterator i = new_selection.begin(); i != new_selection.end(); ++i) {
7828 selection->add (*i);
7831 commit_reversible_command ();
7835 Editor::uncombine_regions ()
7837 typedef set<RouteTimeAxisView*> RTVS;
7840 if (selection->regions.empty()) {
7844 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
7845 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(&(*i)->get_time_axis_view());
7848 tracks.insert (rtv);
7852 begin_reversible_command (_("uncombine regions"));
7854 for (RTVS::iterator i = tracks.begin(); i != tracks.end(); ++i) {
7855 (*i)->uncombine_regions ();
7858 commit_reversible_command ();
7862 Editor::toggle_midi_input_active (bool flip_others)
7865 boost::shared_ptr<RouteList> rl (new RouteList);
7867 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
7868 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
7874 boost::shared_ptr<MidiTrack> mt = rtav->midi_track();
7877 rl->push_back (rtav->route());
7878 onoff = !mt->input_active();
7882 _session->set_exclusive_input_active (rl, onoff, flip_others);
7889 lock_dialog = new Gtk::Dialog (string_compose (_("%1: Locked"), PROGRAM_NAME), true);
7891 Gtk::Image* padlock = manage (new Gtk::Image (ARDOUR_UI_UTILS::get_icon ("padlock_closed")));
7892 lock_dialog->get_vbox()->pack_start (*padlock);
7894 ArdourButton* b = manage (new ArdourButton);
7895 b->set_name ("lock button");
7896 b->set_text (_("Click to unlock"));
7897 b->signal_clicked.connect (sigc::mem_fun (*this, &Editor::unlock));
7898 lock_dialog->get_vbox()->pack_start (*b);
7900 lock_dialog->get_vbox()->show_all ();
7901 lock_dialog->set_size_request (200, 200);
7904 delete _main_menu_disabler;
7905 _main_menu_disabler = new MainMenuDisabler;
7907 lock_dialog->present ();
7913 lock_dialog->hide ();
7915 delete _main_menu_disabler;
7916 _main_menu_disabler = 0;
7918 if (UIConfiguration::instance().get_lock_gui_after_seconds()) {
7919 start_lock_event_timing ();
7924 Editor::bring_in_callback (Gtk::Label* label, uint32_t n, uint32_t total, string name)
7926 Gtkmm2ext::UI::instance()->call_slot (invalidator (*this), boost::bind (&Editor::update_bring_in_message, this, label, n, total, name));
7930 Editor::update_bring_in_message (Gtk::Label* label, uint32_t n, uint32_t total, string name)
7932 Timers::TimerSuspender t;
7933 label->set_text (string_compose ("Copying %1, %2 of %3", name, n, total));
7934 Gtkmm2ext::UI::instance()->flush_pending (1);
7938 Editor::bring_all_sources_into_session ()
7945 ArdourDialog w (_("Moving embedded files into session folder"));
7946 w.get_vbox()->pack_start (msg);
7949 /* flush all pending GUI events because we're about to start copying
7953 Timers::TimerSuspender t;
7954 Gtkmm2ext::UI::instance()->flush_pending (3);
7958 _session->bring_all_sources_into_session (boost::bind (&Editor::bring_in_callback, this, &msg, _1, _2, _3));