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);
2248 Editor::toggle_location_at_playhead_cursor ()
2250 if (!do_remove_location_at_playhead_cursor())
2252 add_location_from_playhead_cursor();
2257 Editor::add_location_from_playhead_cursor ()
2259 add_location_mark (_session->audible_frame());
2263 Editor::do_remove_location_at_playhead_cursor ()
2265 bool removed = false;
2268 XMLNode &before = _session->locations()->get_state();
2270 //find location(s) at this time
2271 Locations::LocationList locs;
2272 _session->locations()->find_all_between (_session->audible_frame(), _session->audible_frame()+1, locs, Location::Flags(0));
2273 for (Locations::LocationList::iterator i = locs.begin(); i != locs.end(); ++i) {
2274 if ((*i)->is_mark()) {
2275 _session->locations()->remove (*i);
2282 begin_reversible_command (_("remove marker"));
2283 XMLNode &after = _session->locations()->get_state();
2284 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2285 commit_reversible_command ();
2292 Editor::remove_location_at_playhead_cursor ()
2294 do_remove_location_at_playhead_cursor ();
2297 /** Add a range marker around each selected region */
2299 Editor::add_locations_from_region ()
2301 RegionSelection rs = get_regions_from_selection_and_entered ();
2306 bool commit = false;
2308 XMLNode &before = _session->locations()->get_state();
2310 for (RegionSelection::iterator i = rs.begin (); i != rs.end (); ++i) {
2312 boost::shared_ptr<Region> region = (*i)->region ();
2314 Location *location = new Location (*_session, region->position(), region->last_frame(), region->name(), Location::IsRangeMarker);
2316 _session->locations()->add (location, true);
2321 begin_reversible_command (selection->regions.size () > 1 ? _("add markers") : _("add marker"));
2322 XMLNode &after = _session->locations()->get_state();
2323 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2324 commit_reversible_command ();
2328 /** Add a single range marker around all selected regions */
2330 Editor::add_location_from_region ()
2332 RegionSelection rs = get_regions_from_selection_and_entered ();
2338 XMLNode &before = _session->locations()->get_state();
2342 if (rs.size() > 1) {
2343 _session->locations()->next_available_name(markername, "regions");
2345 RegionView* rv = *(rs.begin());
2346 boost::shared_ptr<Region> region = rv->region();
2347 markername = region->name();
2350 if (!choose_new_marker_name(markername)) {
2354 // single range spanning all selected
2355 Location *location = new Location (*_session, selection->regions.start(), selection->regions.end_frame(), markername, Location::IsRangeMarker);
2356 _session->locations()->add (location, true);
2358 begin_reversible_command (_("add marker"));
2359 XMLNode &after = _session->locations()->get_state();
2360 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2361 commit_reversible_command ();
2367 Editor::jump_forward_to_mark ()
2373 framepos_t pos = _session->locations()->first_mark_after (playhead_cursor->current_frame());
2379 _session->request_locate (pos, _session->transport_rolling());
2383 Editor::jump_backward_to_mark ()
2389 framepos_t pos = _session->locations()->first_mark_before (playhead_cursor->current_frame());
2395 _session->request_locate (pos, _session->transport_rolling());
2401 framepos_t const pos = _session->audible_frame ();
2404 _session->locations()->next_available_name (markername, "mark");
2406 if (!choose_new_marker_name (markername)) {
2410 _session->locations()->add (new Location (*_session, pos, 0, markername, Location::IsMark), true);
2414 Editor::clear_markers ()
2417 begin_reversible_command (_("clear markers"));
2419 XMLNode &before = _session->locations()->get_state();
2420 _session->locations()->clear_markers ();
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_ranges ()
2432 begin_reversible_command (_("clear ranges"));
2434 XMLNode &before = _session->locations()->get_state();
2436 _session->locations()->clear_ranges ();
2438 XMLNode &after = _session->locations()->get_state();
2439 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2441 commit_reversible_command ();
2446 Editor::clear_locations ()
2448 begin_reversible_command (_("clear locations"));
2450 XMLNode &before = _session->locations()->get_state();
2451 _session->locations()->clear ();
2452 XMLNode &after = _session->locations()->get_state();
2453 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2455 commit_reversible_command ();
2459 Editor::unhide_markers ()
2461 for (LocationMarkerMap::iterator i = location_markers.begin(); i != location_markers.end(); ++i) {
2462 Location *l = (*i).first;
2463 if (l->is_hidden() && l->is_mark()) {
2464 l->set_hidden(false, this);
2470 Editor::unhide_ranges ()
2472 for (LocationMarkerMap::iterator i = location_markers.begin(); i != location_markers.end(); ++i) {
2473 Location *l = (*i).first;
2474 if (l->is_hidden() && l->is_range_marker()) {
2475 l->set_hidden(false, this);
2480 /* INSERT/REPLACE */
2483 Editor::insert_region_list_selection (float times)
2485 RouteTimeAxisView *tv = 0;
2486 boost::shared_ptr<Playlist> playlist;
2488 if (clicked_routeview != 0) {
2489 tv = clicked_routeview;
2490 } else if (!selection->tracks.empty()) {
2491 if ((tv = dynamic_cast<RouteTimeAxisView*>(selection->tracks.front())) == 0) {
2494 } else if (entered_track != 0) {
2495 if ((tv = dynamic_cast<RouteTimeAxisView*>(entered_track)) == 0) {
2502 if ((playlist = tv->playlist()) == 0) {
2506 boost::shared_ptr<Region> region = _regions->get_single_selection ();
2511 begin_reversible_command (_("insert region"));
2512 playlist->clear_changes ();
2513 playlist->add_region ((RegionFactory::create (region, true)), get_preferred_edit_position(), times);
2514 if (Config->get_edit_mode() == Ripple)
2515 playlist->ripple (get_preferred_edit_position(), region->length() * times, boost::shared_ptr<Region>());
2517 _session->add_command(new StatefulDiffCommand (playlist));
2518 commit_reversible_command ();
2521 /* BUILT-IN EFFECTS */
2524 Editor::reverse_selection ()
2529 /* GAIN ENVELOPE EDITING */
2532 Editor::edit_envelope ()
2539 Editor::transition_to_rolling (bool fwd)
2545 if (_session->config.get_external_sync()) {
2546 switch (Config->get_sync_source()) {
2550 /* transport controlled by the master */
2555 if (_session->is_auditioning()) {
2556 _session->cancel_audition ();
2560 _session->request_transport_speed (fwd ? 1.0f : -1.0f);
2564 Editor::play_from_start ()
2566 _session->request_locate (_session->current_start_frame(), true);
2570 Editor::play_from_edit_point ()
2572 _session->request_locate (get_preferred_edit_position(), true);
2576 Editor::play_from_edit_point_and_return ()
2578 framepos_t start_frame;
2579 framepos_t return_frame;
2581 start_frame = get_preferred_edit_position ( EDIT_IGNORE_PHEAD );
2583 if (_session->transport_rolling()) {
2584 _session->request_locate (start_frame, false);
2588 /* don't reset the return frame if its already set */
2590 if ((return_frame = _session->requested_return_frame()) < 0) {
2591 return_frame = _session->audible_frame();
2594 if (start_frame >= 0) {
2595 _session->request_roll_at_and_return (start_frame, return_frame);
2600 Editor::play_selection ()
2602 framepos_t start, end;
2603 if (!get_selection_extents ( start, end))
2606 AudioRange ar (start, end, 0);
2607 list<AudioRange> lar;
2610 _session->request_play_range (&lar, true);
2614 Editor::get_preroll ()
2616 return Config->get_preroll_seconds() * _session->frame_rate();
2621 Editor::maybe_locate_with_edit_preroll ( framepos_t location )
2623 if ( _session->transport_rolling() || !UIConfiguration::instance().get_follow_edits() || _ignore_follow_edits || _session->config.get_external_sync() )
2626 location -= get_preroll();
2628 //don't try to locate before the beginning of time
2632 //if follow_playhead is on, keep the playhead on the screen
2633 if ( _follow_playhead )
2634 if ( location < leftmost_frame )
2635 location = leftmost_frame;
2637 _session->request_locate( location );
2641 Editor::play_with_preroll ()
2644 framepos_t preroll = get_preroll();
2646 framepos_t start, end;
2647 if (!get_selection_extents ( start, end))
2650 if (start > preroll)
2651 start = start - preroll;
2653 end = end + preroll; //"post-roll"
2655 AudioRange ar (start, end, 0);
2656 list<AudioRange> lar;
2659 _session->request_play_range (&lar, true);
2664 Editor::play_location (Location& location)
2666 if (location.start() <= location.end()) {
2670 _session->request_bounded_roll (location.start(), location.end());
2674 Editor::loop_location (Location& location)
2676 if (location.start() <= location.end()) {
2682 if ((tll = transport_loop_location()) != 0) {
2683 tll->set (location.start(), location.end());
2685 // enable looping, reposition and start rolling
2686 _session->request_locate (tll->start(), true);
2687 _session->request_play_loop (true);
2692 Editor::do_layer_operation (LayerOperation op)
2694 if (selection->regions.empty ()) {
2698 bool const multiple = selection->regions.size() > 1;
2702 begin_reversible_command (_("raise regions"));
2704 begin_reversible_command (_("raise region"));
2710 begin_reversible_command (_("raise regions to top"));
2712 begin_reversible_command (_("raise region to top"));
2718 begin_reversible_command (_("lower regions"));
2720 begin_reversible_command (_("lower region"));
2726 begin_reversible_command (_("lower regions to bottom"));
2728 begin_reversible_command (_("lower region"));
2733 set<boost::shared_ptr<Playlist> > playlists = selection->regions.playlists ();
2734 for (set<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
2735 (*i)->clear_owned_changes ();
2738 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
2739 boost::shared_ptr<Region> r = (*i)->region ();
2751 r->lower_to_bottom ();
2755 for (set<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
2756 vector<Command*> cmds;
2758 _session->add_commands (cmds);
2761 commit_reversible_command ();
2765 Editor::raise_region ()
2767 do_layer_operation (Raise);
2771 Editor::raise_region_to_top ()
2773 do_layer_operation (RaiseToTop);
2777 Editor::lower_region ()
2779 do_layer_operation (Lower);
2783 Editor::lower_region_to_bottom ()
2785 do_layer_operation (LowerToBottom);
2788 /** Show the region editor for the selected regions */
2790 Editor::show_region_properties ()
2792 selection->foreach_regionview (&RegionView::show_region_editor);
2795 /** Show the midi list editor for the selected MIDI regions */
2797 Editor::show_midi_list_editor ()
2799 selection->foreach_midi_regionview (&MidiRegionView::show_list_editor);
2803 Editor::rename_region ()
2805 RegionSelection rs = get_regions_from_selection_and_entered ();
2811 ArdourDialog d (_("Rename Region"), true, false);
2813 Label label (_("New name:"));
2816 hbox.set_spacing (6);
2817 hbox.pack_start (label, false, false);
2818 hbox.pack_start (entry, true, true);
2820 d.get_vbox()->set_border_width (12);
2821 d.get_vbox()->pack_start (hbox, false, false);
2823 d.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
2824 d.add_button(Gtk::Stock::OK, Gtk::RESPONSE_OK);
2826 d.set_size_request (300, -1);
2828 entry.set_text (rs.front()->region()->name());
2829 entry.select_region (0, -1);
2831 entry.signal_activate().connect (sigc::bind (sigc::mem_fun (d, &Dialog::response), RESPONSE_OK));
2837 int const ret = d.run();
2841 if (ret != RESPONSE_OK) {
2845 std::string str = entry.get_text();
2846 strip_whitespace_edges (str);
2848 rs.front()->region()->set_name (str);
2849 _regions->redisplay ();
2853 /** Start an audition of the first selected region */
2855 Editor::play_edit_range ()
2857 framepos_t start, end;
2859 if (get_edit_op_range (start, end)) {
2860 _session->request_bounded_roll (start, end);
2865 Editor::play_selected_region ()
2867 framepos_t start = max_framepos;
2870 RegionSelection rs = get_regions_from_selection_and_entered ();
2876 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
2877 if ((*i)->region()->position() < start) {
2878 start = (*i)->region()->position();
2880 if ((*i)->region()->last_frame() + 1 > end) {
2881 end = (*i)->region()->last_frame() + 1;
2885 _session->request_bounded_roll (start, end);
2889 Editor::audition_playlist_region_standalone (boost::shared_ptr<Region> region)
2891 _session->audition_region (region);
2895 Editor::region_from_selection ()
2897 if (clicked_axisview == 0) {
2901 if (selection->time.empty()) {
2905 framepos_t start = selection->time[clicked_selection].start;
2906 framepos_t end = selection->time[clicked_selection].end;
2908 TrackViewList tracks = get_tracks_for_range_action ();
2910 framepos_t selection_cnt = end - start + 1;
2912 for (TrackSelection::iterator i = tracks.begin(); i != tracks.end(); ++i) {
2913 boost::shared_ptr<Region> current;
2914 boost::shared_ptr<Playlist> pl;
2915 framepos_t internal_start;
2918 if ((pl = (*i)->playlist()) == 0) {
2922 if ((current = pl->top_region_at (start)) == 0) {
2926 internal_start = start - current->position();
2927 RegionFactory::region_name (new_name, current->name(), true);
2931 plist.add (ARDOUR::Properties::start, current->start() + internal_start);
2932 plist.add (ARDOUR::Properties::length, selection_cnt);
2933 plist.add (ARDOUR::Properties::name, new_name);
2934 plist.add (ARDOUR::Properties::layer, 0);
2936 boost::shared_ptr<Region> region (RegionFactory::create (current, plist));
2941 Editor::create_region_from_selection (vector<boost::shared_ptr<Region> >& new_regions)
2943 if (selection->time.empty() || selection->tracks.empty()) {
2947 framepos_t start, end;
2948 if (clicked_selection) {
2949 start = selection->time[clicked_selection].start;
2950 end = selection->time[clicked_selection].end;
2952 start = selection->time.start();
2953 end = selection->time.end_frame();
2956 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
2957 sort_track_selection (ts);
2959 for (TrackSelection::iterator i = ts.begin(); i != ts.end(); ++i) {
2960 boost::shared_ptr<Region> current;
2961 boost::shared_ptr<Playlist> playlist;
2962 framepos_t internal_start;
2965 if ((playlist = (*i)->playlist()) == 0) {
2969 if ((current = playlist->top_region_at(start)) == 0) {
2973 internal_start = start - current->position();
2974 RegionFactory::region_name (new_name, current->name(), true);
2978 plist.add (ARDOUR::Properties::start, current->start() + internal_start);
2979 plist.add (ARDOUR::Properties::length, end - start + 1);
2980 plist.add (ARDOUR::Properties::name, new_name);
2982 new_regions.push_back (RegionFactory::create (current, plist));
2987 Editor::split_multichannel_region ()
2989 RegionSelection rs = get_regions_from_selection_and_entered ();
2995 vector< boost::shared_ptr<Region> > v;
2997 for (list<RegionView*>::iterator x = rs.begin(); x != rs.end(); ++x) {
2998 (*x)->region()->separate_by_channel (*_session, v);
3003 Editor::new_region_from_selection ()
3005 region_from_selection ();
3006 cancel_selection ();
3010 add_if_covered (RegionView* rv, const AudioRange* ar, RegionSelection* rs)
3012 switch (rv->region()->coverage (ar->start, ar->end - 1)) {
3013 // n.b. -1 because AudioRange::end is one past the end, but coverage expects inclusive ranges
3014 case Evoral::OverlapNone:
3022 * - selected tracks, or if there are none...
3023 * - tracks containing selected regions, or if there are none...
3028 Editor::get_tracks_for_range_action () const
3032 if (selection->tracks.empty()) {
3034 /* use tracks with selected regions */
3036 RegionSelection rs = selection->regions;
3038 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3039 TimeAxisView* tv = &(*i)->get_time_axis_view();
3041 if (!t.contains (tv)) {
3047 /* no regions and no tracks: use all tracks */
3053 t = selection->tracks;
3056 return t.filter_to_unique_playlists();
3060 Editor::separate_regions_between (const TimeSelection& ts)
3062 bool in_command = false;
3063 boost::shared_ptr<Playlist> playlist;
3064 RegionSelection new_selection;
3066 TrackViewList tmptracks = get_tracks_for_range_action ();
3067 sort_track_selection (tmptracks);
3069 for (TrackSelection::iterator i = tmptracks.begin(); i != tmptracks.end(); ++i) {
3071 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> ((*i));
3077 if (!rtv->is_track()) {
3081 /* no edits to destructive tracks */
3083 if (rtv->track()->destructive()) {
3087 if ((playlist = rtv->playlist()) != 0) {
3089 playlist->clear_changes ();
3091 /* XXX need to consider musical time selections here at some point */
3093 double speed = rtv->track()->speed();
3095 for (list<AudioRange>::const_iterator t = ts.begin(); t != ts.end(); ++t) {
3097 sigc::connection c = rtv->view()->RegionViewAdded.connect (
3098 sigc::mem_fun(*this, &Editor::collect_new_region_view));
3100 latest_regionviews.clear ();
3102 playlist->partition ((framepos_t)((*t).start * speed),
3103 (framepos_t)((*t).end * speed), false);
3107 if (!latest_regionviews.empty()) {
3109 rtv->view()->foreach_regionview (sigc::bind (
3110 sigc::ptr_fun (add_if_covered),
3111 &(*t), &new_selection));
3114 begin_reversible_command (_("separate"));
3118 /* pick up changes to existing regions */
3120 vector<Command*> cmds;
3121 playlist->rdiff (cmds);
3122 _session->add_commands (cmds);
3124 /* pick up changes to the playlist itself (adds/removes)
3127 _session->add_command(new StatefulDiffCommand (playlist));
3134 // selection->set (new_selection);
3136 commit_reversible_command ();
3140 struct PlaylistState {
3141 boost::shared_ptr<Playlist> playlist;
3145 /** Take tracks from get_tracks_for_range_action and cut any regions
3146 * on those tracks so that the tracks are empty over the time
3150 Editor::separate_region_from_selection ()
3152 /* preferentially use *all* ranges in the time selection if we're in range mode
3153 to allow discontiguous operation, since get_edit_op_range() currently
3154 returns a single range.
3157 if (!selection->time.empty()) {
3159 separate_regions_between (selection->time);
3166 if (get_edit_op_range (start, end)) {
3168 AudioRange ar (start, end, 1);
3172 separate_regions_between (ts);
3178 Editor::separate_region_from_punch ()
3180 Location* loc = _session->locations()->auto_punch_location();
3182 separate_regions_using_location (*loc);
3187 Editor::separate_region_from_loop ()
3189 Location* loc = _session->locations()->auto_loop_location();
3191 separate_regions_using_location (*loc);
3196 Editor::separate_regions_using_location (Location& loc)
3198 if (loc.is_mark()) {
3202 AudioRange ar (loc.start(), loc.end(), 1);
3207 separate_regions_between (ts);
3210 /** Separate regions under the selected region */
3212 Editor::separate_under_selected_regions ()
3214 vector<PlaylistState> playlists;
3218 rs = get_regions_from_selection_and_entered();
3220 if (!_session || rs.empty()) {
3224 begin_reversible_command (_("separate region under"));
3226 list<boost::shared_ptr<Region> > regions_to_remove;
3228 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3229 // we can't just remove the region(s) in this loop because
3230 // this removes them from the RegionSelection, and they thus
3231 // disappear from underneath the iterator, and the ++i above
3232 // SEGVs in a puzzling fashion.
3234 // so, first iterate over the regions to be removed from rs and
3235 // add them to the regions_to_remove list, and then
3236 // iterate over the list to actually remove them.
3238 regions_to_remove.push_back ((*i)->region());
3241 for (list<boost::shared_ptr<Region> >::iterator rl = regions_to_remove.begin(); rl != regions_to_remove.end(); ++rl) {
3243 boost::shared_ptr<Playlist> playlist = (*rl)->playlist();
3246 // is this check necessary?
3250 vector<PlaylistState>::iterator i;
3252 //only take state if this is a new playlist.
3253 for (i = playlists.begin(); i != playlists.end(); ++i) {
3254 if ((*i).playlist == playlist) {
3259 if (i == playlists.end()) {
3261 PlaylistState before;
3262 before.playlist = playlist;
3263 before.before = &playlist->get_state();
3265 playlist->freeze ();
3266 playlists.push_back(before);
3269 //Partition on the region bounds
3270 playlist->partition ((*rl)->first_frame() - 1, (*rl)->last_frame() + 1, true);
3272 //Re-add region that was just removed due to the partition operation
3273 playlist->add_region( (*rl), (*rl)->first_frame() );
3276 vector<PlaylistState>::iterator pl;
3278 for (pl = playlists.begin(); pl != playlists.end(); ++pl) {
3279 (*pl).playlist->thaw ();
3280 _session->add_command(new MementoCommand<Playlist>(*(*pl).playlist, (*pl).before, &(*pl).playlist->get_state()));
3283 commit_reversible_command ();
3287 Editor::crop_region_to_selection ()
3289 if (!selection->time.empty()) {
3291 crop_region_to (selection->time.start(), selection->time.end_frame());
3298 if (get_edit_op_range (start, end)) {
3299 crop_region_to (start, end);
3306 Editor::crop_region_to (framepos_t start, framepos_t end)
3308 vector<boost::shared_ptr<Playlist> > playlists;
3309 boost::shared_ptr<Playlist> playlist;
3312 if (selection->tracks.empty()) {
3313 ts = track_views.filter_to_unique_playlists();
3315 ts = selection->tracks.filter_to_unique_playlists ();
3318 sort_track_selection (ts);
3320 for (TrackSelection::iterator i = ts.begin(); i != ts.end(); ++i) {
3322 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> ((*i));
3328 boost::shared_ptr<Track> t = rtv->track();
3330 if (t != 0 && ! t->destructive()) {
3332 if ((playlist = rtv->playlist()) != 0) {
3333 playlists.push_back (playlist);
3338 if (playlists.empty()) {
3343 framepos_t new_start;
3345 framecnt_t new_length;
3346 bool in_command = false;
3348 for (vector<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
3350 /* Only the top regions at start and end have to be cropped */
3351 boost::shared_ptr<Region> region_at_start = (*i)->top_region_at(start);
3352 boost::shared_ptr<Region> region_at_end = (*i)->top_region_at(end);
3354 vector<boost::shared_ptr<Region> > regions;
3356 if (region_at_start != 0) {
3357 regions.push_back (region_at_start);
3359 if (region_at_end != 0) {
3360 regions.push_back (region_at_end);
3363 /* now adjust lengths */
3364 for (vector<boost::shared_ptr<Region> >::iterator i = regions.begin(); i != regions.end(); ++i) {
3366 pos = (*i)->position();
3367 new_start = max (start, pos);
3368 if (max_framepos - pos > (*i)->length()) {
3369 new_end = pos + (*i)->length() - 1;
3371 new_end = max_framepos;
3373 new_end = min (end, new_end);
3374 new_length = new_end - new_start + 1;
3377 begin_reversible_command (_("trim to selection"));
3380 (*i)->clear_changes ();
3381 (*i)->trim_to (new_start, new_length);
3382 _session->add_command (new StatefulDiffCommand (*i));
3387 commit_reversible_command ();
3392 Editor::region_fill_track ()
3394 boost::shared_ptr<Playlist> playlist;
3395 RegionSelection regions = get_regions_from_selection_and_entered ();
3396 RegionSelection foo;
3398 framepos_t const end = _session->current_end_frame ();
3400 if (regions.empty () || regions.end_frame () + 1 >= end) {
3404 framepos_t const start_frame = regions.start ();
3405 framepos_t const end_frame = regions.end_frame ();
3406 framecnt_t const gap = end_frame - start_frame + 1;
3408 begin_reversible_command (Operations::region_fill);
3410 selection->clear_regions ();
3412 for (RegionSelection::iterator i = regions.begin(); i != regions.end(); ++i) {
3414 boost::shared_ptr<Region> r ((*i)->region());
3416 TimeAxisView& tv = (*i)->get_time_axis_view();
3417 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (&tv);
3418 latest_regionviews.clear ();
3419 sigc::connection c = rtv->view()->RegionViewAdded.connect (sigc::mem_fun(*this, &Editor::collect_new_region_view));
3421 framepos_t const position = end_frame + (r->first_frame() - start_frame + 1);
3422 playlist = (*i)->region()->playlist();
3423 playlist->clear_changes ();
3424 playlist->duplicate_until (r, position, gap, end);
3425 _session->add_command(new StatefulDiffCommand (playlist));
3429 foo.insert (foo.end(), latest_regionviews.begin(), latest_regionviews.end());
3433 selection->set (foo);
3436 commit_reversible_command ();
3440 Editor::set_region_sync_position ()
3442 set_sync_point (get_preferred_edit_position (), get_regions_from_selection_and_edit_point ());
3446 Editor::set_sync_point (framepos_t where, const RegionSelection& rs)
3448 bool in_command = false;
3450 for (RegionSelection::const_iterator r = rs.begin(); r != rs.end(); ++r) {
3452 if (!(*r)->region()->covers (where)) {
3456 boost::shared_ptr<Region> region ((*r)->region());
3459 begin_reversible_command (_("set sync point"));
3463 region->clear_changes ();
3464 region->set_sync_position (where);
3465 _session->add_command(new StatefulDiffCommand (region));
3469 commit_reversible_command ();
3473 /** Remove the sync positions of the selection */
3475 Editor::remove_region_sync ()
3477 RegionSelection rs = get_regions_from_selection_and_entered ();
3483 begin_reversible_command (_("remove region sync"));
3485 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3487 (*i)->region()->clear_changes ();
3488 (*i)->region()->clear_sync_position ();
3489 _session->add_command(new StatefulDiffCommand ((*i)->region()));
3492 commit_reversible_command ();
3496 Editor::naturalize_region ()
3498 RegionSelection rs = get_regions_from_selection_and_entered ();
3504 if (rs.size() > 1) {
3505 begin_reversible_command (_("move regions to original position"));
3507 begin_reversible_command (_("move region to original position"));
3510 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3511 (*i)->region()->clear_changes ();
3512 (*i)->region()->move_to_natural_position ();
3513 _session->add_command (new StatefulDiffCommand ((*i)->region()));
3516 commit_reversible_command ();
3520 Editor::align_regions (RegionPoint what)
3522 RegionSelection const rs = get_regions_from_selection_and_edit_point ();
3528 begin_reversible_command (_("align selection"));
3530 framepos_t const position = get_preferred_edit_position ();
3532 for (RegionSelection::const_iterator i = rs.begin(); i != rs.end(); ++i) {
3533 align_region_internal ((*i)->region(), what, position);
3536 commit_reversible_command ();
3539 struct RegionSortByTime {
3540 bool operator() (const RegionView* a, const RegionView* b) {
3541 return a->region()->position() < b->region()->position();
3546 Editor::align_regions_relative (RegionPoint point)
3548 RegionSelection const rs = get_regions_from_selection_and_edit_point ();
3554 framepos_t const position = get_preferred_edit_position ();
3556 framepos_t distance = 0;
3560 list<RegionView*> sorted;
3561 rs.by_position (sorted);
3563 boost::shared_ptr<Region> r ((*sorted.begin())->region());
3568 if (position > r->position()) {
3569 distance = position - r->position();
3571 distance = r->position() - position;
3577 if (position > r->last_frame()) {
3578 distance = position - r->last_frame();
3579 pos = r->position() + distance;
3581 distance = r->last_frame() - position;
3582 pos = r->position() - distance;
3588 pos = r->adjust_to_sync (position);
3589 if (pos > r->position()) {
3590 distance = pos - r->position();
3592 distance = r->position() - pos;
3598 if (pos == r->position()) {
3602 begin_reversible_command (_("align selection (relative)"));
3604 /* move first one specially */
3606 r->clear_changes ();
3607 r->set_position (pos);
3608 _session->add_command(new StatefulDiffCommand (r));
3610 /* move rest by the same amount */
3614 for (list<RegionView*>::iterator i = sorted.begin(); i != sorted.end(); ++i) {
3616 boost::shared_ptr<Region> region ((*i)->region());
3618 region->clear_changes ();
3621 region->set_position (region->position() + distance);
3623 region->set_position (region->position() - distance);
3626 _session->add_command(new StatefulDiffCommand (region));
3630 commit_reversible_command ();
3634 Editor::align_region (boost::shared_ptr<Region> region, RegionPoint point, framepos_t position)
3636 begin_reversible_command (_("align region"));
3637 align_region_internal (region, point, position);
3638 commit_reversible_command ();
3642 Editor::align_region_internal (boost::shared_ptr<Region> region, RegionPoint point, framepos_t position)
3644 region->clear_changes ();
3648 region->set_position (region->adjust_to_sync (position));
3652 if (position > region->length()) {
3653 region->set_position (position - region->length());
3658 region->set_position (position);
3662 _session->add_command(new StatefulDiffCommand (region));
3666 Editor::trim_region_front ()
3672 Editor::trim_region_back ()
3674 trim_region (false);
3678 Editor::trim_region (bool front)
3680 framepos_t where = get_preferred_edit_position();
3681 RegionSelection rs = get_regions_from_selection_and_edit_point ();
3687 begin_reversible_command (front ? _("trim front") : _("trim back"));
3689 for (list<RegionView*>::const_iterator i = rs.by_layer().begin(); i != rs.by_layer().end(); ++i) {
3690 if (!(*i)->region()->locked()) {
3692 (*i)->region()->clear_changes ();
3695 (*i)->region()->trim_front (where);
3696 maybe_locate_with_edit_preroll ( where );
3698 (*i)->region()->trim_end (where);
3699 maybe_locate_with_edit_preroll ( where );
3702 _session->add_command (new StatefulDiffCommand ((*i)->region()));
3706 commit_reversible_command ();
3709 /** Trim the end of the selected regions to the position of the edit cursor */
3711 Editor::trim_region_to_loop ()
3713 Location* loc = _session->locations()->auto_loop_location();
3717 trim_region_to_location (*loc, _("trim to loop"));
3721 Editor::trim_region_to_punch ()
3723 Location* loc = _session->locations()->auto_punch_location();
3727 trim_region_to_location (*loc, _("trim to punch"));
3731 Editor::trim_region_to_location (const Location& loc, const char* str)
3733 RegionSelection rs = get_regions_from_selection_and_entered ();
3734 bool in_command = false;
3736 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
3737 RegionView* rv = (*x);
3739 /* require region to span proposed trim */
3740 switch (rv->region()->coverage (loc.start(), loc.end())) {
3741 case Evoral::OverlapInternal:
3747 RouteTimeAxisView* tav = dynamic_cast<RouteTimeAxisView*> (&rv->get_time_axis_view());
3756 if (tav->track() != 0) {
3757 speed = tav->track()->speed();
3760 start = session_frame_to_track_frame (loc.start(), speed);
3761 end = session_frame_to_track_frame (loc.end(), speed);
3763 rv->region()->clear_changes ();
3764 rv->region()->trim_to (start, (end - start));
3767 begin_reversible_command (str);
3770 _session->add_command(new StatefulDiffCommand (rv->region()));
3774 commit_reversible_command ();
3779 Editor::trim_region_to_previous_region_end ()
3781 return trim_to_region(false);
3785 Editor::trim_region_to_next_region_start ()
3787 return trim_to_region(true);
3791 Editor::trim_to_region(bool forward)
3793 RegionSelection rs = get_regions_from_selection_and_entered ();
3794 bool in_command = false;
3796 boost::shared_ptr<Region> next_region;
3798 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
3800 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*x);
3806 AudioTimeAxisView* atav = dynamic_cast<AudioTimeAxisView*> (&arv->get_time_axis_view());
3814 if (atav->track() != 0) {
3815 speed = atav->track()->speed();
3819 boost::shared_ptr<Region> region = arv->region();
3820 boost::shared_ptr<Playlist> playlist (region->playlist());
3822 region->clear_changes ();
3826 next_region = playlist->find_next_region (region->first_frame(), Start, 1);
3832 region->trim_end((framepos_t) ( (next_region->first_frame() - 1) * speed));
3833 arv->region_changed (PropertyChange (ARDOUR::Properties::length));
3837 next_region = playlist->find_next_region (region->first_frame(), Start, 0);
3843 region->trim_front((framepos_t) ((next_region->last_frame() + 1) * speed));
3845 arv->region_changed (ARDOUR::bounds_change);
3849 begin_reversible_command (_("trim to region"));
3852 _session->add_command(new StatefulDiffCommand (region));
3856 commit_reversible_command ();
3861 Editor::unfreeze_route ()
3863 if (clicked_routeview == 0 || !clicked_routeview->is_track()) {
3867 clicked_routeview->track()->unfreeze ();
3871 Editor::_freeze_thread (void* arg)
3873 return static_cast<Editor*>(arg)->freeze_thread ();
3877 Editor::freeze_thread ()
3879 /* create event pool because we may need to talk to the session */
3880 SessionEvent::create_per_thread_pool ("freeze events", 64);
3881 /* create per-thread buffers for process() tree to use */
3882 clicked_routeview->audio_track()->freeze_me (*current_interthread_info);
3883 current_interthread_info->done = true;
3888 Editor::freeze_route ()
3894 /* stop transport before we start. this is important */
3896 _session->request_transport_speed (0.0);
3898 /* wait for just a little while, because the above call is asynchronous */
3900 Glib::usleep (250000);
3902 if (clicked_routeview == 0 || !clicked_routeview->is_audio_track()) {
3906 if (!clicked_routeview->track()->bounceable (clicked_routeview->track()->main_outs(), true)) {
3908 _("This track/bus cannot be frozen because the signal adds or loses channels before reaching the outputs.\n"
3909 "This is typically caused by plugins that generate stereo output from mono input or vice versa.")
3911 d.set_title (_("Cannot freeze"));
3916 if (clicked_routeview->track()->has_external_redirects()) {
3917 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"
3918 "Freezing will only process the signal as far as the first send/insert/return."),
3919 clicked_routeview->track()->name()), true, MESSAGE_INFO, BUTTONS_NONE, true);
3921 d.add_button (_("Freeze anyway"), Gtk::RESPONSE_OK);
3922 d.add_button (_("Don't freeze"), Gtk::RESPONSE_CANCEL);
3923 d.set_title (_("Freeze Limits"));
3925 int response = d.run ();
3928 case Gtk::RESPONSE_CANCEL:
3935 InterThreadInfo itt;
3936 current_interthread_info = &itt;
3938 InterthreadProgressWindow ipw (current_interthread_info, _("Freeze"), _("Cancel Freeze"));
3940 pthread_create_and_store (X_("freezer"), &itt.thread, _freeze_thread, this);
3942 CursorContext::Handle cursor_ctx = CursorContext::create(*this, _cursors->wait);
3944 while (!itt.done && !itt.cancel) {
3945 gtk_main_iteration ();
3948 pthread_join (itt.thread, 0);
3949 current_interthread_info = 0;
3953 Editor::bounce_range_selection (bool replace, bool enable_processing)
3955 if (selection->time.empty()) {
3959 TrackSelection views = selection->tracks;
3961 for (TrackViewList::iterator i = views.begin(); i != views.end(); ++i) {
3963 if (enable_processing) {
3965 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*i);
3967 if (rtv && rtv->track() && replace && enable_processing && !rtv->track()->bounceable (rtv->track()->main_outs(), false)) {
3969 _("You can't perform this operation because the processing of the signal "
3970 "will cause one or more of the tracks to end up with a region with more channels than this track has inputs.\n\n"
3971 "You can do this without processing, which is a different operation.")
3973 d.set_title (_("Cannot bounce"));
3980 framepos_t start = selection->time[clicked_selection].start;
3981 framepos_t end = selection->time[clicked_selection].end;
3982 framepos_t cnt = end - start + 1;
3983 bool in_command = false;
3985 for (TrackViewList::iterator i = views.begin(); i != views.end(); ++i) {
3987 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*i);
3993 boost::shared_ptr<Playlist> playlist;
3995 if ((playlist = rtv->playlist()) == 0) {
3999 InterThreadInfo itt;
4001 playlist->clear_changes ();
4002 playlist->clear_owned_changes ();
4004 boost::shared_ptr<Region> r;
4006 if (enable_processing) {
4007 r = rtv->track()->bounce_range (start, start+cnt, itt, rtv->track()->main_outs(), false);
4009 r = rtv->track()->bounce_range (start, start+cnt, itt, boost::shared_ptr<Processor>(), false);
4017 list<AudioRange> ranges;
4018 ranges.push_back (AudioRange (start, start+cnt, 0));
4019 playlist->cut (ranges); // discard result
4020 playlist->add_region (r, start);
4024 begin_reversible_command (_("bounce range"));
4027 vector<Command*> cmds;
4028 playlist->rdiff (cmds);
4029 _session->add_commands (cmds);
4031 _session->add_command (new StatefulDiffCommand (playlist));
4035 commit_reversible_command ();
4039 /** Delete selected regions, automation points or a time range */
4043 //special case: if the user is pointing in the editor/mixer strip, they may be trying to delete a plugin.
4044 //we need this because the editor-mixer strip is in the editor window, so it doesn't get the bindings from the mix window
4045 bool deleted = false;
4046 if ( current_mixer_strip && current_mixer_strip == MixerStrip::entered_mixer_strip() )
4047 deleted = current_mixer_strip->delete_processors ();
4053 /** Cut selected regions, automation points or a time range */
4060 /** Copy selected regions, automation points or a time range */
4068 /** @return true if a Cut, Copy or Clear is possible */
4070 Editor::can_cut_copy () const
4072 if (!selection->time.empty() || !selection->regions.empty() || !selection->points.empty())
4079 /** Cut, copy or clear selected regions, automation points or a time range.
4080 * @param op Operation (Delete, Cut, Copy or Clear)
4083 Editor::cut_copy (CutCopyOp op)
4085 /* only cancel selection if cut/copy is successful.*/
4091 opname = _("delete");
4100 opname = _("clear");
4104 /* if we're deleting something, and the mouse is still pressed,
4105 the thing we started a drag for will be gone when we release
4106 the mouse button(s). avoid this. see part 2 at the end of
4110 if (op == Delete || op == Cut || op == Clear) {
4111 if (_drags->active ()) {
4116 if ( op != Delete ) //"Delete" doesn't change copy/paste buf
4117 cut_buffer->clear ();
4119 if (entered_marker) {
4121 /* cut/delete op while pointing at a marker */
4124 Location* loc = find_location_from_marker (entered_marker, ignored);
4126 if (_session && loc) {
4127 entered_marker = NULL;
4128 Glib::signal_idle().connect (sigc::bind (sigc::mem_fun(*this, &Editor::really_remove_marker), loc));
4135 switch (mouse_mode) {
4138 begin_reversible_command (opname + ' ' + X_("MIDI"));
4140 commit_reversible_command ();
4146 bool did_edit = false;
4148 if (!selection->regions.empty() || !selection->points.empty()) {
4149 begin_reversible_command (opname + ' ' + _("objects"));
4152 if (!selection->regions.empty()) {
4153 cut_copy_regions (op, selection->regions);
4155 if (op == Cut || op == Delete) {
4156 selection->clear_regions ();
4160 if (!selection->points.empty()) {
4161 cut_copy_points (op);
4163 if (op == Cut || op == Delete) {
4164 selection->clear_points ();
4167 } else if (selection->time.empty()) {
4168 framepos_t start, end;
4169 /* no time selection, see if we can get an edit range
4172 if (get_edit_op_range (start, end)) {
4173 selection->set (start, end);
4175 } else if (!selection->time.empty()) {
4176 begin_reversible_command (opname + ' ' + _("range"));
4179 cut_copy_ranges (op);
4181 if (op == Cut || op == Delete) {
4182 selection->clear_time ();
4187 /* reset repeated paste state */
4190 commit_reversible_command ();
4193 if (op == Delete || op == Cut || op == Clear) {
4199 struct AutomationRecord {
4200 AutomationRecord () : state (0) , line(NULL) {}
4201 AutomationRecord (XMLNode* s, const AutomationLine* l) : state (s) , line (l) {}
4203 XMLNode* state; ///< state before any operation
4204 const AutomationLine* line; ///< line this came from
4205 boost::shared_ptr<Evoral::ControlList> copy; ///< copied events for the cut buffer
4207 struct PointsSelectionPositionSorter {
4208 bool operator() (ControlPoint* a, ControlPoint* b) {
4209 return (*(a->model()))->when < (*(b->model()))->when;
4212 /** Cut, copy or clear selected automation points.
4213 * @param op Operation (Cut, Copy or Clear)
4216 Editor::cut_copy_points (Editing::CutCopyOp op, Evoral::Beats earliest, bool midi)
4218 if (selection->points.empty ()) {
4222 /* XXX: not ideal, as there may be more than one track involved in the point selection */
4223 _last_cut_copy_source_track = &selection->points.front()->line().trackview;
4225 /* Keep a record of the AutomationLists that we end up using in this operation */
4226 typedef std::map<boost::shared_ptr<AutomationList>, AutomationRecord> Lists;
4229 /* user could select points in any order */
4230 selection->points.sort(PointsSelectionPositionSorter ());
4232 /* Go through all selected points, making an AutomationRecord for each distinct AutomationList */
4233 for (PointSelection::iterator sel_point = selection->points.begin(); sel_point != selection->points.end(); ++sel_point) {
4234 const AutomationLine& line = (*sel_point)->line();
4235 const boost::shared_ptr<AutomationList> al = line.the_list();
4236 if (lists.find (al) == lists.end ()) {
4237 /* We haven't seen this list yet, so make a record for it. This includes
4238 taking a copy of its current state, in case this is needed for undo later.
4240 lists[al] = AutomationRecord (&al->get_state (), &line);
4244 if (op == Cut || op == Copy) {
4245 /* This operation will involve putting things in the cut buffer, so create an empty
4246 ControlList for each of our source lists to put the cut buffer data in.
4248 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
4249 i->second.copy = i->first->create (i->first->parameter (), i->first->descriptor());
4252 /* Add all selected points to the relevant copy ControlLists */
4253 framepos_t start = std::numeric_limits<framepos_t>::max();
4254 for (PointSelection::iterator sel_point = selection->points.begin(); sel_point != selection->points.end(); ++sel_point) {
4255 boost::shared_ptr<AutomationList> al = (*sel_point)->line().the_list();
4256 AutomationList::const_iterator ctrl_evt = (*sel_point)->model ();
4258 lists[al].copy->fast_simple_add ((*ctrl_evt)->when, (*ctrl_evt)->value);
4260 /* Update earliest MIDI start time in beats */
4261 earliest = std::min(earliest, Evoral::Beats((*ctrl_evt)->when));
4263 /* Update earliest session start time in frames */
4264 start = std::min(start, (*sel_point)->line().session_position(ctrl_evt));
4268 /* Snap start time backwards, so copy/paste is snap aligned. */
4270 if (earliest == Evoral::Beats::max()) {
4271 earliest = Evoral::Beats(); // Weird... don't offset
4273 earliest.round_down_to_beat();
4275 if (start == std::numeric_limits<double>::max()) {
4276 start = 0; // Weird... don't offset
4278 snap_to(start, RoundDownMaybe);
4281 const double line_offset = midi ? earliest.to_double() : start;
4282 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
4283 /* Correct this copy list so that it is relative to the earliest
4284 start time, so relative ordering between points is preserved
4285 when copying from several lists and the paste starts at the
4286 earliest copied piece of data. */
4287 boost::shared_ptr<Evoral::ControlList> &al_cpy = i->second.copy;
4288 for (AutomationList::iterator ctrl_evt = al_cpy->begin(); ctrl_evt != al_cpy->end(); ++ctrl_evt) {
4289 (*ctrl_evt)->when -= line_offset;
4292 /* And add it to the cut buffer */
4293 cut_buffer->add (al_cpy);
4297 if (op == Delete || op == Cut) {
4298 /* This operation needs to remove things from the main AutomationList, so do that now */
4300 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
4301 i->first->freeze ();
4304 /* Remove each selected point from its AutomationList */
4305 for (PointSelection::iterator sel_point = selection->points.begin(); sel_point != selection->points.end(); ++sel_point) {
4306 AutomationLine& line = (*sel_point)->line ();
4307 boost::shared_ptr<AutomationList> al = line.the_list();
4311 if (dynamic_cast<AudioRegionGainLine*> (&line)) {
4312 /* removing of first and last gain point in region gain lines is prohibited*/
4313 if (line.is_last_point (*(*sel_point)) || line.is_first_point (*(*sel_point))) {
4319 al->erase ((*sel_point)->model ());
4323 /* Thaw the lists and add undo records for them */
4324 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
4325 boost::shared_ptr<AutomationList> al = i->first;
4327 _session->add_command (new MementoCommand<AutomationList> (*al.get(), i->second.state, &(al->get_state ())));
4332 /** Cut, copy or clear selected automation points.
4333 * @param op Operation (Cut, Copy or Clear)
4336 Editor::cut_copy_midi (CutCopyOp op)
4338 Evoral::Beats earliest = Evoral::Beats::max();
4339 for (MidiRegionSelection::iterator i = selection->midi_regions.begin(); i != selection->midi_regions.end(); ++i) {
4340 MidiRegionView* mrv = dynamic_cast<MidiRegionView*>(*i);
4342 if (!mrv->selection().empty()) {
4343 earliest = std::min(earliest, (*mrv->selection().begin())->note()->time());
4345 mrv->cut_copy_clear (op);
4347 /* XXX: not ideal, as there may be more than one track involved in the selection */
4348 _last_cut_copy_source_track = &mrv->get_time_axis_view();
4352 if (!selection->points.empty()) {
4353 cut_copy_points (op, earliest, true);
4354 if (op == Cut || op == Delete) {
4355 selection->clear_points ();
4360 struct lt_playlist {
4361 bool operator () (const PlaylistState& a, const PlaylistState& b) {
4362 return a.playlist < b.playlist;
4366 struct PlaylistMapping {
4368 boost::shared_ptr<Playlist> pl;
4370 PlaylistMapping (TimeAxisView* tvp) : tv (tvp) {}
4373 /** Remove `clicked_regionview' */
4375 Editor::remove_clicked_region ()
4377 if (clicked_routeview == 0 || clicked_regionview == 0) {
4381 begin_reversible_command (_("remove region"));
4383 boost::shared_ptr<Playlist> playlist = clicked_routeview->playlist();
4385 playlist->clear_changes ();
4386 playlist->clear_owned_changes ();
4387 playlist->remove_region (clicked_regionview->region());
4388 if (Config->get_edit_mode() == Ripple)
4389 playlist->ripple (clicked_regionview->region()->position(), -clicked_regionview->region()->length(), boost::shared_ptr<Region>());
4391 /* We might have removed regions, which alters other regions' layering_index,
4392 so we need to do a recursive diff here.
4394 vector<Command*> cmds;
4395 playlist->rdiff (cmds);
4396 _session->add_commands (cmds);
4398 _session->add_command(new StatefulDiffCommand (playlist));
4399 commit_reversible_command ();
4403 /** Remove the selected regions */
4405 Editor::remove_selected_regions ()
4407 RegionSelection rs = get_regions_from_selection_and_entered ();
4409 if (!_session || rs.empty()) {
4413 list<boost::shared_ptr<Region> > regions_to_remove;
4415 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
4416 // we can't just remove the region(s) in this loop because
4417 // this removes them from the RegionSelection, and they thus
4418 // disappear from underneath the iterator, and the ++i above
4419 // SEGVs in a puzzling fashion.
4421 // so, first iterate over the regions to be removed from rs and
4422 // add them to the regions_to_remove list, and then
4423 // iterate over the list to actually remove them.
4425 regions_to_remove.push_back ((*i)->region());
4428 vector<boost::shared_ptr<Playlist> > playlists;
4430 for (list<boost::shared_ptr<Region> >::iterator rl = regions_to_remove.begin(); rl != regions_to_remove.end(); ++rl) {
4432 boost::shared_ptr<Playlist> playlist = (*rl)->playlist();
4435 // is this check necessary?
4439 /* get_regions_from_selection_and_entered() guarantees that
4440 the playlists involved are unique, so there is no need
4444 playlists.push_back (playlist);
4446 playlist->clear_changes ();
4447 playlist->clear_owned_changes ();
4448 playlist->freeze ();
4449 playlist->remove_region (*rl);
4450 if (Config->get_edit_mode() == Ripple)
4451 playlist->ripple ((*rl)->position(), -(*rl)->length(), boost::shared_ptr<Region>());
4455 vector<boost::shared_ptr<Playlist> >::iterator pl;
4456 bool in_command = false;
4458 for (pl = playlists.begin(); pl != playlists.end(); ++pl) {
4461 /* We might have removed regions, which alters other regions' layering_index,
4462 so we need to do a recursive diff here.
4466 begin_reversible_command (_("remove region"));
4469 vector<Command*> cmds;
4470 (*pl)->rdiff (cmds);
4471 _session->add_commands (cmds);
4473 _session->add_command(new StatefulDiffCommand (*pl));
4477 commit_reversible_command ();
4481 /** Cut, copy or clear selected regions.
4482 * @param op Operation (Cut, Copy or Clear)
4485 Editor::cut_copy_regions (CutCopyOp op, RegionSelection& rs)
4487 /* we can't use a std::map here because the ordering is important, and we can't trivially sort
4488 a map when we want ordered access to both elements. i think.
4491 vector<PlaylistMapping> pmap;
4493 framepos_t first_position = max_framepos;
4495 typedef set<boost::shared_ptr<Playlist> > FreezeList;
4496 FreezeList freezelist;
4498 /* get ordering correct before we cut/copy */
4500 rs.sort_by_position_and_track ();
4502 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
4504 first_position = min ((framepos_t) (*x)->region()->position(), first_position);
4506 if (op == Cut || op == Clear || op == Delete) {
4507 boost::shared_ptr<Playlist> pl = (*x)->region()->playlist();
4510 FreezeList::iterator fl;
4512 // only take state if this is a new playlist.
4513 for (fl = freezelist.begin(); fl != freezelist.end(); ++fl) {
4519 if (fl == freezelist.end()) {
4520 pl->clear_changes();
4521 pl->clear_owned_changes ();
4523 freezelist.insert (pl);
4528 TimeAxisView* tv = &(*x)->get_time_axis_view();
4529 vector<PlaylistMapping>::iterator z;
4531 for (z = pmap.begin(); z != pmap.end(); ++z) {
4532 if ((*z).tv == tv) {
4537 if (z == pmap.end()) {
4538 pmap.push_back (PlaylistMapping (tv));
4542 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ) {
4544 boost::shared_ptr<Playlist> pl = (*x)->region()->playlist();
4547 /* region not yet associated with a playlist (e.g. unfinished
4554 TimeAxisView& tv = (*x)->get_time_axis_view();
4555 boost::shared_ptr<Playlist> npl;
4556 RegionSelection::iterator tmp;
4563 vector<PlaylistMapping>::iterator z;
4565 for (z = pmap.begin(); z != pmap.end(); ++z) {
4566 if ((*z).tv == &tv) {
4571 assert (z != pmap.end());
4574 npl = PlaylistFactory::create (pl->data_type(), *_session, "cutlist", true);
4582 boost::shared_ptr<Region> r = (*x)->region();
4583 boost::shared_ptr<Region> _xx;
4589 pl->remove_region (r);
4590 if (Config->get_edit_mode() == Ripple)
4591 pl->ripple (r->position(), -r->length(), boost::shared_ptr<Region>());
4595 _xx = RegionFactory::create (r);
4596 npl->add_region (_xx, r->position() - first_position);
4597 pl->remove_region (r);
4598 if (Config->get_edit_mode() == Ripple)
4599 pl->ripple (r->position(), -r->length(), boost::shared_ptr<Region>());
4603 /* copy region before adding, so we're not putting same object into two different playlists */
4604 npl->add_region (RegionFactory::create (r), r->position() - first_position);
4608 pl->remove_region (r);
4609 if (Config->get_edit_mode() == Ripple)
4610 pl->ripple (r->position(), -r->length(), boost::shared_ptr<Region>());
4619 list<boost::shared_ptr<Playlist> > foo;
4621 /* the pmap is in the same order as the tracks in which selected regions occurred */
4623 for (vector<PlaylistMapping>::iterator i = pmap.begin(); i != pmap.end(); ++i) {
4626 foo.push_back ((*i).pl);
4631 cut_buffer->set (foo);
4635 _last_cut_copy_source_track = 0;
4637 _last_cut_copy_source_track = pmap.front().tv;
4641 for (FreezeList::iterator pl = freezelist.begin(); pl != freezelist.end(); ++pl) {
4644 /* We might have removed regions, which alters other regions' layering_index,
4645 so we need to do a recursive diff here.
4647 vector<Command*> cmds;
4648 (*pl)->rdiff (cmds);
4649 _session->add_commands (cmds);
4651 _session->add_command (new StatefulDiffCommand (*pl));
4656 Editor::cut_copy_ranges (CutCopyOp op)
4658 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4660 /* Sort the track selection now, so that it if is used, the playlists
4661 selected by the calls below to cut_copy_clear are in the order that
4662 their tracks appear in the editor. This makes things like paste
4663 of ranges work properly.
4666 sort_track_selection (ts);
4669 if (!entered_track) {
4672 ts.push_back (entered_track);
4675 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4676 (*i)->cut_copy_clear (*selection, op);
4681 Editor::paste (float times, bool from_context)
4683 DEBUG_TRACE (DEBUG::CutNPaste, "paste to preferred edit pos\n");
4685 paste_internal (get_preferred_edit_position (EDIT_IGNORE_NONE, from_context), times, get_grid_music_divisions (0));
4689 Editor::mouse_paste ()
4694 if (!mouse_frame (where, ignored)) {
4699 paste_internal (where, 1, get_grid_music_divisions (0));
4703 Editor::paste_internal (framepos_t position, float times, const int32_t sub_num)
4705 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("apparent paste position is %1\n", position));
4707 if (cut_buffer->empty(internal_editing())) {
4711 if (position == max_framepos) {
4712 position = get_preferred_edit_position();
4713 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("preferred edit position is %1\n", position));
4716 if (position == last_paste_pos) {
4717 /* repeated paste in the same position */
4720 /* paste in new location, reset repeated paste state */
4722 last_paste_pos = position;
4725 /* get everything in the correct order */
4728 if (!selection->tracks.empty()) {
4729 /* If there is a track selection, paste into exactly those tracks and
4730 only those tracks. This allows the user to be explicit and override
4731 the below "do the reasonable thing" logic. */
4732 ts = selection->tracks.filter_to_unique_playlists ();
4733 sort_track_selection (ts);
4735 /* Figure out which track to base the paste at. */
4736 TimeAxisView* base_track = NULL;
4737 if (_edit_point == Editing::EditAtMouse && entered_track) {
4738 /* With the mouse edit point, paste onto the track under the mouse. */
4739 base_track = entered_track;
4740 } else if (_edit_point == Editing::EditAtMouse && entered_regionview) {
4741 /* With the mouse edit point, paste onto the track of the region under the mouse. */
4742 base_track = &entered_regionview->get_time_axis_view();
4743 } else if (_last_cut_copy_source_track) {
4744 /* Paste to the track that the cut/copy came from (see mantis #333). */
4745 base_track = _last_cut_copy_source_track;
4747 /* This is "impossible" since we've copied... well, do nothing. */
4751 /* Walk up to parent if necessary, so base track is a route. */
4752 while (base_track->get_parent()) {
4753 base_track = base_track->get_parent();
4756 /* Add base track and all tracks below it. The paste logic will select
4757 the appropriate object types from the cut buffer in relative order. */
4758 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4759 if ((*i)->order() >= base_track->order()) {
4764 /* Sort tracks so the nth track of type T will pick the nth object of type T. */
4765 sort_track_selection (ts);
4767 /* Add automation children of each track in order, for pasting several lines. */
4768 for (TrackViewList::iterator i = ts.begin(); i != ts.end();) {
4769 /* Add any automation children for pasting several lines */
4770 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*i++);
4775 typedef RouteTimeAxisView::AutomationTracks ATracks;
4776 const ATracks& atracks = rtv->automation_tracks();
4777 for (ATracks::const_iterator a = atracks.begin(); a != atracks.end(); ++a) {
4778 i = ts.insert(i, a->second.get());
4783 /* We now have a list of trackviews starting at base_track, including
4784 automation children, in the order shown in the editor, e.g. R1,
4785 R1.A1, R1.A2, R2, R2.A1, ... */
4788 begin_reversible_command (Operations::paste);
4790 if (ts.size() == 1 && cut_buffer->lines.size() == 1 &&
4791 dynamic_cast<AutomationTimeAxisView*>(ts.front())) {
4792 /* Only one line copied, and one automation track selected. Do a
4793 "greedy" paste from one automation type to another. */
4795 PasteContext ctx(paste_count, times, ItemCounts(), true);
4796 ts.front()->paste (position, *cut_buffer, ctx, sub_num);
4800 /* Paste into tracks */
4802 PasteContext ctx(paste_count, times, ItemCounts(), false);
4803 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4804 (*i)->paste (position, *cut_buffer, ctx, sub_num);
4808 commit_reversible_command ();
4812 Editor::duplicate_some_regions (RegionSelection& regions, float times)
4814 if (regions.empty ()) {
4818 boost::shared_ptr<Playlist> playlist;
4819 RegionSelection sel = regions; // clear (below) may clear the argument list if its the current region selection
4820 RegionSelection foo;
4822 framepos_t const start_frame = regions.start ();
4823 framepos_t const end_frame = regions.end_frame ();
4824 framecnt_t const gap = end_frame - start_frame + 1;
4826 begin_reversible_command (Operations::duplicate_region);
4828 selection->clear_regions ();
4830 for (RegionSelection::iterator i = sel.begin(); i != sel.end(); ++i) {
4832 boost::shared_ptr<Region> r ((*i)->region());
4834 TimeAxisView& tv = (*i)->get_time_axis_view();
4835 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (&tv);
4836 latest_regionviews.clear ();
4837 sigc::connection c = rtv->view()->RegionViewAdded.connect (sigc::mem_fun(*this, &Editor::collect_new_region_view));
4839 framepos_t const position = end_frame + (r->first_frame() - start_frame + 1);
4840 playlist = (*i)->region()->playlist();
4841 playlist->clear_changes ();
4842 playlist->duplicate (r, position, gap, times);
4843 _session->add_command(new StatefulDiffCommand (playlist));
4847 foo.insert (foo.end(), latest_regionviews.begin(), latest_regionviews.end());
4851 selection->set (foo);
4854 commit_reversible_command ();
4858 Editor::duplicate_selection (float times)
4860 if (selection->time.empty() || selection->tracks.empty()) {
4864 boost::shared_ptr<Playlist> playlist;
4866 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4868 bool in_command = false;
4870 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4871 if ((playlist = (*i)->playlist()) == 0) {
4874 playlist->clear_changes ();
4876 if (clicked_selection) {
4877 playlist->duplicate_range (selection->time[clicked_selection], times);
4879 playlist->duplicate_ranges (selection->time, times);
4883 begin_reversible_command (_("duplicate range selection"));
4886 _session->add_command (new StatefulDiffCommand (playlist));
4891 // now "move" range selection to after the current range selection
4892 framecnt_t distance = 0;
4894 if (clicked_selection) {
4895 distance = selection->time[clicked_selection].end -
4896 selection->time[clicked_selection].start;
4898 distance = selection->time.end_frame() - selection->time.start();
4901 selection->move_time (distance);
4903 commit_reversible_command ();
4907 /** Reset all selected points to the relevant default value */
4909 Editor::reset_point_selection ()
4911 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
4912 ARDOUR::AutomationList::iterator j = (*i)->model ();
4913 (*j)->value = (*i)->line().the_list()->default_value ();
4918 Editor::center_playhead ()
4920 float const page = _visible_canvas_width * samples_per_pixel;
4921 center_screen_internal (playhead_cursor->current_frame (), page);
4925 Editor::center_edit_point ()
4927 float const page = _visible_canvas_width * samples_per_pixel;
4928 center_screen_internal (get_preferred_edit_position(), page);
4931 /** Caller must begin and commit a reversible command */
4933 Editor::clear_playlist (boost::shared_ptr<Playlist> playlist)
4935 playlist->clear_changes ();
4937 _session->add_command (new StatefulDiffCommand (playlist));
4941 Editor::nudge_track (bool use_edit, bool forwards)
4943 boost::shared_ptr<Playlist> playlist;
4944 framepos_t distance;
4945 framepos_t next_distance;
4949 start = get_preferred_edit_position();
4954 if ((distance = get_nudge_distance (start, next_distance)) == 0) {
4958 if (selection->tracks.empty()) {
4962 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4963 bool in_command = false;
4965 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4967 if ((playlist = (*i)->playlist()) == 0) {
4971 playlist->clear_changes ();
4972 playlist->clear_owned_changes ();
4974 playlist->nudge_after (start, distance, forwards);
4977 begin_reversible_command (_("nudge track"));
4980 vector<Command*> cmds;
4982 playlist->rdiff (cmds);
4983 _session->add_commands (cmds);
4985 _session->add_command (new StatefulDiffCommand (playlist));
4989 commit_reversible_command ();
4994 Editor::remove_last_capture ()
4996 vector<string> choices;
5003 if (Config->get_verify_remove_last_capture()) {
5004 prompt = _("Do you really want to destroy the last capture?"
5005 "\n(This is destructive and cannot be undone)");
5007 choices.push_back (_("No, do nothing."));
5008 choices.push_back (_("Yes, destroy it."));
5010 Gtkmm2ext::Choice prompter (_("Destroy last capture"), prompt, choices);
5012 if (prompter.run () == 1) {
5013 _session->remove_last_capture ();
5014 _regions->redisplay ();
5018 _session->remove_last_capture();
5019 _regions->redisplay ();
5024 Editor::normalize_region ()
5030 RegionSelection rs = get_regions_from_selection_and_entered ();
5036 NormalizeDialog dialog (rs.size() > 1);
5038 if (dialog.run () == RESPONSE_CANCEL) {
5042 CursorContext::Handle cursor_ctx = CursorContext::create(*this, _cursors->wait);
5045 /* XXX: should really only count audio regions here */
5046 int const regions = rs.size ();
5048 /* Make a list of the selected audio regions' maximum amplitudes, and also
5049 obtain the maximum amplitude of them all.
5051 list<double> max_amps;
5052 list<double> rms_vals;
5055 bool use_rms = dialog.constrain_rms ();
5057 for (RegionSelection::const_iterator i = rs.begin(); i != rs.end(); ++i) {
5058 AudioRegionView const * arv = dynamic_cast<AudioRegionView const *> (*i);
5062 dialog.descend (1.0 / regions);
5063 double const a = arv->audio_region()->maximum_amplitude (&dialog);
5065 double r = arv->audio_region()->rms (&dialog);
5066 max_rms = max (max_rms, r);
5067 rms_vals.push_back (r);
5071 /* the user cancelled the operation */
5075 max_amps.push_back (a);
5076 max_amp = max (max_amp, a);
5080 list<double>::const_iterator a = max_amps.begin ();
5081 list<double>::const_iterator l = rms_vals.begin ();
5082 bool in_command = false;
5084 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
5085 AudioRegionView* const arv = dynamic_cast<AudioRegionView*> (*r);
5090 arv->region()->clear_changes ();
5092 double amp = dialog.normalize_individually() ? *a : max_amp;
5093 double target = dialog.target_peak (); // dB
5096 double const amp_rms = dialog.normalize_individually() ? *l : max_rms;
5097 const double t_rms = dialog.target_rms ();
5098 const gain_t c_peak = dB_to_coefficient (target);
5099 const gain_t c_rms = dB_to_coefficient (t_rms);
5100 if ((amp_rms / c_rms) > (amp / c_peak)) {
5106 arv->audio_region()->normalize (amp, target);
5109 begin_reversible_command (_("normalize"));
5112 _session->add_command (new StatefulDiffCommand (arv->region()));
5119 commit_reversible_command ();
5125 Editor::reset_region_scale_amplitude ()
5131 RegionSelection rs = get_regions_from_selection_and_entered ();
5137 bool in_command = false;
5139 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
5140 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
5143 arv->region()->clear_changes ();
5144 arv->audio_region()->set_scale_amplitude (1.0f);
5147 begin_reversible_command ("reset gain");
5150 _session->add_command (new StatefulDiffCommand (arv->region()));
5154 commit_reversible_command ();
5159 Editor::adjust_region_gain (bool up)
5161 RegionSelection rs = get_regions_from_selection_and_entered ();
5163 if (!_session || rs.empty()) {
5167 bool in_command = false;
5169 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
5170 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
5175 arv->region()->clear_changes ();
5177 double dB = accurate_coefficient_to_dB (arv->audio_region()->scale_amplitude ());
5185 arv->audio_region()->set_scale_amplitude (dB_to_coefficient (dB));
5188 begin_reversible_command ("adjust region gain");
5191 _session->add_command (new StatefulDiffCommand (arv->region()));
5195 commit_reversible_command ();
5201 Editor::reverse_region ()
5207 Reverse rev (*_session);
5208 apply_filter (rev, _("reverse regions"));
5212 Editor::strip_region_silence ()
5218 RegionSelection rs = get_regions_from_selection_and_entered ();
5224 std::list<RegionView*> audio_only;
5226 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5227 AudioRegionView* const arv = dynamic_cast<AudioRegionView*> (*i);
5229 audio_only.push_back (arv);
5233 assert (!audio_only.empty());
5235 StripSilenceDialog d (_session, audio_only);
5236 int const r = d.run ();
5240 if (r == Gtk::RESPONSE_OK) {
5241 ARDOUR::AudioIntervalMap silences;
5242 d.silences (silences);
5243 StripSilence s (*_session, silences, d.fade_length());
5245 apply_filter (s, _("strip silence"), &d);
5250 Editor::apply_midi_note_edit_op_to_region (MidiOperator& op, MidiRegionView& mrv)
5252 Evoral::Sequence<Evoral::Beats>::Notes selected;
5253 mrv.selection_as_notelist (selected, true);
5255 vector<Evoral::Sequence<Evoral::Beats>::Notes> v;
5256 v.push_back (selected);
5258 framepos_t pos_frames = mrv.midi_region()->position() - mrv.midi_region()->start();
5259 Evoral::Beats pos_beats = _session->tempo_map().framewalk_to_beats(0, pos_frames);
5261 return op (mrv.midi_region()->model(), pos_beats, v);
5265 Editor::apply_midi_note_edit_op (MidiOperator& op, const RegionSelection& rs)
5271 bool in_command = false;
5273 for (RegionSelection::const_iterator r = rs.begin(); r != rs.end(); ) {
5274 RegionSelection::const_iterator tmp = r;
5277 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*r);
5280 Command* cmd = apply_midi_note_edit_op_to_region (op, *mrv);
5283 begin_reversible_command (op.name ());
5287 _session->add_command (cmd);
5295 commit_reversible_command ();
5300 Editor::fork_region ()
5302 RegionSelection rs = get_regions_from_selection_and_entered ();
5308 CursorContext::Handle cursor_ctx = CursorContext::create(*this, _cursors->wait);
5309 bool in_command = false;
5313 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
5314 RegionSelection::iterator tmp = r;
5317 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*>(*r);
5321 boost::shared_ptr<Playlist> playlist = mrv->region()->playlist();
5322 boost::shared_ptr<MidiSource> new_source = _session->create_midi_source_by_stealing_name (mrv->midi_view()->track());
5323 boost::shared_ptr<MidiRegion> newregion = mrv->midi_region()->clone (new_source);
5326 begin_reversible_command (_("Fork Region(s)"));
5329 playlist->clear_changes ();
5330 playlist->replace_region (mrv->region(), newregion, mrv->region()->position());
5331 _session->add_command(new StatefulDiffCommand (playlist));
5333 error << string_compose (_("Could not unlink %1"), mrv->region()->name()) << endmsg;
5341 commit_reversible_command ();
5346 Editor::quantize_region ()
5349 quantize_regions(get_regions_from_selection_and_entered ());
5354 Editor::quantize_regions (const RegionSelection& rs)
5356 if (rs.n_midi_regions() == 0) {
5360 if (!quantize_dialog) {
5361 quantize_dialog = new QuantizeDialog (*this);
5364 quantize_dialog->present ();
5365 const int r = quantize_dialog->run ();
5366 quantize_dialog->hide ();
5368 if (r == Gtk::RESPONSE_OK) {
5369 Quantize quant (quantize_dialog->snap_start(),
5370 quantize_dialog->snap_end(),
5371 quantize_dialog->start_grid_size(),
5372 quantize_dialog->end_grid_size(),
5373 quantize_dialog->strength(),
5374 quantize_dialog->swing(),
5375 quantize_dialog->threshold());
5377 apply_midi_note_edit_op (quant, rs);
5382 Editor::legatize_region (bool shrink_only)
5385 legatize_regions(get_regions_from_selection_and_entered (), shrink_only);
5390 Editor::legatize_regions (const RegionSelection& rs, bool shrink_only)
5392 if (rs.n_midi_regions() == 0) {
5396 Legatize legatize(shrink_only);
5397 apply_midi_note_edit_op (legatize, rs);
5401 Editor::transform_region ()
5404 transform_regions(get_regions_from_selection_and_entered ());
5409 Editor::transform_regions (const RegionSelection& rs)
5411 if (rs.n_midi_regions() == 0) {
5418 const int r = td.run();
5421 if (r == Gtk::RESPONSE_OK) {
5422 Transform transform(td.get());
5423 apply_midi_note_edit_op(transform, rs);
5428 Editor::transpose_region ()
5431 transpose_regions(get_regions_from_selection_and_entered ());
5436 Editor::transpose_regions (const RegionSelection& rs)
5438 if (rs.n_midi_regions() == 0) {
5443 int const r = d.run ();
5445 if (r == RESPONSE_ACCEPT) {
5446 Transpose transpose(d.semitones ());
5447 apply_midi_note_edit_op (transpose, rs);
5452 Editor::insert_patch_change (bool from_context)
5454 RegionSelection rs = get_regions_from_selection_and_entered ();
5460 const framepos_t p = get_preferred_edit_position (EDIT_IGNORE_NONE, from_context);
5462 /* XXX: bit of a hack; use the MIDNAM from the first selected region;
5463 there may be more than one, but the PatchChangeDialog can only offer
5464 one set of patch menus.
5466 MidiRegionView* first = dynamic_cast<MidiRegionView*> (rs.front ());
5468 Evoral::PatchChange<Evoral::Beats> empty (Evoral::Beats(), 0, 0, 0);
5469 PatchChangeDialog d (0, _session, empty, first->instrument_info(), Gtk::Stock::ADD);
5471 if (d.run() == RESPONSE_CANCEL) {
5475 for (RegionSelection::iterator i = rs.begin (); i != rs.end(); ++i) {
5476 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*i);
5478 if (p >= mrv->region()->first_frame() && p <= mrv->region()->last_frame()) {
5479 mrv->add_patch_change (p - mrv->region()->position(), d.patch ());
5486 Editor::apply_filter (Filter& filter, string command, ProgressReporter* progress)
5488 RegionSelection rs = get_regions_from_selection_and_entered ();
5494 CursorContext::Handle cursor_ctx = CursorContext::create(*this, _cursors->wait);
5495 bool in_command = false;
5500 int const N = rs.size ();
5502 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
5503 RegionSelection::iterator tmp = r;
5506 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
5508 boost::shared_ptr<Playlist> playlist = arv->region()->playlist();
5511 progress->descend (1.0 / N);
5514 if (arv->audio_region()->apply (filter, progress) == 0) {
5516 playlist->clear_changes ();
5517 playlist->clear_owned_changes ();
5520 begin_reversible_command (command);
5524 if (filter.results.empty ()) {
5526 /* no regions returned; remove the old one */
5527 playlist->remove_region (arv->region ());
5531 std::vector<boost::shared_ptr<Region> >::iterator res = filter.results.begin ();
5533 /* first region replaces the old one */
5534 playlist->replace_region (arv->region(), *res, (*res)->position());
5538 while (res != filter.results.end()) {
5539 playlist->add_region (*res, (*res)->position());
5545 /* We might have removed regions, which alters other regions' layering_index,
5546 so we need to do a recursive diff here.
5548 vector<Command*> cmds;
5549 playlist->rdiff (cmds);
5550 _session->add_commands (cmds);
5552 _session->add_command(new StatefulDiffCommand (playlist));
5556 progress->ascend ();
5565 commit_reversible_command ();
5570 Editor::external_edit_region ()
5576 Editor::reset_region_gain_envelopes ()
5578 RegionSelection rs = get_regions_from_selection_and_entered ();
5580 if (!_session || rs.empty()) {
5584 bool in_command = false;
5586 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5587 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
5589 boost::shared_ptr<AutomationList> alist (arv->audio_region()->envelope());
5590 XMLNode& before (alist->get_state());
5592 arv->audio_region()->set_default_envelope ();
5595 begin_reversible_command (_("reset region gain"));
5598 _session->add_command (new MementoCommand<AutomationList>(*arv->audio_region()->envelope().get(), &before, &alist->get_state()));
5603 commit_reversible_command ();
5608 Editor::set_region_gain_visibility (RegionView* rv)
5610 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (rv);
5612 arv->update_envelope_visibility();
5617 Editor::set_gain_envelope_visibility ()
5623 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5624 AudioTimeAxisView* v = dynamic_cast<AudioTimeAxisView*>(*i);
5626 v->audio_view()->foreach_regionview (sigc::mem_fun (this, &Editor::set_region_gain_visibility));
5632 Editor::toggle_gain_envelope_active ()
5634 if (_ignore_region_action) {
5638 RegionSelection rs = get_regions_from_selection_and_entered ();
5640 if (!_session || rs.empty()) {
5644 bool in_command = false;
5646 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5647 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
5649 arv->region()->clear_changes ();
5650 arv->audio_region()->set_envelope_active (!arv->audio_region()->envelope_active());
5653 begin_reversible_command (_("region gain envelope active"));
5656 _session->add_command (new StatefulDiffCommand (arv->region()));
5661 commit_reversible_command ();
5666 Editor::toggle_region_lock ()
5668 if (_ignore_region_action) {
5672 RegionSelection rs = get_regions_from_selection_and_entered ();
5674 if (!_session || rs.empty()) {
5678 begin_reversible_command (_("toggle region lock"));
5680 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5681 (*i)->region()->clear_changes ();
5682 (*i)->region()->set_locked (!(*i)->region()->locked());
5683 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5686 commit_reversible_command ();
5690 Editor::toggle_region_video_lock ()
5692 if (_ignore_region_action) {
5696 RegionSelection rs = get_regions_from_selection_and_entered ();
5698 if (!_session || rs.empty()) {
5702 begin_reversible_command (_("Toggle Video Lock"));
5704 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5705 (*i)->region()->clear_changes ();
5706 (*i)->region()->set_video_locked (!(*i)->region()->video_locked());
5707 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5710 commit_reversible_command ();
5714 Editor::toggle_region_lock_style ()
5716 if (_ignore_region_action) {
5720 RegionSelection rs = get_regions_from_selection_and_entered ();
5722 if (!_session || rs.empty()) {
5726 begin_reversible_command (_("region lock style"));
5728 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5729 (*i)->region()->clear_changes ();
5730 PositionLockStyle const ns = (*i)->region()->position_lock_style() == AudioTime ? MusicTime : AudioTime;
5731 (*i)->region()->set_position_lock_style (ns);
5732 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5735 commit_reversible_command ();
5739 Editor::toggle_opaque_region ()
5741 if (_ignore_region_action) {
5745 RegionSelection rs = get_regions_from_selection_and_entered ();
5747 if (!_session || rs.empty()) {
5751 begin_reversible_command (_("change region opacity"));
5753 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5754 (*i)->region()->clear_changes ();
5755 (*i)->region()->set_opaque (!(*i)->region()->opaque());
5756 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5759 commit_reversible_command ();
5763 Editor::toggle_record_enable ()
5765 bool new_state = false;
5767 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5768 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5771 if (!rtav->is_track())
5775 new_state = !rtav->track()->rec_enable_control()->get_value();
5779 rtav->track()->rec_enable_control()->set_value (new_state, Controllable::UseGroup);
5784 Editor::toggle_solo ()
5786 bool new_state = false;
5788 boost::shared_ptr<ControlList> cl (new ControlList);
5790 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5791 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5798 new_state = !rtav->route()->soloed ();
5802 cl->push_back (rtav->route()->solo_control());
5805 _session->set_controls (cl, new_state ? 1.0 : 0.0, Controllable::UseGroup);
5809 Editor::toggle_mute ()
5811 bool new_state = false;
5813 boost::shared_ptr<RouteList> rl (new RouteList);
5815 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5816 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5823 new_state = !rtav->route()->muted();
5827 rl->push_back (rtav->route());
5830 _session->set_controls (route_list_to_control_list (rl, &Stripable::mute_control), new_state, Controllable::UseGroup);
5834 Editor::toggle_solo_isolate ()
5840 Editor::fade_range ()
5842 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
5844 begin_reversible_command (_("fade range"));
5846 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
5847 (*i)->fade_range (selection->time);
5850 commit_reversible_command ();
5855 Editor::set_fade_length (bool in)
5857 RegionSelection rs = get_regions_from_selection_and_entered ();
5863 /* we need a region to measure the offset from the start */
5865 RegionView* rv = rs.front ();
5867 framepos_t pos = get_preferred_edit_position();
5871 if (pos > rv->region()->last_frame() || pos < rv->region()->first_frame()) {
5872 /* edit point is outside the relevant region */
5877 if (pos <= rv->region()->position()) {
5881 len = pos - rv->region()->position();
5882 cmd = _("set fade in length");
5884 if (pos >= rv->region()->last_frame()) {
5888 len = rv->region()->last_frame() - pos;
5889 cmd = _("set fade out length");
5892 bool in_command = false;
5894 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5895 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5901 boost::shared_ptr<AutomationList> alist;
5903 alist = tmp->audio_region()->fade_in();
5905 alist = tmp->audio_region()->fade_out();
5908 XMLNode &before = alist->get_state();
5911 tmp->audio_region()->set_fade_in_length (len);
5912 tmp->audio_region()->set_fade_in_active (true);
5914 tmp->audio_region()->set_fade_out_length (len);
5915 tmp->audio_region()->set_fade_out_active (true);
5919 begin_reversible_command (cmd);
5922 XMLNode &after = alist->get_state();
5923 _session->add_command(new MementoCommand<AutomationList>(*alist, &before, &after));
5927 commit_reversible_command ();
5932 Editor::set_fade_in_shape (FadeShape shape)
5934 RegionSelection rs = get_regions_from_selection_and_entered ();
5939 bool in_command = false;
5941 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5942 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5948 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_in();
5949 XMLNode &before = alist->get_state();
5951 tmp->audio_region()->set_fade_in_shape (shape);
5954 begin_reversible_command (_("set fade in shape"));
5957 XMLNode &after = alist->get_state();
5958 _session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
5962 commit_reversible_command ();
5967 Editor::set_fade_out_shape (FadeShape shape)
5969 RegionSelection rs = get_regions_from_selection_and_entered ();
5974 bool in_command = false;
5976 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5977 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5983 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_out();
5984 XMLNode &before = alist->get_state();
5986 tmp->audio_region()->set_fade_out_shape (shape);
5989 begin_reversible_command (_("set fade out shape"));
5992 XMLNode &after = alist->get_state();
5993 _session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
5997 commit_reversible_command ();
6002 Editor::set_fade_in_active (bool yn)
6004 RegionSelection rs = get_regions_from_selection_and_entered ();
6009 bool in_command = false;
6011 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
6012 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
6019 boost::shared_ptr<AudioRegion> ar (tmp->audio_region());
6021 ar->clear_changes ();
6022 ar->set_fade_in_active (yn);
6025 begin_reversible_command (_("set fade in active"));
6028 _session->add_command (new StatefulDiffCommand (ar));
6032 commit_reversible_command ();
6037 Editor::set_fade_out_active (bool yn)
6039 RegionSelection rs = get_regions_from_selection_and_entered ();
6044 bool in_command = false;
6046 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
6047 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
6053 boost::shared_ptr<AudioRegion> ar (tmp->audio_region());
6055 ar->clear_changes ();
6056 ar->set_fade_out_active (yn);
6059 begin_reversible_command (_("set fade out active"));
6062 _session->add_command(new StatefulDiffCommand (ar));
6066 commit_reversible_command ();
6071 Editor::toggle_region_fades (int dir)
6073 if (_ignore_region_action) {
6077 boost::shared_ptr<AudioRegion> ar;
6080 RegionSelection rs = get_regions_from_selection_and_entered ();
6086 RegionSelection::iterator i;
6087 for (i = rs.begin(); i != rs.end(); ++i) {
6088 if ((ar = boost::dynamic_pointer_cast<AudioRegion>((*i)->region())) != 0) {
6090 yn = ar->fade_out_active ();
6092 yn = ar->fade_in_active ();
6098 if (i == rs.end()) {
6102 /* XXX should this undo-able? */
6103 bool in_command = false;
6105 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
6106 if ((ar = boost::dynamic_pointer_cast<AudioRegion>((*i)->region())) == 0) {
6109 ar->clear_changes ();
6111 if (dir == 1 || dir == 0) {
6112 ar->set_fade_in_active (!yn);
6115 if (dir == -1 || dir == 0) {
6116 ar->set_fade_out_active (!yn);
6119 begin_reversible_command (_("toggle fade active"));
6122 _session->add_command(new StatefulDiffCommand (ar));
6126 commit_reversible_command ();
6131 /** Update region fade visibility after its configuration has been changed */
6133 Editor::update_region_fade_visibility ()
6135 bool _fade_visibility = _session->config.get_show_region_fades ();
6137 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
6138 AudioTimeAxisView* v = dynamic_cast<AudioTimeAxisView*>(*i);
6140 if (_fade_visibility) {
6141 v->audio_view()->show_all_fades ();
6143 v->audio_view()->hide_all_fades ();
6150 Editor::set_edit_point ()
6155 if (!mouse_frame (where, ignored)) {
6161 if (selection->markers.empty()) {
6163 mouse_add_new_marker (where);
6168 Location* loc = find_location_from_marker (selection->markers.front(), ignored);
6171 loc->move_to (where);
6177 Editor::set_playhead_cursor ()
6179 if (entered_marker) {
6180 _session->request_locate (entered_marker->position(), _session->transport_rolling());
6185 if (!mouse_frame (where, ignored)) {
6192 _session->request_locate (where, _session->transport_rolling());
6196 if (UIConfiguration::instance().get_follow_edits() && (!_session || !_session->config.get_external_sync())) {
6197 cancel_time_selection();
6202 Editor::split_region ()
6204 if (_drags->active ()) {
6208 //if a range is selected, separate it
6209 if ( !selection->time.empty()) {
6210 separate_regions_between (selection->time);
6214 //if no range was selected, try to find some regions to split
6215 if (current_mouse_mode() == MouseObject) { //don't try this for Internal Edit, Stretch, Draw, etc.
6217 RegionSelection rs = get_regions_from_selection_and_edit_point ();
6219 framepos_t where = get_preferred_edit_position ();
6225 if (snap_musical()) {
6226 split_regions_at (where, rs, get_grid_music_divisions (0));
6228 split_regions_at (where, rs, 0);
6234 Editor::select_next_route()
6236 if (selection->tracks.empty()) {
6237 selection->set (track_views.front());
6241 TimeAxisView* current = selection->tracks.front();
6245 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
6247 if (*i == current) {
6249 if (i != track_views.end()) {
6252 current = (*(track_views.begin()));
6253 //selection->set (*(track_views.begin()));
6259 rui = dynamic_cast<RouteUI *>(current);
6261 } while (current->hidden() || (rui == NULL) || !rui->route()->active());
6263 selection->set (current);
6265 ensure_time_axis_view_is_visible (*current, false);
6269 Editor::select_prev_route()
6271 if (selection->tracks.empty()) {
6272 selection->set (track_views.front());
6276 TimeAxisView* current = selection->tracks.front();
6280 for (TrackViewList::reverse_iterator i = track_views.rbegin(); i != track_views.rend(); ++i) {
6282 if (*i == current) {
6284 if (i != track_views.rend()) {
6287 current = *(track_views.rbegin());
6292 rui = dynamic_cast<RouteUI *>(current);
6294 } while (current->hidden() || (rui == NULL) || !rui->route()->active());
6296 selection->set (current);
6298 ensure_time_axis_view_is_visible (*current, false);
6302 Editor::set_loop_from_selection (bool play)
6304 if (_session == 0) {
6308 framepos_t start, end;
6309 if (!get_selection_extents ( start, end))
6312 set_loop_range (start, end, _("set loop range from selection"));
6315 _session->request_play_loop (true, true);
6320 Editor::set_loop_from_region (bool play)
6322 framepos_t start, end;
6323 if (!get_selection_extents ( start, end))
6326 set_loop_range (start, end, _("set loop range from region"));
6329 _session->request_locate (start, true);
6330 _session->request_play_loop (true);
6335 Editor::set_punch_from_selection ()
6337 if (_session == 0) {
6341 framepos_t start, end;
6342 if (!get_selection_extents ( start, end))
6345 set_punch_range (start, end, _("set punch range from selection"));
6349 Editor::set_session_extents_from_selection ()
6351 if (_session == 0) {
6355 framepos_t start, end;
6356 if (!get_selection_extents ( start, end))
6360 if ((loc = _session->locations()->session_range_location()) == 0) {
6361 _session->set_session_extents (start, end); // this will create a new session range; no need for UNDO
6363 XMLNode &before = loc->get_state();
6365 _session->set_session_extents (start, end);
6367 XMLNode &after = loc->get_state();
6369 begin_reversible_command (_("set session start/end from selection"));
6371 _session->add_command (new MementoCommand<Location>(*loc, &before, &after));
6373 commit_reversible_command ();
6376 _session->set_end_is_free (false);
6380 Editor::set_punch_start_from_edit_point ()
6384 framepos_t start = 0;
6385 framepos_t end = max_framepos;
6387 //use the existing punch end, if any
6388 Location* tpl = transport_punch_location();
6393 if ((_edit_point == EditAtPlayhead) && _session->transport_rolling()) {
6394 start = _session->audible_frame();
6396 start = get_preferred_edit_position();
6399 //snap the selection start/end
6402 //if there's not already a sensible selection endpoint, go "forever"
6403 if ( start > end ) {
6407 set_punch_range (start, end, _("set punch start from EP"));
6413 Editor::set_punch_end_from_edit_point ()
6417 framepos_t start = 0;
6418 framepos_t end = max_framepos;
6420 //use the existing punch start, if any
6421 Location* tpl = transport_punch_location();
6423 start = tpl->start();
6426 if ((_edit_point == EditAtPlayhead) && _session->transport_rolling()) {
6427 end = _session->audible_frame();
6429 end = get_preferred_edit_position();
6432 //snap the selection start/end
6435 set_punch_range (start, end, _("set punch end from EP"));
6441 Editor::set_loop_start_from_edit_point ()
6445 framepos_t start = 0;
6446 framepos_t end = max_framepos;
6448 //use the existing loop end, if any
6449 Location* tpl = transport_loop_location();
6454 if ((_edit_point == EditAtPlayhead) && _session->transport_rolling()) {
6455 start = _session->audible_frame();
6457 start = get_preferred_edit_position();
6460 //snap the selection start/end
6463 //if there's not already a sensible selection endpoint, go "forever"
6464 if ( start > end ) {
6468 set_loop_range (start, end, _("set loop start from EP"));
6474 Editor::set_loop_end_from_edit_point ()
6478 framepos_t start = 0;
6479 framepos_t end = max_framepos;
6481 //use the existing loop start, if any
6482 Location* tpl = transport_loop_location();
6484 start = tpl->start();
6487 if ((_edit_point == EditAtPlayhead) && _session->transport_rolling()) {
6488 end = _session->audible_frame();
6490 end = get_preferred_edit_position();
6493 //snap the selection start/end
6496 set_loop_range (start, end, _("set loop end from EP"));
6501 Editor::set_punch_from_region ()
6503 framepos_t start, end;
6504 if (!get_selection_extents ( start, end))
6507 set_punch_range (start, end, _("set punch range from region"));
6511 Editor::pitch_shift_region ()
6513 RegionSelection rs = get_regions_from_selection_and_entered ();
6515 RegionSelection audio_rs;
6516 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
6517 if (dynamic_cast<AudioRegionView*> (*i)) {
6518 audio_rs.push_back (*i);
6522 if (audio_rs.empty()) {
6526 pitch_shift (audio_rs, 1.2);
6530 Editor::set_tempo_from_region ()
6532 RegionSelection rs = get_regions_from_selection_and_entered ();
6534 if (!_session || rs.empty()) {
6538 RegionView* rv = rs.front();
6540 define_one_bar (rv->region()->position(), rv->region()->last_frame() + 1);
6544 Editor::use_range_as_bar ()
6546 framepos_t start, end;
6547 if (get_edit_op_range (start, end)) {
6548 define_one_bar (start, end);
6553 Editor::define_one_bar (framepos_t start, framepos_t end)
6555 framepos_t length = end - start;
6557 const Meter& m (_session->tempo_map().meter_at_frame (start));
6559 /* length = 1 bar */
6561 /* We're going to deliver a constant tempo here,
6562 so we can use frames per beat to determine length.
6563 now we want frames per beat.
6564 we have frames per bar, and beats per bar, so ...
6567 /* XXXX METER MATH */
6569 double frames_per_beat = length / m.divisions_per_bar();
6571 /* beats per minute = */
6573 double beats_per_minute = (_session->frame_rate() * 60.0) / frames_per_beat;
6575 /* now decide whether to:
6577 (a) set global tempo
6578 (b) add a new tempo marker
6582 const TempoSection& t (_session->tempo_map().tempo_section_at_frame (start));
6584 bool do_global = false;
6586 if ((_session->tempo_map().n_tempos() == 1) && (_session->tempo_map().n_meters() == 1)) {
6588 /* only 1 tempo & 1 meter: ask if the user wants to set the tempo
6589 at the start, or create a new marker
6592 vector<string> options;
6593 options.push_back (_("Cancel"));
6594 options.push_back (_("Add new marker"));
6595 options.push_back (_("Set global tempo"));
6598 _("Define one bar"),
6599 _("Do you want to set the global tempo or add a new tempo marker?"),
6603 c.set_default_response (2);
6619 /* more than 1 tempo and/or meter section already, go ahead do the "usual":
6620 if the marker is at the region starter, change it, otherwise add
6625 begin_reversible_command (_("set tempo from region"));
6626 XMLNode& before (_session->tempo_map().get_state());
6629 _session->tempo_map().change_initial_tempo (beats_per_minute, t.note_type());
6630 } else if (t.frame() == start) {
6631 _session->tempo_map().change_existing_tempo_at (start, beats_per_minute, t.note_type());
6633 const Tempo tempo (beats_per_minute, t.note_type());
6634 _session->tempo_map().add_tempo (tempo, 0.0, start, TempoSection::Constant, AudioTime);
6637 XMLNode& after (_session->tempo_map().get_state());
6639 _session->add_command (new MementoCommand<TempoMap>(_session->tempo_map(), &before, &after));
6640 commit_reversible_command ();
6644 Editor::split_region_at_transients ()
6646 AnalysisFeatureList positions;
6648 RegionSelection rs = get_regions_from_selection_and_entered ();
6650 if (!_session || rs.empty()) {
6654 begin_reversible_command (_("split regions"));
6656 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ) {
6658 RegionSelection::iterator tmp;
6663 boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion> ((*i)->region());
6666 ar->transients (positions);
6667 split_region_at_points ((*i)->region(), positions, true);
6674 commit_reversible_command ();
6679 Editor::split_region_at_points (boost::shared_ptr<Region> r, AnalysisFeatureList& positions, bool can_ferret, bool select_new)
6681 bool use_rhythmic_rodent = false;
6683 boost::shared_ptr<Playlist> pl = r->playlist();
6685 list<boost::shared_ptr<Region> > new_regions;
6691 if (positions.empty()) {
6695 if (positions.size() > 20 && can_ferret) {
6696 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);
6697 MessageDialog msg (msgstr,
6700 Gtk::BUTTONS_OK_CANCEL);
6703 msg.add_button (_("Call for the Ferret!"), RESPONSE_APPLY);
6704 msg.set_secondary_text (_("Press OK to continue with this split operation\nor ask the Ferret dialog to tune the analysis"));
6706 msg.set_secondary_text (_("Press OK to continue with this split operation"));
6709 msg.set_title (_("Excessive split?"));
6712 int response = msg.run();
6718 case RESPONSE_APPLY:
6719 use_rhythmic_rodent = true;
6726 if (use_rhythmic_rodent) {
6727 show_rhythm_ferret ();
6731 AnalysisFeatureList::const_iterator x;
6733 pl->clear_changes ();
6734 pl->clear_owned_changes ();
6736 x = positions.begin();
6738 if (x == positions.end()) {
6743 pl->remove_region (r);
6747 framepos_t rstart = r->first_frame ();
6748 framepos_t rend = r->last_frame ();
6750 while (x != positions.end()) {
6752 /* deal with positons that are out of scope of present region bounds */
6753 if (*x <= rstart || *x > rend) {
6758 /* file start = original start + how far we from the initial position ? */
6760 framepos_t file_start = r->start() + pos;
6762 /* length = next position - current position */
6764 framepos_t len = (*x) - pos - rstart;
6766 /* XXX we do we really want to allow even single-sample regions?
6767 * shouldn't we have some kind of lower limit on region size?
6776 if (RegionFactory::region_name (new_name, r->name())) {
6780 /* do NOT announce new regions 1 by one, just wait till they are all done */
6784 plist.add (ARDOUR::Properties::start, file_start);
6785 plist.add (ARDOUR::Properties::length, len);
6786 plist.add (ARDOUR::Properties::name, new_name);
6787 plist.add (ARDOUR::Properties::layer, 0);
6788 // TODO set transients_offset
6790 boost::shared_ptr<Region> nr = RegionFactory::create (r->sources(), plist, false);
6791 /* because we set annouce to false, manually add the new region to the
6794 RegionFactory::map_add (nr);
6796 pl->add_region (nr, rstart + pos);
6799 new_regions.push_front(nr);
6808 RegionFactory::region_name (new_name, r->name());
6810 /* Add the final region */
6813 plist.add (ARDOUR::Properties::start, r->start() + pos);
6814 plist.add (ARDOUR::Properties::length, r->last_frame() - (r->position() + pos) + 1);
6815 plist.add (ARDOUR::Properties::name, new_name);
6816 plist.add (ARDOUR::Properties::layer, 0);
6818 boost::shared_ptr<Region> nr = RegionFactory::create (r->sources(), plist, false);
6819 /* because we set annouce to false, manually add the new region to the
6822 RegionFactory::map_add (nr);
6823 pl->add_region (nr, r->position() + pos);
6826 new_regions.push_front(nr);
6831 /* We might have removed regions, which alters other regions' layering_index,
6832 so we need to do a recursive diff here.
6834 vector<Command*> cmds;
6836 _session->add_commands (cmds);
6838 _session->add_command (new StatefulDiffCommand (pl));
6842 for (list<boost::shared_ptr<Region> >::iterator i = new_regions.begin(); i != new_regions.end(); ++i){
6843 set_selected_regionview_from_region_list ((*i), Selection::Add);
6849 Editor::place_transient()
6855 RegionSelection rs = get_regions_from_selection_and_edit_point ();
6861 framepos_t where = get_preferred_edit_position();
6863 begin_reversible_command (_("place transient"));
6865 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6866 (*r)->region()->add_transient(where);
6869 commit_reversible_command ();
6873 Editor::remove_transient(ArdourCanvas::Item* item)
6879 ArdourCanvas::Line* _line = reinterpret_cast<ArdourCanvas::Line*> (item);
6882 AudioRegionView* _arv = reinterpret_cast<AudioRegionView*> (item->get_data ("regionview"));
6883 _arv->remove_transient (*(float*) _line->get_data ("position"));
6887 Editor::snap_regions_to_grid ()
6889 list <boost::shared_ptr<Playlist > > used_playlists;
6891 RegionSelection rs = get_regions_from_selection_and_entered ();
6893 if (!_session || rs.empty()) {
6897 begin_reversible_command (_("snap regions to grid"));
6899 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6901 boost::shared_ptr<Playlist> pl = (*r)->region()->playlist();
6903 if (!pl->frozen()) {
6904 /* we haven't seen this playlist before */
6906 /* remember used playlists so we can thaw them later */
6907 used_playlists.push_back(pl);
6911 framepos_t start_frame = (*r)->region()->first_frame ();
6912 snap_to (start_frame);
6913 (*r)->region()->set_position (start_frame);
6916 while (used_playlists.size() > 0) {
6917 list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
6919 used_playlists.pop_front();
6922 commit_reversible_command ();
6926 Editor::close_region_gaps ()
6928 list <boost::shared_ptr<Playlist > > used_playlists;
6930 RegionSelection rs = get_regions_from_selection_and_entered ();
6932 if (!_session || rs.empty()) {
6936 Dialog dialog (_("Close Region Gaps"));
6939 table.set_spacings (12);
6940 table.set_border_width (12);
6941 Label* l = manage (left_aligned_label (_("Crossfade length")));
6942 table.attach (*l, 0, 1, 0, 1);
6944 SpinButton spin_crossfade (1, 0);
6945 spin_crossfade.set_range (0, 15);
6946 spin_crossfade.set_increments (1, 1);
6947 spin_crossfade.set_value (5);
6948 table.attach (spin_crossfade, 1, 2, 0, 1);
6950 table.attach (*manage (new Label (_("ms"))), 2, 3, 0, 1);
6952 l = manage (left_aligned_label (_("Pull-back length")));
6953 table.attach (*l, 0, 1, 1, 2);
6955 SpinButton spin_pullback (1, 0);
6956 spin_pullback.set_range (0, 100);
6957 spin_pullback.set_increments (1, 1);
6958 spin_pullback.set_value(30);
6959 table.attach (spin_pullback, 1, 2, 1, 2);
6961 table.attach (*manage (new Label (_("ms"))), 2, 3, 1, 2);
6963 dialog.get_vbox()->pack_start (table);
6964 dialog.add_button (Stock::CANCEL, RESPONSE_CANCEL);
6965 dialog.add_button (_("Ok"), RESPONSE_ACCEPT);
6968 if (dialog.run () == RESPONSE_CANCEL) {
6972 framepos_t crossfade_len = spin_crossfade.get_value();
6973 framepos_t pull_back_frames = spin_pullback.get_value();
6975 crossfade_len = lrintf (crossfade_len * _session->frame_rate()/1000);
6976 pull_back_frames = lrintf (pull_back_frames * _session->frame_rate()/1000);
6978 /* Iterate over the region list and make adjacent regions overlap by crossfade_len_ms */
6980 begin_reversible_command (_("close region gaps"));
6983 boost::shared_ptr<Region> last_region;
6985 rs.sort_by_position_and_track();
6987 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6989 boost::shared_ptr<Playlist> pl = (*r)->region()->playlist();
6991 if (!pl->frozen()) {
6992 /* we haven't seen this playlist before */
6994 /* remember used playlists so we can thaw them later */
6995 used_playlists.push_back(pl);
6999 framepos_t position = (*r)->region()->position();
7001 if (idx == 0 || position < last_region->position()){
7002 last_region = (*r)->region();
7007 (*r)->region()->trim_front( (position - pull_back_frames));
7008 last_region->trim_end( (position - pull_back_frames + crossfade_len));
7010 last_region = (*r)->region();
7015 while (used_playlists.size() > 0) {
7016 list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
7018 used_playlists.pop_front();
7021 commit_reversible_command ();
7025 Editor::tab_to_transient (bool forward)
7027 AnalysisFeatureList positions;
7029 RegionSelection rs = get_regions_from_selection_and_entered ();
7035 framepos_t pos = _session->audible_frame ();
7037 if (!selection->tracks.empty()) {
7039 /* don't waste time searching for transients in duplicate playlists.
7042 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
7044 for (TrackViewList::iterator t = ts.begin(); t != ts.end(); ++t) {
7046 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*t);
7049 boost::shared_ptr<Track> tr = rtv->track();
7051 boost::shared_ptr<Playlist> pl = tr->playlist ();
7053 framepos_t result = pl->find_next_transient (pos, forward ? 1 : -1);
7056 positions.push_back (result);
7069 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
7070 (*r)->region()->get_transients (positions);
7074 TransientDetector::cleanup_transients (positions, _session->frame_rate(), 3.0);
7077 AnalysisFeatureList::iterator x;
7079 for (x = positions.begin(); x != positions.end(); ++x) {
7085 if (x != positions.end ()) {
7086 _session->request_locate (*x);
7090 AnalysisFeatureList::reverse_iterator x;
7092 for (x = positions.rbegin(); x != positions.rend(); ++x) {
7098 if (x != positions.rend ()) {
7099 _session->request_locate (*x);
7105 Editor::playhead_forward_to_grid ()
7111 framepos_t pos = playhead_cursor->current_frame ();
7112 if (pos < max_framepos - 1) {
7114 snap_to_internal (pos, RoundUpAlways, false);
7115 _session->request_locate (pos);
7121 Editor::playhead_backward_to_grid ()
7127 framepos_t pos = playhead_cursor->current_frame ();
7130 snap_to_internal (pos, RoundDownAlways, false);
7131 _session->request_locate (pos);
7136 Editor::set_track_height (Height h)
7138 TrackSelection& ts (selection->tracks);
7140 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
7141 (*x)->set_height_enum (h);
7146 Editor::toggle_tracks_active ()
7148 TrackSelection& ts (selection->tracks);
7150 bool target = false;
7156 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
7157 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*x);
7161 target = !rtv->_route->active();
7164 rtv->_route->set_active (target, this);
7170 Editor::remove_tracks ()
7172 /* this will delete GUI objects that may be the subject of an event
7173 handler in which this method is called. Defer actual deletion to the
7174 next idle callback, when all event handling is finished.
7176 Glib::signal_idle().connect (sigc::mem_fun (*this, &Editor::idle_remove_tracks));
7180 Editor::idle_remove_tracks ()
7182 Session::StateProtector sp (_session);
7184 return false; /* do not call again */
7188 Editor::_remove_tracks ()
7190 TrackSelection& ts (selection->tracks);
7196 vector<string> choices;
7200 const char* trackstr;
7202 vector<boost::shared_ptr<Route> > routes;
7203 bool special_bus = false;
7205 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
7206 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*x);
7210 if (rtv->is_track()) {
7215 routes.push_back (rtv->_route);
7217 if (rtv->route()->is_master() || rtv->route()->is_monitor()) {
7222 if (special_bus && !Config->get_allow_special_bus_removal()) {
7223 MessageDialog msg (_("That would be bad news ...."),
7227 msg.set_secondary_text (string_compose (_(
7228 "Removing the master or monitor bus is such a bad idea\n\
7229 that %1 is not going to allow it.\n\
7231 If you really want to do this sort of thing\n\
7232 edit your ardour.rc file to set the\n\
7233 \"allow-special-bus-removal\" option to be \"yes\""), PROGRAM_NAME));
7240 if (ntracks + nbusses == 0) {
7244 trackstr = P_("track", "tracks", ntracks);
7245 busstr = P_("bus", "busses", nbusses);
7249 prompt = string_compose (_("Do you really want to remove %1 %2 and %3 %4?\n"
7250 "(You may also lose the playlists associated with the %2)\n\n"
7251 "This action cannot be undone, and the session file will be overwritten!"),
7252 ntracks, trackstr, nbusses, busstr);
7254 prompt = string_compose (_("Do you really want to remove %1 %2?\n"
7255 "(You may also lose the playlists associated with the %2)\n\n"
7256 "This action cannot be undone, and the session file will be overwritten!"),
7259 } else if (nbusses) {
7260 prompt = string_compose (_("Do you really want to remove %1 %2?\n\n"
7261 "This action cannot be undone, and the session file will be overwritten"),
7265 choices.push_back (_("No, do nothing."));
7266 if (ntracks + nbusses > 1) {
7267 choices.push_back (_("Yes, remove them."));
7269 choices.push_back (_("Yes, remove it."));
7274 title = string_compose (_("Remove %1"), trackstr);
7276 title = string_compose (_("Remove %1"), busstr);
7279 Choice prompter (title, prompt, choices);
7281 if (prompter.run () != 1) {
7286 DisplaySuspender ds;
7287 boost::shared_ptr<RouteList> rl (new RouteList);
7288 for (vector<boost::shared_ptr<Route> >::iterator x = routes.begin(); x != routes.end(); ++x) {
7291 _session->remove_routes (rl);
7293 /* TrackSelection and RouteList leave scope,
7294 * destructors are called,
7295 * diskstream drops references, save_state is called (again for every track)
7300 Editor::do_insert_time ()
7302 if (selection->tracks.empty()) {
7306 InsertRemoveTimeDialog d (*this);
7307 int response = d.run ();
7309 if (response != RESPONSE_OK) {
7313 if (d.distance() == 0) {
7318 get_preferred_edit_position (EDIT_IGNORE_MOUSE),
7320 d.intersected_region_action (),
7324 d.move_glued_markers(),
7325 d.move_locked_markers(),
7331 Editor::insert_time (
7332 framepos_t pos, framecnt_t frames, InsertTimeOption opt,
7333 bool all_playlists, bool ignore_music_glue, bool markers_too, bool glued_markers_too, bool locked_markers_too, bool tempo_too
7337 if (Config->get_edit_mode() == Lock) {
7340 bool in_command = false;
7342 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
7344 for (TrackViewList::iterator x = ts.begin(); x != ts.end(); ++x) {
7348 /* don't operate on any playlist more than once, which could
7349 * happen if "all playlists" is enabled, but there is more
7350 * than 1 track using playlists "from" a given track.
7353 set<boost::shared_ptr<Playlist> > pl;
7355 if (all_playlists) {
7356 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*x);
7357 if (rtav && rtav->track ()) {
7358 vector<boost::shared_ptr<Playlist> > all = _session->playlists->playlists_for_track (rtav->track ());
7359 for (vector<boost::shared_ptr<Playlist> >::iterator p = all.begin(); p != all.end(); ++p) {
7364 if ((*x)->playlist ()) {
7365 pl.insert ((*x)->playlist ());
7369 for (set<boost::shared_ptr<Playlist> >::iterator i = pl.begin(); i != pl.end(); ++i) {
7371 (*i)->clear_changes ();
7372 (*i)->clear_owned_changes ();
7374 if (opt == SplitIntersected) {
7375 /* non musical split */
7376 (*i)->split (pos, 0);
7379 (*i)->shift (pos, frames, (opt == MoveIntersected), ignore_music_glue);
7382 begin_reversible_command (_("insert time"));
7385 vector<Command*> cmds;
7387 _session->add_commands (cmds);
7389 _session->add_command (new StatefulDiffCommand (*i));
7393 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*x);
7396 begin_reversible_command (_("insert time"));
7399 rtav->route ()->shift (pos, frames);
7406 XMLNode& before (_session->locations()->get_state());
7407 Locations::LocationList copy (_session->locations()->list());
7409 for (Locations::LocationList::iterator i = copy.begin(); i != copy.end(); ++i) {
7411 Locations::LocationList::const_iterator tmp;
7413 if ((*i)->position_lock_style() == AudioTime || glued_markers_too) {
7414 bool const was_locked = (*i)->locked ();
7415 if (locked_markers_too) {
7419 if ((*i)->start() >= pos) {
7420 // move end first, in case we're moving by more than the length of the range
7421 if (!(*i)->is_mark()) {
7422 (*i)->set_end ((*i)->end() + frames);
7424 (*i)->set_start ((*i)->start() + frames);
7436 begin_reversible_command (_("insert time"));
7439 XMLNode& after (_session->locations()->get_state());
7440 _session->add_command (new MementoCommand<Locations>(*_session->locations(), &before, &after));
7446 begin_reversible_command (_("insert time"));
7449 XMLNode& before (_session->tempo_map().get_state());
7450 _session->tempo_map().insert_time (pos, frames);
7451 XMLNode& after (_session->tempo_map().get_state());
7452 _session->add_command (new MementoCommand<TempoMap>(_session->tempo_map(), &before, &after));
7456 commit_reversible_command ();
7461 Editor::do_remove_time ()
7463 if (selection->tracks.empty()) {
7467 framepos_t pos = get_preferred_edit_position (EDIT_IGNORE_MOUSE);
7468 InsertRemoveTimeDialog d (*this, true);
7470 int response = d.run ();
7472 if (response != RESPONSE_OK) {
7476 framecnt_t distance = d.distance();
7478 if (distance == 0) {
7488 d.move_glued_markers(),
7489 d.move_locked_markers(),
7495 Editor::remove_time (framepos_t pos, framecnt_t frames, InsertTimeOption opt,
7496 bool ignore_music_glue, bool markers_too, bool glued_markers_too, bool locked_markers_too, bool tempo_too)
7498 if (Config->get_edit_mode() == Lock) {
7499 error << (_("Cannot insert or delete time when in Lock edit.")) << endmsg;
7502 bool in_command = false;
7504 for (TrackSelection::iterator x = selection->tracks.begin(); x != selection->tracks.end(); ++x) {
7506 boost::shared_ptr<Playlist> pl = (*x)->playlist();
7510 XMLNode &before = pl->get_state();
7512 std::list<AudioRange> rl;
7513 AudioRange ar(pos, pos+frames, 0);
7516 pl->shift (pos, -frames, true, ignore_music_glue);
7519 begin_reversible_command (_("remove time"));
7522 XMLNode &after = pl->get_state();
7524 _session->add_command (new MementoCommand<Playlist> (*pl, &before, &after));
7528 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*x);
7531 begin_reversible_command (_("remove time"));
7534 rtav->route ()->shift (pos, -frames);
7538 std::list<Location*> loc_kill_list;
7543 XMLNode& before (_session->locations()->get_state());
7544 Locations::LocationList copy (_session->locations()->list());
7546 for (Locations::LocationList::iterator i = copy.begin(); i != copy.end(); ++i) {
7547 if ((*i)->position_lock_style() == AudioTime || glued_markers_too) {
7549 bool const was_locked = (*i)->locked ();
7550 if (locked_markers_too) {
7554 if (!(*i)->is_mark()) { // it's a range; have to handle both start and end
7555 if ((*i)->end() >= pos
7556 && (*i)->end() < pos+frames
7557 && (*i)->start() >= pos
7558 && (*i)->end() < pos+frames) { // range is completely enclosed; kill it
7560 loc_kill_list.push_back(*i);
7561 } else { // only start or end is included, try to do the right thing
7562 // move start before moving end, to avoid trying to move the end to before the start
7563 // if we're removing more time than the length of the range
7564 if ((*i)->start() >= pos && (*i)->start() < pos+frames) {
7565 // start is within cut
7566 (*i)->set_start (pos); // bring the start marker to the beginning of the cut
7568 } else if ((*i)->start() >= pos+frames) {
7569 // start (and thus entire range) lies beyond end of cut
7570 (*i)->set_start ((*i)->start() - frames); // slip the start marker back
7573 if ((*i)->end() >= pos && (*i)->end() < pos+frames) {
7574 // end is inside cut
7575 (*i)->set_end (pos); // bring the end to the cut
7577 } else if ((*i)->end() >= pos+frames) {
7578 // end is beyond end of cut
7579 (*i)->set_end ((*i)->end() - frames); // slip the end marker back
7584 } else if ((*i)->start() >= pos && (*i)->start() < pos+frames ) {
7585 loc_kill_list.push_back(*i);
7587 } else if ((*i)->start() >= pos) {
7588 (*i)->set_start ((*i)->start() -frames);
7598 for (list<Location*>::iterator i = loc_kill_list.begin(); i != loc_kill_list.end(); ++i) {
7599 _session->locations()->remove( *i );
7604 begin_reversible_command (_("remove time"));
7607 XMLNode& after (_session->locations()->get_state());
7608 _session->add_command (new MementoCommand<Locations>(*_session->locations(), &before, &after));
7613 XMLNode& before (_session->tempo_map().get_state());
7615 if (_session->tempo_map().remove_time (pos, frames) ) {
7617 begin_reversible_command (_("remove time"));
7620 XMLNode& after (_session->tempo_map().get_state());
7621 _session->add_command (new MementoCommand<TempoMap>(_session->tempo_map(), &before, &after));
7626 commit_reversible_command ();
7631 Editor::fit_selection ()
7633 if (!selection->tracks.empty()) {
7634 fit_tracks (selection->tracks);
7638 /* no selected tracks - use tracks with selected regions */
7640 if (!selection->regions.empty()) {
7641 for (RegionSelection::iterator r = selection->regions.begin(); r != selection->regions.end(); ++r) {
7642 tvl.push_back (&(*r)->get_time_axis_view ());
7648 } else if (internal_editing()) {
7649 /* no selected tracks, or regions, but in internal edit mode, so follow the mouse and use
7652 if (entered_track) {
7653 tvl.push_back (entered_track);
7662 Editor::fit_tracks (TrackViewList & tracks)
7664 if (tracks.empty()) {
7668 uint32_t child_heights = 0;
7669 int visible_tracks = 0;
7671 for (TrackSelection::iterator t = tracks.begin(); t != tracks.end(); ++t) {
7673 if (!(*t)->marked_for_display()) {
7677 child_heights += (*t)->effective_height() - (*t)->current_height();
7681 /* compute the per-track height from:
7683 total canvas visible height -
7684 height that will be taken by visible children of selected
7685 tracks - height of the ruler/hscroll area
7687 uint32_t h = (uint32_t) floor ((trackviews_height() - child_heights) / visible_tracks);
7688 double first_y_pos = DBL_MAX;
7690 if (h < TimeAxisView::preset_height (HeightSmall)) {
7691 MessageDialog msg (_("There are too many tracks to fit in the current window"));
7692 /* too small to be displayed */
7696 undo_visual_stack.push_back (current_visual_state (true));
7697 PBD::Unwinder<bool> nsv (no_save_visual, true);
7699 /* build a list of all tracks, including children */
7702 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
7704 TimeAxisView::Children c = (*i)->get_child_list ();
7705 for (TimeAxisView::Children::iterator j = c.begin(); j != c.end(); ++j) {
7706 all.push_back (j->get());
7711 // find selection range.
7712 // if someone knows how to user TrackViewList::iterator for this
7714 int selected_top = -1;
7715 int selected_bottom = -1;
7717 for (TrackViewList::iterator t = all.begin(); t != all.end(); ++t, ++i) {
7718 if ((*t)->marked_for_display ()) {
7719 if (tracks.contains(*t)) {
7720 if (selected_top == -1) {
7723 selected_bottom = i;
7729 for (TrackViewList::iterator t = all.begin(); t != all.end(); ++t, ++i) {
7730 if ((*t)->marked_for_display ()) {
7731 if (tracks.contains(*t)) {
7732 (*t)->set_height (h);
7733 first_y_pos = std::min ((*t)->y_position (), first_y_pos);
7735 if (i > selected_top && i < selected_bottom) {
7736 hide_track_in_display (*t);
7743 set the controls_layout height now, because waiting for its size
7744 request signal handler will cause the vertical adjustment setting to fail
7747 controls_layout.property_height () = _full_canvas_height;
7748 vertical_adjustment.set_value (first_y_pos);
7750 redo_visual_stack.push_back (current_visual_state (true));
7752 visible_tracks_selector.set_text (_("Sel"));
7756 Editor::save_visual_state (uint32_t n)
7758 while (visual_states.size() <= n) {
7759 visual_states.push_back (0);
7762 if (visual_states[n] != 0) {
7763 delete visual_states[n];
7766 visual_states[n] = current_visual_state (true);
7771 Editor::goto_visual_state (uint32_t n)
7773 if (visual_states.size() <= n) {
7777 if (visual_states[n] == 0) {
7781 use_visual_state (*visual_states[n]);
7785 Editor::start_visual_state_op (uint32_t n)
7787 save_visual_state (n);
7789 PopUp* pup = new PopUp (WIN_POS_MOUSE, 1000, true);
7791 snprintf (buf, sizeof (buf), _("Saved view %u"), n+1);
7792 pup->set_text (buf);
7797 Editor::cancel_visual_state_op (uint32_t n)
7799 goto_visual_state (n);
7803 Editor::toggle_region_mute ()
7805 if (_ignore_region_action) {
7809 RegionSelection rs = get_regions_from_selection_and_entered ();
7815 if (rs.size() > 1) {
7816 begin_reversible_command (_("mute regions"));
7818 begin_reversible_command (_("mute region"));
7821 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
7823 (*i)->region()->playlist()->clear_changes ();
7824 (*i)->region()->set_muted (!(*i)->region()->muted ());
7825 _session->add_command (new StatefulDiffCommand ((*i)->region()));
7829 commit_reversible_command ();
7833 Editor::combine_regions ()
7835 /* foreach track with selected regions, take all selected regions
7836 and join them into a new region containing the subregions (as a
7840 typedef set<RouteTimeAxisView*> RTVS;
7843 if (selection->regions.empty()) {
7847 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
7848 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(&(*i)->get_time_axis_view());
7851 tracks.insert (rtv);
7855 begin_reversible_command (_("combine regions"));
7857 vector<RegionView*> new_selection;
7859 for (RTVS::iterator i = tracks.begin(); i != tracks.end(); ++i) {
7862 if ((rv = (*i)->combine_regions ()) != 0) {
7863 new_selection.push_back (rv);
7867 selection->clear_regions ();
7868 for (vector<RegionView*>::iterator i = new_selection.begin(); i != new_selection.end(); ++i) {
7869 selection->add (*i);
7872 commit_reversible_command ();
7876 Editor::uncombine_regions ()
7878 typedef set<RouteTimeAxisView*> RTVS;
7881 if (selection->regions.empty()) {
7885 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
7886 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(&(*i)->get_time_axis_view());
7889 tracks.insert (rtv);
7893 begin_reversible_command (_("uncombine regions"));
7895 for (RTVS::iterator i = tracks.begin(); i != tracks.end(); ++i) {
7896 (*i)->uncombine_regions ();
7899 commit_reversible_command ();
7903 Editor::toggle_midi_input_active (bool flip_others)
7906 boost::shared_ptr<RouteList> rl (new RouteList);
7908 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
7909 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
7915 boost::shared_ptr<MidiTrack> mt = rtav->midi_track();
7918 rl->push_back (rtav->route());
7919 onoff = !mt->input_active();
7923 _session->set_exclusive_input_active (rl, onoff, flip_others);
7930 lock_dialog = new Gtk::Dialog (string_compose (_("%1: Locked"), PROGRAM_NAME), true);
7932 Gtk::Image* padlock = manage (new Gtk::Image (ARDOUR_UI_UTILS::get_icon ("padlock_closed")));
7933 lock_dialog->get_vbox()->pack_start (*padlock);
7935 ArdourButton* b = manage (new ArdourButton);
7936 b->set_name ("lock button");
7937 b->set_text (_("Click to unlock"));
7938 b->signal_clicked.connect (sigc::mem_fun (*this, &Editor::unlock));
7939 lock_dialog->get_vbox()->pack_start (*b);
7941 lock_dialog->get_vbox()->show_all ();
7942 lock_dialog->set_size_request (200, 200);
7945 delete _main_menu_disabler;
7946 _main_menu_disabler = new MainMenuDisabler;
7948 lock_dialog->present ();
7954 lock_dialog->hide ();
7956 delete _main_menu_disabler;
7957 _main_menu_disabler = 0;
7959 if (UIConfiguration::instance().get_lock_gui_after_seconds()) {
7960 start_lock_event_timing ();
7965 Editor::bring_in_callback (Gtk::Label* label, uint32_t n, uint32_t total, string name)
7967 Gtkmm2ext::UI::instance()->call_slot (invalidator (*this), boost::bind (&Editor::update_bring_in_message, this, label, n, total, name));
7971 Editor::update_bring_in_message (Gtk::Label* label, uint32_t n, uint32_t total, string name)
7973 Timers::TimerSuspender t;
7974 label->set_text (string_compose ("Copying %1, %2 of %3", name, n, total));
7975 Gtkmm2ext::UI::instance()->flush_pending (1);
7979 Editor::bring_all_sources_into_session ()
7986 ArdourDialog w (_("Moving embedded files into session folder"));
7987 w.get_vbox()->pack_start (msg);
7990 /* flush all pending GUI events because we're about to start copying
7994 Timers::TimerSuspender t;
7995 Gtkmm2ext::UI::instance()->flush_pending (3);
7999 _session->bring_all_sources_into_session (boost::bind (&Editor::bring_in_callback, this, &msg, _1, _2, _3));