2 Copyright (C) 2000-2004 Paul Davis
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 /* Note: public Editor methods are documented in public_editor.h */
31 #include "pbd/error.h"
32 #include "pbd/basename.h"
33 #include "pbd/pthread_utils.h"
34 #include "pbd/memento_command.h"
35 #include "pbd/unwind.h"
36 #include "pbd/whitespace.h"
37 #include "pbd/stateful_diff_command.h"
39 #include <gtkmm2ext/utils.h>
40 #include <gtkmm2ext/choice.h>
41 #include <gtkmm2ext/popup.h>
43 #include "ardour/audio_track.h"
44 #include "ardour/audioregion.h"
45 #include "ardour/boost_debug.h"
46 #include "ardour/dB.h"
47 #include "ardour/location.h"
48 #include "ardour/midi_region.h"
49 #include "ardour/midi_track.h"
50 #include "ardour/operations.h"
51 #include "ardour/playlist_factory.h"
52 #include "ardour/profile.h"
53 #include "ardour/quantize.h"
54 #include "ardour/legatize.h"
55 #include "ardour/region_factory.h"
56 #include "ardour/reverse.h"
57 #include "ardour/session.h"
58 #include "ardour/session_playlists.h"
59 #include "ardour/strip_silence.h"
60 #include "ardour/transient_detector.h"
61 #include "ardour/transpose.h"
63 #include "canvas/canvas.h"
66 #include "audio_region_view.h"
67 #include "audio_streamview.h"
68 #include "audio_time_axis.h"
69 #include "automation_region_view.h"
70 #include "automation_time_axis.h"
71 #include "control_point.h"
75 #include "editor_cursors.h"
76 #include "editor_drag.h"
77 #include "editor_regions.h"
78 #include "editor_routes.h"
79 #include "gui_thread.h"
80 #include "insert_remove_time_dialog.h"
81 #include "interthread_progress_window.h"
82 #include "item_counts.h"
84 #include "midi_region_view.h"
85 #include "mixer_strip.h"
86 #include "mouse_cursors.h"
87 #include "normalize_dialog.h"
89 #include "paste_context.h"
90 #include "patch_change_dialog.h"
91 #include "quantize_dialog.h"
92 #include "region_gain_line.h"
93 #include "rgb_macros.h"
94 #include "route_time_axis.h"
95 #include "selection.h"
96 #include "selection_templates.h"
97 #include "streamview.h"
98 #include "strip_silence_dialog.h"
99 #include "time_axis_view.h"
101 #include "transpose_dialog.h"
102 #include "transform_dialog.h"
103 #include "ui_config.h"
105 #include "pbd/i18n.h"
108 using namespace ARDOUR;
111 using namespace Gtkmm2ext;
112 using namespace Editing;
113 using Gtkmm2ext::Keyboard;
115 /***********************************************************************
117 ***********************************************************************/
120 Editor::undo (uint32_t n)
122 if (_drags->active ()) {
128 if (_session->undo_depth() == 0) {
129 undo_action->set_sensitive(false);
131 redo_action->set_sensitive(true);
132 begin_selection_op_history ();
137 Editor::redo (uint32_t n)
139 if (_drags->active ()) {
145 if (_session->redo_depth() == 0) {
146 redo_action->set_sensitive(false);
148 undo_action->set_sensitive(true);
149 begin_selection_op_history ();
154 Editor::split_regions_at (framepos_t where, RegionSelection& regions, const int32_t sub_num)
158 RegionSelection pre_selected_regions = selection->regions;
159 bool working_on_selection = !pre_selected_regions.empty();
161 list<boost::shared_ptr<Playlist> > used_playlists;
162 list<RouteTimeAxisView*> used_trackviews;
164 if (regions.empty()) {
168 begin_reversible_command (_("split"));
170 // if splitting a single region, and snap-to is using
171 // region boundaries, don't pay attention to them
173 if (regions.size() == 1) {
174 switch (_snap_type) {
175 case SnapToRegionStart:
176 case SnapToRegionSync:
177 case SnapToRegionEnd:
186 EditorFreeze(); /* Emit Signal */
189 for (RegionSelection::iterator a = regions.begin(); a != regions.end(); ) {
191 RegionSelection::iterator tmp;
193 /* XXX this test needs to be more complicated, to make sure we really
194 have something to split.
197 if (!(*a)->region()->covers (where)) {
205 boost::shared_ptr<Playlist> pl = (*a)->region()->playlist();
213 /* we haven't seen this playlist before */
215 /* remember used playlists so we can thaw them later */
216 used_playlists.push_back(pl);
218 TimeAxisView& tv = (*a)->get_time_axis_view();
219 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (&tv);
221 used_trackviews.push_back (rtv);
228 pl->clear_changes ();
229 pl->split_region ((*a)->region(), where, sub_num);
230 _session->add_command (new StatefulDiffCommand (pl));
236 latest_regionviews.clear ();
238 vector<sigc::connection> region_added_connections;
240 for (list<RouteTimeAxisView*>::iterator i = used_trackviews.begin(); i != used_trackviews.end(); ++i) {
241 region_added_connections.push_back ((*i)->view()->RegionViewAdded.connect (sigc::mem_fun(*this, &Editor::collect_new_region_view)));
244 while (used_playlists.size() > 0) {
245 list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
247 used_playlists.pop_front();
250 for (vector<sigc::connection>::iterator c = region_added_connections.begin(); c != region_added_connections.end(); ++c) {
255 EditorThaw(); /* Emit Signal */
258 if (working_on_selection) {
259 // IFF we were working on selected regions, try to reinstate the other region selections that existed before the freeze/thaw.
261 _ignore_follow_edits = true; // a split will change the region selection in mysterious ways; it's not practical or wanted to follow this edit
262 RegionSelectionAfterSplit rsas = Config->get_region_selection_after_split();
263 /* There are three classes of regions that we might want selected after
264 splitting selected regions:
265 - regions selected before the split operation, and unaffected by it
266 - newly-created regions before the split
267 - newly-created regions after the split
270 if (rsas & Existing) {
271 // region selections that existed before the split.
272 selection->add ( pre_selected_regions );
275 for (RegionSelection::iterator ri = latest_regionviews.begin(); ri != latest_regionviews.end(); ri++) {
276 if ((*ri)->region()->position() < where) {
277 // new regions created before the split
278 if (rsas & NewlyCreatedLeft) {
279 selection->add (*ri);
282 // new regions created after the split
283 if (rsas & NewlyCreatedRight) {
284 selection->add (*ri);
288 _ignore_follow_edits = false;
290 _ignore_follow_edits = true;
291 if( working_on_selection ) {
292 selection->add (latest_regionviews); //these are the new regions created after the split
294 _ignore_follow_edits = false;
297 commit_reversible_command ();
300 /** Move one extreme of the current range selection. If more than one range is selected,
301 * the start of the earliest range or the end of the latest range is moved.
303 * @param move_end true to move the end of the current range selection, false to move
305 * @param next true to move the extreme to the next region boundary, false to move to
309 Editor::move_range_selection_start_or_end_to_region_boundary (bool move_end, bool next)
311 if (selection->time.start() == selection->time.end_frame()) {
315 framepos_t start = selection->time.start ();
316 framepos_t end = selection->time.end_frame ();
318 /* the position of the thing we may move */
319 framepos_t pos = move_end ? end : start;
320 int dir = next ? 1 : -1;
322 /* so we don't find the current region again */
323 if (dir > 0 || pos > 0) {
327 framepos_t const target = get_region_boundary (pos, dir, true, false);
342 begin_reversible_selection_op (_("alter selection"));
343 selection->set_preserving_all_ranges (start, end);
344 commit_reversible_selection_op ();
348 Editor::nudge_forward_release (GdkEventButton* ev)
350 if (ev->state & Keyboard::PrimaryModifier) {
351 nudge_forward (false, true);
353 nudge_forward (false, false);
359 Editor::nudge_backward_release (GdkEventButton* ev)
361 if (ev->state & Keyboard::PrimaryModifier) {
362 nudge_backward (false, true);
364 nudge_backward (false, false);
371 Editor::nudge_forward (bool next, bool force_playhead)
374 framepos_t next_distance;
380 RegionSelection rs = get_regions_from_selection_and_entered ();
382 if (!force_playhead && !rs.empty()) {
384 begin_reversible_command (_("nudge regions forward"));
386 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
387 boost::shared_ptr<Region> r ((*i)->region());
389 distance = get_nudge_distance (r->position(), next_distance);
392 distance = next_distance;
396 r->set_position (r->position() + distance);
397 _session->add_command (new StatefulDiffCommand (r));
400 commit_reversible_command ();
403 } else if (!force_playhead && !selection->markers.empty()) {
406 bool in_command = false;
408 for (MarkerSelection::iterator i = selection->markers.begin(); i != selection->markers.end(); ++i) {
410 Location* loc = find_location_from_marker ((*i), is_start);
414 XMLNode& before (loc->get_state());
417 distance = get_nudge_distance (loc->start(), next_distance);
419 distance = next_distance;
421 if (max_framepos - distance > loc->start() + loc->length()) {
422 loc->set_start (loc->start() + distance);
424 loc->set_start (max_framepos - loc->length());
427 distance = get_nudge_distance (loc->end(), next_distance);
429 distance = next_distance;
431 if (max_framepos - distance > loc->end()) {
432 loc->set_end (loc->end() + distance);
434 loc->set_end (max_framepos);
436 if (loc->is_session_range()) {
437 _session->set_end_is_free (false);
441 begin_reversible_command (_("nudge location forward"));
444 XMLNode& after (loc->get_state());
445 _session->add_command (new MementoCommand<Location>(*loc, &before, &after));
450 commit_reversible_command ();
453 distance = get_nudge_distance (playhead_cursor->current_frame (), next_distance);
454 _session->request_locate (playhead_cursor->current_frame () + distance);
459 Editor::nudge_backward (bool next, bool force_playhead)
462 framepos_t next_distance;
468 RegionSelection rs = get_regions_from_selection_and_entered ();
470 if (!force_playhead && !rs.empty()) {
472 begin_reversible_command (_("nudge regions backward"));
474 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
475 boost::shared_ptr<Region> r ((*i)->region());
477 distance = get_nudge_distance (r->position(), next_distance);
480 distance = next_distance;
485 if (r->position() > distance) {
486 r->set_position (r->position() - distance);
490 _session->add_command (new StatefulDiffCommand (r));
493 commit_reversible_command ();
495 } else if (!force_playhead && !selection->markers.empty()) {
498 bool in_command = false;
500 for (MarkerSelection::iterator i = selection->markers.begin(); i != selection->markers.end(); ++i) {
502 Location* loc = find_location_from_marker ((*i), is_start);
506 XMLNode& before (loc->get_state());
509 distance = get_nudge_distance (loc->start(), next_distance);
511 distance = next_distance;
513 if (distance < loc->start()) {
514 loc->set_start (loc->start() - distance);
519 distance = get_nudge_distance (loc->end(), next_distance);
522 distance = next_distance;
525 if (distance < loc->end() - loc->length()) {
526 loc->set_end (loc->end() - distance);
528 loc->set_end (loc->length());
530 if (loc->is_session_range()) {
531 _session->set_end_is_free (false);
535 begin_reversible_command (_("nudge location forward"));
538 XMLNode& after (loc->get_state());
539 _session->add_command (new MementoCommand<Location>(*loc, &before, &after));
543 commit_reversible_command ();
548 distance = get_nudge_distance (playhead_cursor->current_frame (), next_distance);
550 if (playhead_cursor->current_frame () > distance) {
551 _session->request_locate (playhead_cursor->current_frame () - distance);
553 _session->goto_start();
559 Editor::nudge_forward_capture_offset ()
561 RegionSelection rs = get_regions_from_selection_and_entered ();
563 if (!_session || rs.empty()) {
567 begin_reversible_command (_("nudge forward"));
569 framepos_t const distance = _session->worst_output_latency();
571 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
572 boost::shared_ptr<Region> r ((*i)->region());
575 r->set_position (r->position() + distance);
576 _session->add_command(new StatefulDiffCommand (r));
579 commit_reversible_command ();
583 Editor::nudge_backward_capture_offset ()
585 RegionSelection rs = get_regions_from_selection_and_entered ();
587 if (!_session || rs.empty()) {
591 begin_reversible_command (_("nudge backward"));
593 framepos_t const distance = _session->worst_output_latency();
595 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
596 boost::shared_ptr<Region> r ((*i)->region());
600 if (r->position() > distance) {
601 r->set_position (r->position() - distance);
605 _session->add_command(new StatefulDiffCommand (r));
608 commit_reversible_command ();
611 struct RegionSelectionPositionSorter {
612 bool operator() (RegionView* a, RegionView* b) {
613 return a->region()->position() < b->region()->position();
618 Editor::sequence_regions ()
621 framepos_t r_end_prev;
629 RegionSelection rs = get_regions_from_selection_and_entered ();
630 rs.sort(RegionSelectionPositionSorter());
634 bool in_command = false;
636 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
637 boost::shared_ptr<Region> r ((*i)->region());
645 if(r->position_locked())
652 r->set_position(r_end_prev);
656 begin_reversible_command (_("sequence regions"));
659 _session->add_command (new StatefulDiffCommand (r));
661 r_end=r->position() + r->length();
667 commit_reversible_command ();
676 Editor::move_to_start ()
678 _session->goto_start ();
682 Editor::move_to_end ()
685 _session->request_locate (_session->current_end_frame());
689 Editor::build_region_boundary_cache ()
692 vector<RegionPoint> interesting_points;
693 boost::shared_ptr<Region> r;
694 TrackViewList tracks;
697 region_boundary_cache.clear ();
703 switch (_snap_type) {
704 case SnapToRegionStart:
705 interesting_points.push_back (Start);
707 case SnapToRegionEnd:
708 interesting_points.push_back (End);
710 case SnapToRegionSync:
711 interesting_points.push_back (SyncPoint);
713 case SnapToRegionBoundary:
714 interesting_points.push_back (Start);
715 interesting_points.push_back (End);
718 fatal << string_compose (_("build_region_boundary_cache called with snap_type = %1"), _snap_type) << endmsg;
719 abort(); /*NOTREACHED*/
723 TimeAxisView *ontrack = 0;
726 if (!selection->tracks.empty()) {
727 tlist = selection->tracks.filter_to_unique_playlists ();
729 tlist = track_views.filter_to_unique_playlists ();
732 while (pos < _session->current_end_frame() && !at_end) {
735 framepos_t lpos = max_framepos;
737 for (vector<RegionPoint>::iterator p = interesting_points.begin(); p != interesting_points.end(); ++p) {
739 if ((r = find_next_region (pos, *p, 1, tlist, &ontrack)) == 0) {
740 if (*p == interesting_points.back()) {
743 /* move to next point type */
749 rpos = r->first_frame();
753 rpos = r->last_frame();
757 rpos = r->sync_position ();
765 RouteTimeAxisView *rtav;
767 if (ontrack != 0 && (rtav = dynamic_cast<RouteTimeAxisView*>(ontrack)) != 0 ) {
768 if (rtav->track() != 0) {
769 speed = rtav->track()->speed();
773 rpos = track_frame_to_session_frame (rpos, speed);
779 /* prevent duplicates, but we don't use set<> because we want to be able
783 vector<framepos_t>::iterator ri;
785 for (ri = region_boundary_cache.begin(); ri != region_boundary_cache.end(); ++ri) {
791 if (ri == region_boundary_cache.end()) {
792 region_boundary_cache.push_back (rpos);
799 /* finally sort to be sure that the order is correct */
801 sort (region_boundary_cache.begin(), region_boundary_cache.end());
804 boost::shared_ptr<Region>
805 Editor::find_next_region (framepos_t frame, RegionPoint point, int32_t dir, TrackViewList& tracks, TimeAxisView **ontrack)
807 TrackViewList::iterator i;
808 framepos_t closest = max_framepos;
809 boost::shared_ptr<Region> ret;
813 framepos_t track_frame;
814 RouteTimeAxisView *rtav;
816 for (i = tracks.begin(); i != tracks.end(); ++i) {
819 boost::shared_ptr<Region> r;
822 if ( (rtav = dynamic_cast<RouteTimeAxisView*>(*i)) != 0 ) {
823 if (rtav->track()!=0)
824 track_speed = rtav->track()->speed();
827 track_frame = session_frame_to_track_frame(frame, track_speed);
829 if ((r = (*i)->find_next_region (track_frame, point, dir)) == 0) {
835 rpos = r->first_frame ();
839 rpos = r->last_frame ();
843 rpos = r->sync_position ();
847 // rpos is a "track frame", converting it to "_session frame"
848 rpos = track_frame_to_session_frame(rpos, track_speed);
851 distance = rpos - frame;
853 distance = frame - rpos;
856 if (distance < closest) {
868 Editor::find_next_region_boundary (framepos_t pos, int32_t dir, const TrackViewList& tracks)
870 framecnt_t distance = max_framepos;
871 framepos_t current_nearest = -1;
873 for (TrackViewList::const_iterator i = tracks.begin(); i != tracks.end(); ++i) {
874 framepos_t contender;
877 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*i);
883 if ((contender = rtv->find_next_region_boundary (pos, dir)) < 0) {
887 d = ::llabs (pos - contender);
890 current_nearest = contender;
895 return current_nearest;
899 Editor::get_region_boundary (framepos_t pos, int32_t dir, bool with_selection, bool only_onscreen)
904 if (with_selection && Config->get_region_boundaries_from_selected_tracks()) {
906 if (!selection->tracks.empty()) {
908 target = find_next_region_boundary (pos, dir, selection->tracks);
912 if (only_onscreen || Config->get_region_boundaries_from_onscreen_tracks()) {
913 get_onscreen_tracks (tvl);
914 target = find_next_region_boundary (pos, dir, tvl);
916 target = find_next_region_boundary (pos, dir, track_views);
922 if (only_onscreen || Config->get_region_boundaries_from_onscreen_tracks()) {
923 get_onscreen_tracks (tvl);
924 target = find_next_region_boundary (pos, dir, tvl);
926 target = find_next_region_boundary (pos, dir, track_views);
934 Editor::cursor_to_region_boundary (bool with_selection, int32_t dir)
936 framepos_t pos = playhead_cursor->current_frame ();
943 // so we don't find the current region again..
944 if (dir > 0 || pos > 0) {
948 if ((target = get_region_boundary (pos, dir, with_selection, false)) < 0) {
952 _session->request_locate (target);
956 Editor::cursor_to_next_region_boundary (bool with_selection)
958 cursor_to_region_boundary (with_selection, 1);
962 Editor::cursor_to_previous_region_boundary (bool with_selection)
964 cursor_to_region_boundary (with_selection, -1);
968 Editor::cursor_to_region_point (EditorCursor* cursor, RegionPoint point, int32_t dir)
970 boost::shared_ptr<Region> r;
971 framepos_t pos = cursor->current_frame ();
977 TimeAxisView *ontrack = 0;
979 // so we don't find the current region again..
983 if (!selection->tracks.empty()) {
985 r = find_next_region (pos, point, dir, selection->tracks, &ontrack);
987 } else if (clicked_axisview) {
990 t.push_back (clicked_axisview);
992 r = find_next_region (pos, point, dir, t, &ontrack);
996 r = find_next_region (pos, point, dir, track_views, &ontrack);
1005 pos = r->first_frame ();
1009 pos = r->last_frame ();
1013 pos = r->sync_position ();
1018 RouteTimeAxisView *rtav;
1020 if ( ontrack != 0 && (rtav = dynamic_cast<RouteTimeAxisView*>(ontrack)) != 0 ) {
1021 if (rtav->track() != 0) {
1022 speed = rtav->track()->speed();
1026 pos = track_frame_to_session_frame(pos, speed);
1028 if (cursor == playhead_cursor) {
1029 _session->request_locate (pos);
1031 cursor->set_position (pos);
1036 Editor::cursor_to_next_region_point (EditorCursor* cursor, RegionPoint point)
1038 cursor_to_region_point (cursor, point, 1);
1042 Editor::cursor_to_previous_region_point (EditorCursor* cursor, RegionPoint point)
1044 cursor_to_region_point (cursor, point, -1);
1048 Editor::cursor_to_selection_start (EditorCursor *cursor)
1052 switch (mouse_mode) {
1054 if (!selection->regions.empty()) {
1055 pos = selection->regions.start();
1060 if (!selection->time.empty()) {
1061 pos = selection->time.start ();
1069 if (cursor == playhead_cursor) {
1070 _session->request_locate (pos);
1072 cursor->set_position (pos);
1077 Editor::cursor_to_selection_end (EditorCursor *cursor)
1081 switch (mouse_mode) {
1083 if (!selection->regions.empty()) {
1084 pos = selection->regions.end_frame();
1089 if (!selection->time.empty()) {
1090 pos = selection->time.end_frame ();
1098 if (cursor == playhead_cursor) {
1099 _session->request_locate (pos);
1101 cursor->set_position (pos);
1106 Editor::selected_marker_to_region_boundary (bool with_selection, int32_t dir)
1116 if (selection->markers.empty()) {
1120 if (!mouse_frame (mouse, ignored)) {
1124 add_location_mark (mouse);
1127 if ((loc = find_location_from_marker (selection->markers.front(), ignored)) == 0) {
1131 framepos_t pos = loc->start();
1133 // so we don't find the current region again..
1134 if (dir > 0 || pos > 0) {
1138 if ((target = get_region_boundary (pos, dir, with_selection, false)) < 0) {
1142 loc->move_to (target);
1146 Editor::selected_marker_to_next_region_boundary (bool with_selection)
1148 selected_marker_to_region_boundary (with_selection, 1);
1152 Editor::selected_marker_to_previous_region_boundary (bool with_selection)
1154 selected_marker_to_region_boundary (with_selection, -1);
1158 Editor::selected_marker_to_region_point (RegionPoint point, int32_t dir)
1160 boost::shared_ptr<Region> r;
1165 if (!_session || selection->markers.empty()) {
1169 if ((loc = find_location_from_marker (selection->markers.front(), ignored)) == 0) {
1173 TimeAxisView *ontrack = 0;
1177 // so we don't find the current region again..
1181 if (!selection->tracks.empty()) {
1183 r = find_next_region (pos, point, dir, selection->tracks, &ontrack);
1187 r = find_next_region (pos, point, dir, track_views, &ontrack);
1196 pos = r->first_frame ();
1200 pos = r->last_frame ();
1204 pos = r->adjust_to_sync (r->first_frame());
1209 RouteTimeAxisView *rtav;
1211 if (ontrack != 0 && (rtav = dynamic_cast<RouteTimeAxisView*>(ontrack)) != 0) {
1212 if (rtav->track() != 0) {
1213 speed = rtav->track()->speed();
1217 pos = track_frame_to_session_frame(pos, speed);
1223 Editor::selected_marker_to_next_region_point (RegionPoint point)
1225 selected_marker_to_region_point (point, 1);
1229 Editor::selected_marker_to_previous_region_point (RegionPoint point)
1231 selected_marker_to_region_point (point, -1);
1235 Editor::selected_marker_to_selection_start ()
1241 if (!_session || selection->markers.empty()) {
1245 if ((loc = find_location_from_marker (selection->markers.front(), ignored)) == 0) {
1249 switch (mouse_mode) {
1251 if (!selection->regions.empty()) {
1252 pos = selection->regions.start();
1257 if (!selection->time.empty()) {
1258 pos = selection->time.start ();
1270 Editor::selected_marker_to_selection_end ()
1276 if (!_session || selection->markers.empty()) {
1280 if ((loc = find_location_from_marker (selection->markers.front(), ignored)) == 0) {
1284 switch (mouse_mode) {
1286 if (!selection->regions.empty()) {
1287 pos = selection->regions.end_frame();
1292 if (!selection->time.empty()) {
1293 pos = selection->time.end_frame ();
1305 Editor::scroll_playhead (bool forward)
1307 framepos_t pos = playhead_cursor->current_frame ();
1308 framecnt_t delta = (framecnt_t) floor (current_page_samples() / 0.8);
1311 if (pos == max_framepos) {
1315 if (pos < max_framepos - delta) {
1334 _session->request_locate (pos);
1338 Editor::cursor_align (bool playhead_to_edit)
1344 if (playhead_to_edit) {
1346 if (selection->markers.empty()) {
1350 _session->request_locate (selection->markers.front()->position(), _session->transport_rolling());
1353 /* move selected markers to playhead */
1355 for (MarkerSelection::iterator i = selection->markers.begin(); i != selection->markers.end(); ++i) {
1358 Location* loc = find_location_from_marker (*i, ignored);
1360 if (loc->is_mark()) {
1361 loc->set_start (playhead_cursor->current_frame ());
1363 loc->set (playhead_cursor->current_frame (),
1364 playhead_cursor->current_frame () + loc->length());
1371 Editor::scroll_backward (float pages)
1373 framepos_t const one_page = (framepos_t) rint (_visible_canvas_width * samples_per_pixel);
1374 framepos_t const cnt = (framepos_t) floor (pages * one_page);
1377 if (leftmost_frame < cnt) {
1380 frame = leftmost_frame - cnt;
1383 reset_x_origin (frame);
1387 Editor::scroll_forward (float pages)
1389 framepos_t const one_page = (framepos_t) rint (_visible_canvas_width * samples_per_pixel);
1390 framepos_t const cnt = (framepos_t) floor (pages * one_page);
1393 if (max_framepos - cnt < leftmost_frame) {
1394 frame = max_framepos - cnt;
1396 frame = leftmost_frame + cnt;
1399 reset_x_origin (frame);
1403 Editor::scroll_tracks_down ()
1405 double vert_value = vertical_adjustment.get_value() + vertical_adjustment.get_page_size();
1406 if (vert_value > vertical_adjustment.get_upper() - _visible_canvas_height) {
1407 vert_value = vertical_adjustment.get_upper() - _visible_canvas_height;
1410 vertical_adjustment.set_value (vert_value);
1414 Editor::scroll_tracks_up ()
1416 vertical_adjustment.set_value (vertical_adjustment.get_value() - vertical_adjustment.get_page_size());
1420 Editor::scroll_tracks_down_line ()
1422 double vert_value = vertical_adjustment.get_value() + 60;
1424 if (vert_value > vertical_adjustment.get_upper() - _visible_canvas_height) {
1425 vert_value = vertical_adjustment.get_upper() - _visible_canvas_height;
1428 vertical_adjustment.set_value (vert_value);
1432 Editor::scroll_tracks_up_line ()
1434 reset_y_origin (vertical_adjustment.get_value() - 60);
1438 Editor::scroll_down_one_track (bool skip_child_views)
1440 TrackViewList::reverse_iterator next = track_views.rend();
1441 const double top_of_trackviews = vertical_adjustment.get_value();
1443 for (TrackViewList::reverse_iterator t = track_views.rbegin(); t != track_views.rend(); ++t) {
1444 if ((*t)->hidden()) {
1448 /* If this is the upper-most visible trackview, we want to display
1449 * the one above it (next)
1451 * Note that covers_y_position() is recursive and includes child views
1453 std::pair<TimeAxisView*,double> res = (*t)->covers_y_position (top_of_trackviews);
1456 if (skip_child_views) {
1459 /* automation lane (one level, non-recursive)
1461 * - if no automation lane exists -> move to next tack
1462 * - if the first (here: bottom-most) matches -> move to next tack
1463 * - if no y-axis match is found -> the current track is at the top
1464 * -> move to last (here: top-most) automation lane
1466 TimeAxisView::Children kids = (*t)->get_child_list();
1467 TimeAxisView::Children::reverse_iterator nkid = kids.rend();
1469 for (TimeAxisView::Children::reverse_iterator ci = kids.rbegin(); ci != kids.rend(); ++ci) {
1470 if ((*ci)->hidden()) {
1474 std::pair<TimeAxisView*,double> dev;
1475 dev = (*ci)->covers_y_position (top_of_trackviews);
1477 /* some automation lane is currently at the top */
1478 if (ci == kids.rbegin()) {
1479 /* first (bottom-most) autmation lane is at the top.
1480 * -> move to next track
1489 if (nkid != kids.rend()) {
1490 ensure_time_axis_view_is_visible (**nkid, true);
1498 /* move to the track below the first one that covers the */
1500 if (next != track_views.rend()) {
1501 ensure_time_axis_view_is_visible (**next, true);
1509 Editor::scroll_up_one_track (bool skip_child_views)
1511 TrackViewList::iterator prev = track_views.end();
1512 double top_of_trackviews = vertical_adjustment.get_value ();
1514 for (TrackViewList::iterator t = track_views.begin(); t != track_views.end(); ++t) {
1516 if ((*t)->hidden()) {
1520 /* find the trackview at the top of the trackview group
1522 * Note that covers_y_position() is recursive and includes child views
1524 std::pair<TimeAxisView*,double> res = (*t)->covers_y_position (top_of_trackviews);
1527 if (skip_child_views) {
1530 /* automation lane (one level, non-recursive)
1532 * - if no automation lane exists -> move to prev tack
1533 * - if no y-axis match is found -> the current track is at the top -> move to prev track
1534 * (actually last automation lane of previous track, see below)
1535 * - if first (top-most) lane is at the top -> move to this track
1536 * - else move up one lane
1538 TimeAxisView::Children kids = (*t)->get_child_list();
1539 TimeAxisView::Children::iterator pkid = kids.end();
1541 for (TimeAxisView::Children::iterator ci = kids.begin(); ci != kids.end(); ++ci) {
1542 if ((*ci)->hidden()) {
1546 std::pair<TimeAxisView*,double> dev;
1547 dev = (*ci)->covers_y_position (top_of_trackviews);
1549 /* some automation lane is currently at the top */
1550 if (ci == kids.begin()) {
1551 /* first (top-most) autmation lane is at the top.
1552 * jump directly to this track's top
1554 ensure_time_axis_view_is_visible (**t, true);
1557 else if (pkid != kids.end()) {
1558 /* some other automation lane is at the top.
1559 * move up to prev automation lane.
1561 ensure_time_axis_view_is_visible (**pkid, true);
1564 assert(0); // not reached
1575 if (prev != track_views.end()) {
1576 // move to bottom-most automation-lane of the previous track
1577 TimeAxisView::Children kids = (*prev)->get_child_list();
1578 TimeAxisView::Children::reverse_iterator pkid = kids.rend();
1579 if (!skip_child_views) {
1580 // find the last visible lane
1581 for (TimeAxisView::Children::reverse_iterator ci = kids.rbegin(); ci != kids.rend(); ++ci) {
1582 if (!(*ci)->hidden()) {
1588 if (pkid != kids.rend()) {
1589 ensure_time_axis_view_is_visible (**pkid, true);
1591 ensure_time_axis_view_is_visible (**prev, true);
1600 Editor::scroll_left_step ()
1602 framepos_t xdelta = (current_page_samples() / 8);
1604 if (leftmost_frame > xdelta) {
1605 reset_x_origin (leftmost_frame - xdelta);
1613 Editor::scroll_right_step ()
1615 framepos_t xdelta = (current_page_samples() / 8);
1617 if (max_framepos - xdelta > leftmost_frame) {
1618 reset_x_origin (leftmost_frame + xdelta);
1620 reset_x_origin (max_framepos - current_page_samples());
1625 Editor::scroll_left_half_page ()
1627 framepos_t xdelta = (current_page_samples() / 2);
1628 if (leftmost_frame > xdelta) {
1629 reset_x_origin (leftmost_frame - xdelta);
1636 Editor::scroll_right_half_page ()
1638 framepos_t xdelta = (current_page_samples() / 2);
1639 if (max_framepos - xdelta > leftmost_frame) {
1640 reset_x_origin (leftmost_frame + xdelta);
1642 reset_x_origin (max_framepos - current_page_samples());
1649 Editor::tav_zoom_step (bool coarser)
1651 DisplaySuspender ds;
1655 if (selection->tracks.empty()) {
1658 ts = &selection->tracks;
1661 for (TrackViewList::iterator i = ts->begin(); i != ts->end(); ++i) {
1662 TimeAxisView *tv = (static_cast<TimeAxisView*>(*i));
1663 tv->step_height (coarser);
1668 Editor::tav_zoom_smooth (bool coarser, bool force_all)
1670 DisplaySuspender ds;
1674 if (selection->tracks.empty() || force_all) {
1677 ts = &selection->tracks;
1680 for (TrackViewList::iterator i = ts->begin(); i != ts->end(); ++i) {
1681 TimeAxisView *tv = (static_cast<TimeAxisView*>(*i));
1682 uint32_t h = tv->current_height ();
1687 if (h >= TimeAxisView::preset_height (HeightSmall)) {
1692 tv->set_height (h + 5);
1698 Editor::temporal_zoom_step_mouse_focus (bool coarser)
1700 Editing::ZoomFocus temp_focus = zoom_focus;
1701 zoom_focus = Editing::ZoomFocusMouse;
1702 temporal_zoom_step (coarser);
1703 zoom_focus = temp_focus;
1707 Editor::temporal_zoom_step (bool coarser)
1709 ENSURE_GUI_THREAD (*this, &Editor::temporal_zoom_step, coarser)
1711 framecnt_t nspp = samples_per_pixel;
1719 temporal_zoom (nspp);
1723 Editor::temporal_zoom (framecnt_t fpp)
1729 framepos_t current_page = current_page_samples();
1730 framepos_t current_leftmost = leftmost_frame;
1731 framepos_t current_rightmost;
1732 framepos_t current_center;
1733 framepos_t new_page_size;
1734 framepos_t half_page_size;
1735 framepos_t leftmost_after_zoom = 0;
1737 bool in_track_canvas;
1741 if (fpp == samples_per_pixel) {
1745 // Imposing an arbitrary limit to zoom out as too much zoom out produces
1746 // segfaults for lack of memory. If somebody decides this is not high enough I
1747 // believe it can be raisen to higher values but some limit must be in place.
1749 // This constant represents 1 day @ 48kHz on a 1600 pixel wide display
1750 // all of which is used for the editor track displays. The whole day
1751 // would be 4147200000 samples, so 2592000 samples per pixel.
1753 nfpp = min (fpp, (framecnt_t) 2592000);
1754 nfpp = max ((framecnt_t) 1, nfpp);
1756 new_page_size = (framepos_t) floor (_visible_canvas_width * nfpp);
1757 half_page_size = new_page_size / 2;
1759 switch (zoom_focus) {
1761 leftmost_after_zoom = current_leftmost;
1764 case ZoomFocusRight:
1765 current_rightmost = leftmost_frame + current_page;
1766 if (current_rightmost < new_page_size) {
1767 leftmost_after_zoom = 0;
1769 leftmost_after_zoom = current_rightmost - new_page_size;
1773 case ZoomFocusCenter:
1774 current_center = current_leftmost + (current_page/2);
1775 if (current_center < half_page_size) {
1776 leftmost_after_zoom = 0;
1778 leftmost_after_zoom = current_center - half_page_size;
1782 case ZoomFocusPlayhead:
1783 /* centre playhead */
1784 l = playhead_cursor->current_frame () - (new_page_size * 0.5);
1787 leftmost_after_zoom = 0;
1788 } else if (l > max_framepos) {
1789 leftmost_after_zoom = max_framepos - new_page_size;
1791 leftmost_after_zoom = (framepos_t) l;
1795 case ZoomFocusMouse:
1796 /* try to keep the mouse over the same point in the display */
1798 if (!mouse_frame (where, in_track_canvas)) {
1799 /* use playhead instead */
1800 where = playhead_cursor->current_frame ();
1802 if (where < half_page_size) {
1803 leftmost_after_zoom = 0;
1805 leftmost_after_zoom = where - half_page_size;
1810 l = - ((new_page_size * ((where - current_leftmost)/(double)current_page)) - where);
1813 leftmost_after_zoom = 0;
1814 } else if (l > max_framepos) {
1815 leftmost_after_zoom = max_framepos - new_page_size;
1817 leftmost_after_zoom = (framepos_t) l;
1824 /* try to keep the edit point in the same place */
1825 where = get_preferred_edit_position ();
1829 double l = - ((new_page_size * ((where - current_leftmost)/(double)current_page)) - where);
1832 leftmost_after_zoom = 0;
1833 } else if (l > max_framepos) {
1834 leftmost_after_zoom = max_framepos - new_page_size;
1836 leftmost_after_zoom = (framepos_t) l;
1840 /* edit point not defined */
1847 // leftmost_after_zoom = min (leftmost_after_zoom, _session->current_end_frame());
1849 reposition_and_zoom (leftmost_after_zoom, nfpp);
1853 Editor::calc_extra_zoom_edges(framepos_t &start, framepos_t &end)
1855 /* this func helps make sure we leave a little space
1856 at each end of the editor so that the zoom doesn't fit the region
1857 precisely to the screen.
1860 GdkScreen* screen = gdk_screen_get_default ();
1861 const gint pixwidth = gdk_screen_get_width (screen);
1862 const gint mmwidth = gdk_screen_get_width_mm (screen);
1863 const double pix_per_mm = (double) pixwidth/ (double) mmwidth;
1864 const double one_centimeter_in_pixels = pix_per_mm * 10.0;
1866 const framepos_t range = end - start;
1867 const framecnt_t new_fpp = (framecnt_t) ceil ((double) range / (double) _visible_canvas_width);
1868 const framepos_t extra_samples = (framepos_t) floor (one_centimeter_in_pixels * new_fpp);
1870 if (start > extra_samples) {
1871 start -= extra_samples;
1876 if (max_framepos - extra_samples > end) {
1877 end += extra_samples;
1884 Editor::temporal_zoom_region (bool both_axes)
1886 framepos_t start = max_framepos;
1888 set<TimeAxisView*> tracks;
1890 if ( !get_selection_extents(start, end) )
1893 calc_extra_zoom_edges (start, end);
1895 /* if we're zooming on both axes we need to save track heights etc.
1898 undo_visual_stack.push_back (current_visual_state (both_axes));
1900 PBD::Unwinder<bool> nsv (no_save_visual, true);
1902 temporal_zoom_by_frame (start, end);
1905 uint32_t per_track_height = (uint32_t) floor ((_visible_canvas_height - 10.0) / tracks.size());
1907 /* set visible track heights appropriately */
1909 for (set<TimeAxisView*>::iterator t = tracks.begin(); t != tracks.end(); ++t) {
1910 (*t)->set_height (per_track_height);
1913 /* hide irrelevant tracks */
1915 DisplaySuspender ds;
1917 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1918 if (find (tracks.begin(), tracks.end(), (*i)) == tracks.end()) {
1919 hide_track_in_display (*i);
1923 vertical_adjustment.set_value (0.0);
1926 redo_visual_stack.push_back (current_visual_state (both_axes));
1931 Editor::get_selection_extents (framepos_t &start, framepos_t &end) const
1933 start = max_framepos;
1937 //ToDo: if notes are selected, set extents to that selection
1939 //ToDo: if control points are selected, set extents to that selection
1941 if ( !selection->regions.empty() ) {
1942 RegionSelection rs = get_regions_from_selection_and_entered ();
1944 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
1946 if ((*i)->region()->position() < start) {
1947 start = (*i)->region()->position();
1950 if ((*i)->region()->last_frame() + 1 > end) {
1951 end = (*i)->region()->last_frame() + 1;
1955 } else if (!selection->time.empty()) {
1956 start = selection->time.start();
1957 end = selection->time.end_frame();
1959 ret = false; //no selection found
1962 if ((start == 0 && end == 0) || end < start) {
1971 Editor::temporal_zoom_selection (bool both_axes)
1973 if (!selection) return;
1975 //ToDo: if notes are selected, zoom to that
1977 //ToDo: if control points are selected, zoom to that
1979 //if region(s) are selected, zoom to that
1980 if ( !selection->regions.empty() )
1981 temporal_zoom_region (both_axes);
1983 //if a range is selected, zoom to that
1984 if (!selection->time.empty()) {
1986 framepos_t start, end;
1987 if (get_selection_extents (start, end)) {
1988 calc_extra_zoom_edges(start, end);
1989 temporal_zoom_by_frame (start, end);
1999 Editor::temporal_zoom_session ()
2001 ENSURE_GUI_THREAD (*this, &Editor::temporal_zoom_session)
2004 framecnt_t start = _session->current_start_frame();
2005 framecnt_t end = _session->current_end_frame();
2007 if (_session->actively_recording () ) {
2008 framepos_t cur = playhead_cursor->current_frame ();
2010 /* recording beyond the end marker; zoom out
2011 * by 5 seconds more so that if 'follow
2012 * playhead' is active we don't immediately
2015 end = cur + _session->frame_rate() * 5;
2019 if ((start == 0 && end == 0) || end < start) {
2023 calc_extra_zoom_edges(start, end);
2025 temporal_zoom_by_frame (start, end);
2030 Editor::temporal_zoom_by_frame (framepos_t start, framepos_t end)
2032 if (!_session) return;
2034 if ((start == 0 && end == 0) || end < start) {
2038 framepos_t range = end - start;
2040 const framecnt_t new_fpp = (framecnt_t) ceil ((double) range / (double) _visible_canvas_width);
2042 framepos_t new_page = range;
2043 framepos_t middle = (framepos_t) floor ((double) start + ((double) range / 2.0f));
2044 framepos_t new_leftmost = (framepos_t) floor ((double) middle - ((double) new_page / 2.0f));
2046 if (new_leftmost > middle) {
2050 if (new_leftmost < 0) {
2054 reposition_and_zoom (new_leftmost, new_fpp);
2058 Editor::temporal_zoom_to_frame (bool coarser, framepos_t frame)
2064 framecnt_t range_before = frame - leftmost_frame;
2068 if (samples_per_pixel <= 1) {
2071 new_spp = samples_per_pixel + (samples_per_pixel/2);
2073 range_before += range_before/2;
2075 if (samples_per_pixel >= 1) {
2076 new_spp = samples_per_pixel - (samples_per_pixel/2);
2078 /* could bail out here since we cannot zoom any finer,
2079 but leave that to the equality test below
2081 new_spp = samples_per_pixel;
2084 range_before -= range_before/2;
2087 if (new_spp == samples_per_pixel) {
2091 /* zoom focus is automatically taken as @param frame when this
2095 framepos_t new_leftmost = frame - (framepos_t)range_before;
2097 if (new_leftmost > frame) {
2101 if (new_leftmost < 0) {
2105 reposition_and_zoom (new_leftmost, new_spp);
2110 Editor::choose_new_marker_name(string &name) {
2112 if (!UIConfiguration::instance().get_name_new_markers()) {
2113 /* don't prompt user for a new name */
2117 ArdourPrompter dialog (true);
2119 dialog.set_prompt (_("New Name:"));
2121 dialog.set_title (_("New Location Marker"));
2123 dialog.set_name ("MarkNameWindow");
2124 dialog.set_size_request (250, -1);
2125 dialog.set_position (Gtk::WIN_POS_MOUSE);
2127 dialog.add_button (Stock::OK, RESPONSE_ACCEPT);
2128 dialog.set_initial_text (name);
2132 switch (dialog.run ()) {
2133 case RESPONSE_ACCEPT:
2139 dialog.get_result(name);
2146 Editor::add_location_from_selection ()
2150 if (selection->time.empty()) {
2154 if (_session == 0 || clicked_axisview == 0) {
2158 framepos_t start = selection->time[clicked_selection].start;
2159 framepos_t end = selection->time[clicked_selection].end;
2161 _session->locations()->next_available_name(rangename,"selection");
2162 Location *location = new Location (*_session, start, end, rangename, Location::IsRangeMarker);
2164 begin_reversible_command (_("add marker"));
2166 XMLNode &before = _session->locations()->get_state();
2167 _session->locations()->add (location, true);
2168 XMLNode &after = _session->locations()->get_state();
2169 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2171 commit_reversible_command ();
2175 Editor::add_location_mark (framepos_t where)
2179 select_new_marker = true;
2181 _session->locations()->next_available_name(markername,"mark");
2182 if (!choose_new_marker_name(markername)) {
2185 Location *location = new Location (*_session, where, where, markername, Location::IsMark);
2186 begin_reversible_command (_("add marker"));
2188 XMLNode &before = _session->locations()->get_state();
2189 _session->locations()->add (location, true);
2190 XMLNode &after = _session->locations()->get_state();
2191 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2193 commit_reversible_command ();
2197 Editor::set_session_start_from_playhead ()
2203 if ((loc = _session->locations()->session_range_location()) == 0) { //should never happen
2204 _session->set_session_extents ( _session->audible_frame(), _session->audible_frame() );
2206 XMLNode &before = loc->get_state();
2208 _session->set_session_extents ( _session->audible_frame(), loc->end() );
2210 XMLNode &after = loc->get_state();
2212 begin_reversible_command (_("Set session start"));
2214 _session->add_command (new MementoCommand<Location>(*loc, &before, &after));
2216 commit_reversible_command ();
2221 Editor::set_session_end_from_playhead ()
2227 if ((loc = _session->locations()->session_range_location()) == 0) { //should never happen
2228 _session->set_session_extents ( _session->audible_frame(), _session->audible_frame() );
2230 XMLNode &before = loc->get_state();
2232 _session->set_session_extents ( loc->start(), _session->audible_frame() );
2234 XMLNode &after = loc->get_state();
2236 begin_reversible_command (_("Set session start"));
2238 _session->add_command (new MementoCommand<Location>(*loc, &before, &after));
2240 commit_reversible_command ();
2243 _session->set_end_is_free (false);
2247 Editor::add_location_from_playhead_cursor ()
2249 add_location_mark (_session->audible_frame());
2253 Editor::remove_location_at_playhead_cursor ()
2257 XMLNode &before = _session->locations()->get_state();
2258 bool removed = false;
2260 //find location(s) at this time
2261 Locations::LocationList locs;
2262 _session->locations()->find_all_between (_session->audible_frame(), _session->audible_frame()+1, locs, Location::Flags(0));
2263 for (Locations::LocationList::iterator i = locs.begin(); i != locs.end(); ++i) {
2264 if ((*i)->is_mark()) {
2265 _session->locations()->remove (*i);
2272 begin_reversible_command (_("remove marker"));
2273 XMLNode &after = _session->locations()->get_state();
2274 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2275 commit_reversible_command ();
2280 /** Add a range marker around each selected region */
2282 Editor::add_locations_from_region ()
2284 RegionSelection rs = get_regions_from_selection_and_entered ();
2289 bool commit = false;
2291 XMLNode &before = _session->locations()->get_state();
2293 for (RegionSelection::iterator i = rs.begin (); i != rs.end (); ++i) {
2295 boost::shared_ptr<Region> region = (*i)->region ();
2297 Location *location = new Location (*_session, region->position(), region->last_frame(), region->name(), Location::IsRangeMarker);
2299 _session->locations()->add (location, true);
2304 begin_reversible_command (selection->regions.size () > 1 ? _("add markers") : _("add marker"));
2305 XMLNode &after = _session->locations()->get_state();
2306 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2307 commit_reversible_command ();
2311 /** Add a single range marker around all selected regions */
2313 Editor::add_location_from_region ()
2315 RegionSelection rs = get_regions_from_selection_and_entered ();
2321 XMLNode &before = _session->locations()->get_state();
2325 if (rs.size() > 1) {
2326 _session->locations()->next_available_name(markername, "regions");
2328 RegionView* rv = *(rs.begin());
2329 boost::shared_ptr<Region> region = rv->region();
2330 markername = region->name();
2333 if (!choose_new_marker_name(markername)) {
2337 // single range spanning all selected
2338 Location *location = new Location (*_session, selection->regions.start(), selection->regions.end_frame(), markername, Location::IsRangeMarker);
2339 _session->locations()->add (location, true);
2341 begin_reversible_command (_("add marker"));
2342 XMLNode &after = _session->locations()->get_state();
2343 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2344 commit_reversible_command ();
2350 Editor::jump_forward_to_mark ()
2356 framepos_t pos = _session->locations()->first_mark_after (playhead_cursor->current_frame());
2362 _session->request_locate (pos, _session->transport_rolling());
2366 Editor::jump_backward_to_mark ()
2372 framepos_t pos = _session->locations()->first_mark_before (playhead_cursor->current_frame());
2378 _session->request_locate (pos, _session->transport_rolling());
2384 framepos_t const pos = _session->audible_frame ();
2387 _session->locations()->next_available_name (markername, "mark");
2389 if (!choose_new_marker_name (markername)) {
2393 _session->locations()->add (new Location (*_session, pos, 0, markername, Location::IsMark), true);
2397 Editor::clear_markers ()
2400 begin_reversible_command (_("clear markers"));
2402 XMLNode &before = _session->locations()->get_state();
2403 _session->locations()->clear_markers ();
2404 XMLNode &after = _session->locations()->get_state();
2405 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2407 commit_reversible_command ();
2412 Editor::clear_ranges ()
2415 begin_reversible_command (_("clear ranges"));
2417 XMLNode &before = _session->locations()->get_state();
2419 _session->locations()->clear_ranges ();
2421 XMLNode &after = _session->locations()->get_state();
2422 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2424 commit_reversible_command ();
2429 Editor::clear_locations ()
2431 begin_reversible_command (_("clear locations"));
2433 XMLNode &before = _session->locations()->get_state();
2434 _session->locations()->clear ();
2435 XMLNode &after = _session->locations()->get_state();
2436 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2438 commit_reversible_command ();
2442 Editor::unhide_markers ()
2444 for (LocationMarkerMap::iterator i = location_markers.begin(); i != location_markers.end(); ++i) {
2445 Location *l = (*i).first;
2446 if (l->is_hidden() && l->is_mark()) {
2447 l->set_hidden(false, this);
2453 Editor::unhide_ranges ()
2455 for (LocationMarkerMap::iterator i = location_markers.begin(); i != location_markers.end(); ++i) {
2456 Location *l = (*i).first;
2457 if (l->is_hidden() && l->is_range_marker()) {
2458 l->set_hidden(false, this);
2463 /* INSERT/REPLACE */
2466 Editor::insert_region_list_selection (float times)
2468 RouteTimeAxisView *tv = 0;
2469 boost::shared_ptr<Playlist> playlist;
2471 if (clicked_routeview != 0) {
2472 tv = clicked_routeview;
2473 } else if (!selection->tracks.empty()) {
2474 if ((tv = dynamic_cast<RouteTimeAxisView*>(selection->tracks.front())) == 0) {
2477 } else if (entered_track != 0) {
2478 if ((tv = dynamic_cast<RouteTimeAxisView*>(entered_track)) == 0) {
2485 if ((playlist = tv->playlist()) == 0) {
2489 boost::shared_ptr<Region> region = _regions->get_single_selection ();
2494 begin_reversible_command (_("insert region"));
2495 playlist->clear_changes ();
2496 playlist->add_region ((RegionFactory::create (region, true)), get_preferred_edit_position(), times);
2497 if (Config->get_edit_mode() == Ripple)
2498 playlist->ripple (get_preferred_edit_position(), region->length() * times, boost::shared_ptr<Region>());
2500 _session->add_command(new StatefulDiffCommand (playlist));
2501 commit_reversible_command ();
2504 /* BUILT-IN EFFECTS */
2507 Editor::reverse_selection ()
2512 /* GAIN ENVELOPE EDITING */
2515 Editor::edit_envelope ()
2522 Editor::transition_to_rolling (bool fwd)
2528 if (_session->config.get_external_sync()) {
2529 switch (Config->get_sync_source()) {
2533 /* transport controlled by the master */
2538 if (_session->is_auditioning()) {
2539 _session->cancel_audition ();
2543 _session->request_transport_speed (fwd ? 1.0f : -1.0f);
2547 Editor::play_from_start ()
2549 _session->request_locate (_session->current_start_frame(), true);
2553 Editor::play_from_edit_point ()
2555 _session->request_locate (get_preferred_edit_position(), true);
2559 Editor::play_from_edit_point_and_return ()
2561 framepos_t start_frame;
2562 framepos_t return_frame;
2564 start_frame = get_preferred_edit_position ( EDIT_IGNORE_PHEAD );
2566 if (_session->transport_rolling()) {
2567 _session->request_locate (start_frame, false);
2571 /* don't reset the return frame if its already set */
2573 if ((return_frame = _session->requested_return_frame()) < 0) {
2574 return_frame = _session->audible_frame();
2577 if (start_frame >= 0) {
2578 _session->request_roll_at_and_return (start_frame, return_frame);
2583 Editor::play_selection ()
2585 framepos_t start, end;
2586 if (!get_selection_extents ( start, end))
2589 AudioRange ar (start, end, 0);
2590 list<AudioRange> lar;
2593 _session->request_play_range (&lar, true);
2597 Editor::get_preroll ()
2599 return Config->get_preroll_seconds() * _session->frame_rate();
2604 Editor::maybe_locate_with_edit_preroll ( framepos_t location )
2606 if ( _session->transport_rolling() || !UIConfiguration::instance().get_follow_edits() || _ignore_follow_edits || _session->config.get_external_sync() )
2609 location -= get_preroll();
2611 //don't try to locate before the beginning of time
2615 //if follow_playhead is on, keep the playhead on the screen
2616 if ( _follow_playhead )
2617 if ( location < leftmost_frame )
2618 location = leftmost_frame;
2620 _session->request_locate( location );
2624 Editor::play_with_preroll ()
2627 framepos_t preroll = get_preroll();
2629 framepos_t start, end;
2630 if (!get_selection_extents ( start, end))
2633 if (start > preroll)
2634 start = start - preroll;
2636 end = end + preroll; //"post-roll"
2638 AudioRange ar (start, end, 0);
2639 list<AudioRange> lar;
2642 _session->request_play_range (&lar, true);
2647 Editor::play_location (Location& location)
2649 if (location.start() <= location.end()) {
2653 _session->request_bounded_roll (location.start(), location.end());
2657 Editor::loop_location (Location& location)
2659 if (location.start() <= location.end()) {
2665 if ((tll = transport_loop_location()) != 0) {
2666 tll->set (location.start(), location.end());
2668 // enable looping, reposition and start rolling
2669 _session->request_locate (tll->start(), true);
2670 _session->request_play_loop (true);
2675 Editor::do_layer_operation (LayerOperation op)
2677 if (selection->regions.empty ()) {
2681 bool const multiple = selection->regions.size() > 1;
2685 begin_reversible_command (_("raise regions"));
2687 begin_reversible_command (_("raise region"));
2693 begin_reversible_command (_("raise regions to top"));
2695 begin_reversible_command (_("raise region to top"));
2701 begin_reversible_command (_("lower regions"));
2703 begin_reversible_command (_("lower region"));
2709 begin_reversible_command (_("lower regions to bottom"));
2711 begin_reversible_command (_("lower region"));
2716 set<boost::shared_ptr<Playlist> > playlists = selection->regions.playlists ();
2717 for (set<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
2718 (*i)->clear_owned_changes ();
2721 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
2722 boost::shared_ptr<Region> r = (*i)->region ();
2734 r->lower_to_bottom ();
2738 for (set<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
2739 vector<Command*> cmds;
2741 _session->add_commands (cmds);
2744 commit_reversible_command ();
2748 Editor::raise_region ()
2750 do_layer_operation (Raise);
2754 Editor::raise_region_to_top ()
2756 do_layer_operation (RaiseToTop);
2760 Editor::lower_region ()
2762 do_layer_operation (Lower);
2766 Editor::lower_region_to_bottom ()
2768 do_layer_operation (LowerToBottom);
2771 /** Show the region editor for the selected regions */
2773 Editor::show_region_properties ()
2775 selection->foreach_regionview (&RegionView::show_region_editor);
2778 /** Show the midi list editor for the selected MIDI regions */
2780 Editor::show_midi_list_editor ()
2782 selection->foreach_midi_regionview (&MidiRegionView::show_list_editor);
2786 Editor::rename_region ()
2788 RegionSelection rs = get_regions_from_selection_and_entered ();
2794 ArdourDialog d (_("Rename Region"), true, false);
2796 Label label (_("New name:"));
2799 hbox.set_spacing (6);
2800 hbox.pack_start (label, false, false);
2801 hbox.pack_start (entry, true, true);
2803 d.get_vbox()->set_border_width (12);
2804 d.get_vbox()->pack_start (hbox, false, false);
2806 d.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
2807 d.add_button(Gtk::Stock::OK, Gtk::RESPONSE_OK);
2809 d.set_size_request (300, -1);
2811 entry.set_text (rs.front()->region()->name());
2812 entry.select_region (0, -1);
2814 entry.signal_activate().connect (sigc::bind (sigc::mem_fun (d, &Dialog::response), RESPONSE_OK));
2820 int const ret = d.run();
2824 if (ret != RESPONSE_OK) {
2828 std::string str = entry.get_text();
2829 strip_whitespace_edges (str);
2831 rs.front()->region()->set_name (str);
2832 _regions->redisplay ();
2836 /** Start an audition of the first selected region */
2838 Editor::play_edit_range ()
2840 framepos_t start, end;
2842 if (get_edit_op_range (start, end)) {
2843 _session->request_bounded_roll (start, end);
2848 Editor::play_selected_region ()
2850 framepos_t start = max_framepos;
2853 RegionSelection rs = get_regions_from_selection_and_entered ();
2859 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
2860 if ((*i)->region()->position() < start) {
2861 start = (*i)->region()->position();
2863 if ((*i)->region()->last_frame() + 1 > end) {
2864 end = (*i)->region()->last_frame() + 1;
2868 _session->request_bounded_roll (start, end);
2872 Editor::audition_playlist_region_standalone (boost::shared_ptr<Region> region)
2874 _session->audition_region (region);
2878 Editor::region_from_selection ()
2880 if (clicked_axisview == 0) {
2884 if (selection->time.empty()) {
2888 framepos_t start = selection->time[clicked_selection].start;
2889 framepos_t end = selection->time[clicked_selection].end;
2891 TrackViewList tracks = get_tracks_for_range_action ();
2893 framepos_t selection_cnt = end - start + 1;
2895 for (TrackSelection::iterator i = tracks.begin(); i != tracks.end(); ++i) {
2896 boost::shared_ptr<Region> current;
2897 boost::shared_ptr<Playlist> pl;
2898 framepos_t internal_start;
2901 if ((pl = (*i)->playlist()) == 0) {
2905 if ((current = pl->top_region_at (start)) == 0) {
2909 internal_start = start - current->position();
2910 RegionFactory::region_name (new_name, current->name(), true);
2914 plist.add (ARDOUR::Properties::start, current->start() + internal_start);
2915 plist.add (ARDOUR::Properties::length, selection_cnt);
2916 plist.add (ARDOUR::Properties::name, new_name);
2917 plist.add (ARDOUR::Properties::layer, 0);
2919 boost::shared_ptr<Region> region (RegionFactory::create (current, plist));
2924 Editor::create_region_from_selection (vector<boost::shared_ptr<Region> >& new_regions)
2926 if (selection->time.empty() || selection->tracks.empty()) {
2930 framepos_t start, end;
2931 if (clicked_selection) {
2932 start = selection->time[clicked_selection].start;
2933 end = selection->time[clicked_selection].end;
2935 start = selection->time.start();
2936 end = selection->time.end_frame();
2939 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
2940 sort_track_selection (ts);
2942 for (TrackSelection::iterator i = ts.begin(); i != ts.end(); ++i) {
2943 boost::shared_ptr<Region> current;
2944 boost::shared_ptr<Playlist> playlist;
2945 framepos_t internal_start;
2948 if ((playlist = (*i)->playlist()) == 0) {
2952 if ((current = playlist->top_region_at(start)) == 0) {
2956 internal_start = start - current->position();
2957 RegionFactory::region_name (new_name, current->name(), true);
2961 plist.add (ARDOUR::Properties::start, current->start() + internal_start);
2962 plist.add (ARDOUR::Properties::length, end - start + 1);
2963 plist.add (ARDOUR::Properties::name, new_name);
2965 new_regions.push_back (RegionFactory::create (current, plist));
2970 Editor::split_multichannel_region ()
2972 RegionSelection rs = get_regions_from_selection_and_entered ();
2978 vector< boost::shared_ptr<Region> > v;
2980 for (list<RegionView*>::iterator x = rs.begin(); x != rs.end(); ++x) {
2981 (*x)->region()->separate_by_channel (*_session, v);
2986 Editor::new_region_from_selection ()
2988 region_from_selection ();
2989 cancel_selection ();
2993 add_if_covered (RegionView* rv, const AudioRange* ar, RegionSelection* rs)
2995 switch (rv->region()->coverage (ar->start, ar->end - 1)) {
2996 // n.b. -1 because AudioRange::end is one past the end, but coverage expects inclusive ranges
2997 case Evoral::OverlapNone:
3005 * - selected tracks, or if there are none...
3006 * - tracks containing selected regions, or if there are none...
3011 Editor::get_tracks_for_range_action () const
3015 if (selection->tracks.empty()) {
3017 /* use tracks with selected regions */
3019 RegionSelection rs = selection->regions;
3021 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3022 TimeAxisView* tv = &(*i)->get_time_axis_view();
3024 if (!t.contains (tv)) {
3030 /* no regions and no tracks: use all tracks */
3036 t = selection->tracks;
3039 return t.filter_to_unique_playlists();
3043 Editor::separate_regions_between (const TimeSelection& ts)
3045 bool in_command = false;
3046 boost::shared_ptr<Playlist> playlist;
3047 RegionSelection new_selection;
3049 TrackViewList tmptracks = get_tracks_for_range_action ();
3050 sort_track_selection (tmptracks);
3052 for (TrackSelection::iterator i = tmptracks.begin(); i != tmptracks.end(); ++i) {
3054 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> ((*i));
3060 if (!rtv->is_track()) {
3064 /* no edits to destructive tracks */
3066 if (rtv->track()->destructive()) {
3070 if ((playlist = rtv->playlist()) != 0) {
3072 playlist->clear_changes ();
3074 /* XXX need to consider musical time selections here at some point */
3076 double speed = rtv->track()->speed();
3078 for (list<AudioRange>::const_iterator t = ts.begin(); t != ts.end(); ++t) {
3080 sigc::connection c = rtv->view()->RegionViewAdded.connect (
3081 sigc::mem_fun(*this, &Editor::collect_new_region_view));
3083 latest_regionviews.clear ();
3085 playlist->partition ((framepos_t)((*t).start * speed),
3086 (framepos_t)((*t).end * speed), false);
3090 if (!latest_regionviews.empty()) {
3092 rtv->view()->foreach_regionview (sigc::bind (
3093 sigc::ptr_fun (add_if_covered),
3094 &(*t), &new_selection));
3097 begin_reversible_command (_("separate"));
3101 /* pick up changes to existing regions */
3103 vector<Command*> cmds;
3104 playlist->rdiff (cmds);
3105 _session->add_commands (cmds);
3107 /* pick up changes to the playlist itself (adds/removes)
3110 _session->add_command(new StatefulDiffCommand (playlist));
3117 // selection->set (new_selection);
3119 commit_reversible_command ();
3123 struct PlaylistState {
3124 boost::shared_ptr<Playlist> playlist;
3128 /** Take tracks from get_tracks_for_range_action and cut any regions
3129 * on those tracks so that the tracks are empty over the time
3133 Editor::separate_region_from_selection ()
3135 /* preferentially use *all* ranges in the time selection if we're in range mode
3136 to allow discontiguous operation, since get_edit_op_range() currently
3137 returns a single range.
3140 if (!selection->time.empty()) {
3142 separate_regions_between (selection->time);
3149 if (get_edit_op_range (start, end)) {
3151 AudioRange ar (start, end, 1);
3155 separate_regions_between (ts);
3161 Editor::separate_region_from_punch ()
3163 Location* loc = _session->locations()->auto_punch_location();
3165 separate_regions_using_location (*loc);
3170 Editor::separate_region_from_loop ()
3172 Location* loc = _session->locations()->auto_loop_location();
3174 separate_regions_using_location (*loc);
3179 Editor::separate_regions_using_location (Location& loc)
3181 if (loc.is_mark()) {
3185 AudioRange ar (loc.start(), loc.end(), 1);
3190 separate_regions_between (ts);
3193 /** Separate regions under the selected region */
3195 Editor::separate_under_selected_regions ()
3197 vector<PlaylistState> playlists;
3201 rs = get_regions_from_selection_and_entered();
3203 if (!_session || rs.empty()) {
3207 begin_reversible_command (_("separate region under"));
3209 list<boost::shared_ptr<Region> > regions_to_remove;
3211 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3212 // we can't just remove the region(s) in this loop because
3213 // this removes them from the RegionSelection, and they thus
3214 // disappear from underneath the iterator, and the ++i above
3215 // SEGVs in a puzzling fashion.
3217 // so, first iterate over the regions to be removed from rs and
3218 // add them to the regions_to_remove list, and then
3219 // iterate over the list to actually remove them.
3221 regions_to_remove.push_back ((*i)->region());
3224 for (list<boost::shared_ptr<Region> >::iterator rl = regions_to_remove.begin(); rl != regions_to_remove.end(); ++rl) {
3226 boost::shared_ptr<Playlist> playlist = (*rl)->playlist();
3229 // is this check necessary?
3233 vector<PlaylistState>::iterator i;
3235 //only take state if this is a new playlist.
3236 for (i = playlists.begin(); i != playlists.end(); ++i) {
3237 if ((*i).playlist == playlist) {
3242 if (i == playlists.end()) {
3244 PlaylistState before;
3245 before.playlist = playlist;
3246 before.before = &playlist->get_state();
3248 playlist->freeze ();
3249 playlists.push_back(before);
3252 //Partition on the region bounds
3253 playlist->partition ((*rl)->first_frame() - 1, (*rl)->last_frame() + 1, true);
3255 //Re-add region that was just removed due to the partition operation
3256 playlist->add_region( (*rl), (*rl)->first_frame() );
3259 vector<PlaylistState>::iterator pl;
3261 for (pl = playlists.begin(); pl != playlists.end(); ++pl) {
3262 (*pl).playlist->thaw ();
3263 _session->add_command(new MementoCommand<Playlist>(*(*pl).playlist, (*pl).before, &(*pl).playlist->get_state()));
3266 commit_reversible_command ();
3270 Editor::crop_region_to_selection ()
3272 if (!selection->time.empty()) {
3274 crop_region_to (selection->time.start(), selection->time.end_frame());
3281 if (get_edit_op_range (start, end)) {
3282 crop_region_to (start, end);
3289 Editor::crop_region_to (framepos_t start, framepos_t end)
3291 vector<boost::shared_ptr<Playlist> > playlists;
3292 boost::shared_ptr<Playlist> playlist;
3295 if (selection->tracks.empty()) {
3296 ts = track_views.filter_to_unique_playlists();
3298 ts = selection->tracks.filter_to_unique_playlists ();
3301 sort_track_selection (ts);
3303 for (TrackSelection::iterator i = ts.begin(); i != ts.end(); ++i) {
3305 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> ((*i));
3311 boost::shared_ptr<Track> t = rtv->track();
3313 if (t != 0 && ! t->destructive()) {
3315 if ((playlist = rtv->playlist()) != 0) {
3316 playlists.push_back (playlist);
3321 if (playlists.empty()) {
3326 framepos_t new_start;
3328 framecnt_t new_length;
3329 bool in_command = false;
3331 for (vector<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
3333 /* Only the top regions at start and end have to be cropped */
3334 boost::shared_ptr<Region> region_at_start = (*i)->top_region_at(start);
3335 boost::shared_ptr<Region> region_at_end = (*i)->top_region_at(end);
3337 vector<boost::shared_ptr<Region> > regions;
3339 if (region_at_start != 0) {
3340 regions.push_back (region_at_start);
3342 if (region_at_end != 0) {
3343 regions.push_back (region_at_end);
3346 /* now adjust lengths */
3347 for (vector<boost::shared_ptr<Region> >::iterator i = regions.begin(); i != regions.end(); ++i) {
3349 pos = (*i)->position();
3350 new_start = max (start, pos);
3351 if (max_framepos - pos > (*i)->length()) {
3352 new_end = pos + (*i)->length() - 1;
3354 new_end = max_framepos;
3356 new_end = min (end, new_end);
3357 new_length = new_end - new_start + 1;
3360 begin_reversible_command (_("trim to selection"));
3363 (*i)->clear_changes ();
3364 (*i)->trim_to (new_start, new_length);
3365 _session->add_command (new StatefulDiffCommand (*i));
3370 commit_reversible_command ();
3375 Editor::region_fill_track ()
3377 boost::shared_ptr<Playlist> playlist;
3378 RegionSelection regions = get_regions_from_selection_and_entered ();
3379 RegionSelection foo;
3381 framepos_t const end = _session->current_end_frame ();
3383 if (regions.empty () || regions.end_frame () + 1 >= end) {
3387 framepos_t const start_frame = regions.start ();
3388 framepos_t const end_frame = regions.end_frame ();
3389 framecnt_t const gap = end_frame - start_frame + 1;
3391 begin_reversible_command (Operations::region_fill);
3393 selection->clear_regions ();
3395 for (RegionSelection::iterator i = regions.begin(); i != regions.end(); ++i) {
3397 boost::shared_ptr<Region> r ((*i)->region());
3399 TimeAxisView& tv = (*i)->get_time_axis_view();
3400 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (&tv);
3401 latest_regionviews.clear ();
3402 sigc::connection c = rtv->view()->RegionViewAdded.connect (sigc::mem_fun(*this, &Editor::collect_new_region_view));
3404 framepos_t const position = end_frame + (r->first_frame() - start_frame + 1);
3405 playlist = (*i)->region()->playlist();
3406 playlist->clear_changes ();
3407 playlist->duplicate_until (r, position, gap, end);
3408 _session->add_command(new StatefulDiffCommand (playlist));
3412 foo.insert (foo.end(), latest_regionviews.begin(), latest_regionviews.end());
3416 selection->set (foo);
3419 commit_reversible_command ();
3423 Editor::set_region_sync_position ()
3425 set_sync_point (get_preferred_edit_position (), get_regions_from_selection_and_edit_point ());
3429 Editor::set_sync_point (framepos_t where, const RegionSelection& rs)
3431 bool in_command = false;
3433 for (RegionSelection::const_iterator r = rs.begin(); r != rs.end(); ++r) {
3435 if (!(*r)->region()->covers (where)) {
3439 boost::shared_ptr<Region> region ((*r)->region());
3442 begin_reversible_command (_("set sync point"));
3446 region->clear_changes ();
3447 region->set_sync_position (where);
3448 _session->add_command(new StatefulDiffCommand (region));
3452 commit_reversible_command ();
3456 /** Remove the sync positions of the selection */
3458 Editor::remove_region_sync ()
3460 RegionSelection rs = get_regions_from_selection_and_entered ();
3466 begin_reversible_command (_("remove region sync"));
3468 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3470 (*i)->region()->clear_changes ();
3471 (*i)->region()->clear_sync_position ();
3472 _session->add_command(new StatefulDiffCommand ((*i)->region()));
3475 commit_reversible_command ();
3479 Editor::naturalize_region ()
3481 RegionSelection rs = get_regions_from_selection_and_entered ();
3487 if (rs.size() > 1) {
3488 begin_reversible_command (_("move regions to original position"));
3490 begin_reversible_command (_("move region to original position"));
3493 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3494 (*i)->region()->clear_changes ();
3495 (*i)->region()->move_to_natural_position ();
3496 _session->add_command (new StatefulDiffCommand ((*i)->region()));
3499 commit_reversible_command ();
3503 Editor::align_regions (RegionPoint what)
3505 RegionSelection const rs = get_regions_from_selection_and_edit_point ();
3511 begin_reversible_command (_("align selection"));
3513 framepos_t const position = get_preferred_edit_position ();
3515 for (RegionSelection::const_iterator i = rs.begin(); i != rs.end(); ++i) {
3516 align_region_internal ((*i)->region(), what, position);
3519 commit_reversible_command ();
3522 struct RegionSortByTime {
3523 bool operator() (const RegionView* a, const RegionView* b) {
3524 return a->region()->position() < b->region()->position();
3529 Editor::align_regions_relative (RegionPoint point)
3531 RegionSelection const rs = get_regions_from_selection_and_edit_point ();
3537 framepos_t const position = get_preferred_edit_position ();
3539 framepos_t distance = 0;
3543 list<RegionView*> sorted;
3544 rs.by_position (sorted);
3546 boost::shared_ptr<Region> r ((*sorted.begin())->region());
3551 if (position > r->position()) {
3552 distance = position - r->position();
3554 distance = r->position() - position;
3560 if (position > r->last_frame()) {
3561 distance = position - r->last_frame();
3562 pos = r->position() + distance;
3564 distance = r->last_frame() - position;
3565 pos = r->position() - distance;
3571 pos = r->adjust_to_sync (position);
3572 if (pos > r->position()) {
3573 distance = pos - r->position();
3575 distance = r->position() - pos;
3581 if (pos == r->position()) {
3585 begin_reversible_command (_("align selection (relative)"));
3587 /* move first one specially */
3589 r->clear_changes ();
3590 r->set_position (pos);
3591 _session->add_command(new StatefulDiffCommand (r));
3593 /* move rest by the same amount */
3597 for (list<RegionView*>::iterator i = sorted.begin(); i != sorted.end(); ++i) {
3599 boost::shared_ptr<Region> region ((*i)->region());
3601 region->clear_changes ();
3604 region->set_position (region->position() + distance);
3606 region->set_position (region->position() - distance);
3609 _session->add_command(new StatefulDiffCommand (region));
3613 commit_reversible_command ();
3617 Editor::align_region (boost::shared_ptr<Region> region, RegionPoint point, framepos_t position)
3619 begin_reversible_command (_("align region"));
3620 align_region_internal (region, point, position);
3621 commit_reversible_command ();
3625 Editor::align_region_internal (boost::shared_ptr<Region> region, RegionPoint point, framepos_t position)
3627 region->clear_changes ();
3631 region->set_position (region->adjust_to_sync (position));
3635 if (position > region->length()) {
3636 region->set_position (position - region->length());
3641 region->set_position (position);
3645 _session->add_command(new StatefulDiffCommand (region));
3649 Editor::trim_region_front ()
3655 Editor::trim_region_back ()
3657 trim_region (false);
3661 Editor::trim_region (bool front)
3663 framepos_t where = get_preferred_edit_position();
3664 RegionSelection rs = get_regions_from_selection_and_edit_point ();
3670 begin_reversible_command (front ? _("trim front") : _("trim back"));
3672 for (list<RegionView*>::const_iterator i = rs.by_layer().begin(); i != rs.by_layer().end(); ++i) {
3673 if (!(*i)->region()->locked()) {
3675 (*i)->region()->clear_changes ();
3678 (*i)->region()->trim_front (where);
3679 maybe_locate_with_edit_preroll ( where );
3681 (*i)->region()->trim_end (where);
3682 maybe_locate_with_edit_preroll ( where );
3685 _session->add_command (new StatefulDiffCommand ((*i)->region()));
3689 commit_reversible_command ();
3692 /** Trim the end of the selected regions to the position of the edit cursor */
3694 Editor::trim_region_to_loop ()
3696 Location* loc = _session->locations()->auto_loop_location();
3700 trim_region_to_location (*loc, _("trim to loop"));
3704 Editor::trim_region_to_punch ()
3706 Location* loc = _session->locations()->auto_punch_location();
3710 trim_region_to_location (*loc, _("trim to punch"));
3714 Editor::trim_region_to_location (const Location& loc, const char* str)
3716 RegionSelection rs = get_regions_from_selection_and_entered ();
3717 bool in_command = false;
3719 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
3720 RegionView* rv = (*x);
3722 /* require region to span proposed trim */
3723 switch (rv->region()->coverage (loc.start(), loc.end())) {
3724 case Evoral::OverlapInternal:
3730 RouteTimeAxisView* tav = dynamic_cast<RouteTimeAxisView*> (&rv->get_time_axis_view());
3739 if (tav->track() != 0) {
3740 speed = tav->track()->speed();
3743 start = session_frame_to_track_frame (loc.start(), speed);
3744 end = session_frame_to_track_frame (loc.end(), speed);
3746 rv->region()->clear_changes ();
3747 rv->region()->trim_to (start, (end - start));
3750 begin_reversible_command (str);
3753 _session->add_command(new StatefulDiffCommand (rv->region()));
3757 commit_reversible_command ();
3762 Editor::trim_region_to_previous_region_end ()
3764 return trim_to_region(false);
3768 Editor::trim_region_to_next_region_start ()
3770 return trim_to_region(true);
3774 Editor::trim_to_region(bool forward)
3776 RegionSelection rs = get_regions_from_selection_and_entered ();
3777 bool in_command = false;
3779 boost::shared_ptr<Region> next_region;
3781 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
3783 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*x);
3789 AudioTimeAxisView* atav = dynamic_cast<AudioTimeAxisView*> (&arv->get_time_axis_view());
3797 if (atav->track() != 0) {
3798 speed = atav->track()->speed();
3802 boost::shared_ptr<Region> region = arv->region();
3803 boost::shared_ptr<Playlist> playlist (region->playlist());
3805 region->clear_changes ();
3809 next_region = playlist->find_next_region (region->first_frame(), Start, 1);
3815 region->trim_end((framepos_t) ( (next_region->first_frame() - 1) * speed));
3816 arv->region_changed (PropertyChange (ARDOUR::Properties::length));
3820 next_region = playlist->find_next_region (region->first_frame(), Start, 0);
3826 region->trim_front((framepos_t) ((next_region->last_frame() + 1) * speed));
3828 arv->region_changed (ARDOUR::bounds_change);
3832 begin_reversible_command (_("trim to region"));
3835 _session->add_command(new StatefulDiffCommand (region));
3839 commit_reversible_command ();
3844 Editor::unfreeze_route ()
3846 if (clicked_routeview == 0 || !clicked_routeview->is_track()) {
3850 clicked_routeview->track()->unfreeze ();
3854 Editor::_freeze_thread (void* arg)
3856 return static_cast<Editor*>(arg)->freeze_thread ();
3860 Editor::freeze_thread ()
3862 /* create event pool because we may need to talk to the session */
3863 SessionEvent::create_per_thread_pool ("freeze events", 64);
3864 /* create per-thread buffers for process() tree to use */
3865 clicked_routeview->audio_track()->freeze_me (*current_interthread_info);
3866 current_interthread_info->done = true;
3871 Editor::freeze_route ()
3877 /* stop transport before we start. this is important */
3879 _session->request_transport_speed (0.0);
3881 /* wait for just a little while, because the above call is asynchronous */
3883 Glib::usleep (250000);
3885 if (clicked_routeview == 0 || !clicked_routeview->is_audio_track()) {
3889 if (!clicked_routeview->track()->bounceable (clicked_routeview->track()->main_outs(), true)) {
3891 _("This track/bus cannot be frozen because the signal adds or loses channels before reaching the outputs.\n"
3892 "This is typically caused by plugins that generate stereo output from mono input or vice versa.")
3894 d.set_title (_("Cannot freeze"));
3899 if (clicked_routeview->track()->has_external_redirects()) {
3900 MessageDialog d (string_compose (_("<b>%1</b>\n\nThis track has at least one send/insert/return as part of its signal flow.\n\n"
3901 "Freezing will only process the signal as far as the first send/insert/return."),
3902 clicked_routeview->track()->name()), true, MESSAGE_INFO, BUTTONS_NONE, true);
3904 d.add_button (_("Freeze anyway"), Gtk::RESPONSE_OK);
3905 d.add_button (_("Don't freeze"), Gtk::RESPONSE_CANCEL);
3906 d.set_title (_("Freeze Limits"));
3908 int response = d.run ();
3911 case Gtk::RESPONSE_CANCEL:
3918 InterThreadInfo itt;
3919 current_interthread_info = &itt;
3921 InterthreadProgressWindow ipw (current_interthread_info, _("Freeze"), _("Cancel Freeze"));
3923 pthread_create_and_store (X_("freezer"), &itt.thread, _freeze_thread, this);
3925 CursorContext::Handle cursor_ctx = CursorContext::create(*this, _cursors->wait);
3927 while (!itt.done && !itt.cancel) {
3928 gtk_main_iteration ();
3931 pthread_join (itt.thread, 0);
3932 current_interthread_info = 0;
3936 Editor::bounce_range_selection (bool replace, bool enable_processing)
3938 if (selection->time.empty()) {
3942 TrackSelection views = selection->tracks;
3944 for (TrackViewList::iterator i = views.begin(); i != views.end(); ++i) {
3946 if (enable_processing) {
3948 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*i);
3950 if (rtv && rtv->track() && replace && enable_processing && !rtv->track()->bounceable (rtv->track()->main_outs(), false)) {
3952 _("You can't perform this operation because the processing of the signal "
3953 "will cause one or more of the tracks to end up with a region with more channels than this track has inputs.\n\n"
3954 "You can do this without processing, which is a different operation.")
3956 d.set_title (_("Cannot bounce"));
3963 framepos_t start = selection->time[clicked_selection].start;
3964 framepos_t end = selection->time[clicked_selection].end;
3965 framepos_t cnt = end - start + 1;
3966 bool in_command = false;
3968 for (TrackViewList::iterator i = views.begin(); i != views.end(); ++i) {
3970 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*i);
3976 boost::shared_ptr<Playlist> playlist;
3978 if ((playlist = rtv->playlist()) == 0) {
3982 InterThreadInfo itt;
3984 playlist->clear_changes ();
3985 playlist->clear_owned_changes ();
3987 boost::shared_ptr<Region> r;
3989 if (enable_processing) {
3990 r = rtv->track()->bounce_range (start, start+cnt, itt, rtv->track()->main_outs(), false);
3992 r = rtv->track()->bounce_range (start, start+cnt, itt, boost::shared_ptr<Processor>(), false);
4000 list<AudioRange> ranges;
4001 ranges.push_back (AudioRange (start, start+cnt, 0));
4002 playlist->cut (ranges); // discard result
4003 playlist->add_region (r, start);
4007 begin_reversible_command (_("bounce range"));
4010 vector<Command*> cmds;
4011 playlist->rdiff (cmds);
4012 _session->add_commands (cmds);
4014 _session->add_command (new StatefulDiffCommand (playlist));
4018 commit_reversible_command ();
4022 /** Delete selected regions, automation points or a time range */
4026 //special case: if the user is pointing in the editor/mixer strip, they may be trying to delete a plugin.
4027 //we need this because the editor-mixer strip is in the editor window, so it doesn't get the bindings from the mix window
4028 bool deleted = false;
4029 if ( current_mixer_strip && current_mixer_strip == MixerStrip::entered_mixer_strip() )
4030 deleted = current_mixer_strip->delete_processors ();
4036 /** Cut selected regions, automation points or a time range */
4043 /** Copy selected regions, automation points or a time range */
4051 /** @return true if a Cut, Copy or Clear is possible */
4053 Editor::can_cut_copy () const
4055 if (!selection->time.empty() || !selection->regions.empty() || !selection->points.empty())
4062 /** Cut, copy or clear selected regions, automation points or a time range.
4063 * @param op Operation (Delete, Cut, Copy or Clear)
4066 Editor::cut_copy (CutCopyOp op)
4068 /* only cancel selection if cut/copy is successful.*/
4074 opname = _("delete");
4083 opname = _("clear");
4087 /* if we're deleting something, and the mouse is still pressed,
4088 the thing we started a drag for will be gone when we release
4089 the mouse button(s). avoid this. see part 2 at the end of
4093 if (op == Delete || op == Cut || op == Clear) {
4094 if (_drags->active ()) {
4099 if ( op != Delete ) //"Delete" doesn't change copy/paste buf
4100 cut_buffer->clear ();
4102 if (entered_marker) {
4104 /* cut/delete op while pointing at a marker */
4107 Location* loc = find_location_from_marker (entered_marker, ignored);
4109 if (_session && loc) {
4110 entered_marker = NULL;
4111 Glib::signal_idle().connect (sigc::bind (sigc::mem_fun(*this, &Editor::really_remove_marker), loc));
4118 switch (mouse_mode) {
4121 begin_reversible_command (opname + ' ' + X_("MIDI"));
4123 commit_reversible_command ();
4129 bool did_edit = false;
4131 if (!selection->regions.empty() || !selection->points.empty()) {
4132 begin_reversible_command (opname + ' ' + _("objects"));
4135 if (!selection->regions.empty()) {
4136 cut_copy_regions (op, selection->regions);
4138 if (op == Cut || op == Delete) {
4139 selection->clear_regions ();
4143 if (!selection->points.empty()) {
4144 cut_copy_points (op);
4146 if (op == Cut || op == Delete) {
4147 selection->clear_points ();
4150 } else if (selection->time.empty()) {
4151 framepos_t start, end;
4152 /* no time selection, see if we can get an edit range
4155 if (get_edit_op_range (start, end)) {
4156 selection->set (start, end);
4158 } else if (!selection->time.empty()) {
4159 begin_reversible_command (opname + ' ' + _("range"));
4162 cut_copy_ranges (op);
4164 if (op == Cut || op == Delete) {
4165 selection->clear_time ();
4170 /* reset repeated paste state */
4173 commit_reversible_command ();
4176 if (op == Delete || op == Cut || op == Clear) {
4182 struct AutomationRecord {
4183 AutomationRecord () : state (0) , line(NULL) {}
4184 AutomationRecord (XMLNode* s, const AutomationLine* l) : state (s) , line (l) {}
4186 XMLNode* state; ///< state before any operation
4187 const AutomationLine* line; ///< line this came from
4188 boost::shared_ptr<Evoral::ControlList> copy; ///< copied events for the cut buffer
4190 struct PointsSelectionPositionSorter {
4191 bool operator() (ControlPoint* a, ControlPoint* b) {
4192 return (*(a->model()))->when < (*(b->model()))->when;
4195 /** Cut, copy or clear selected automation points.
4196 * @param op Operation (Cut, Copy or Clear)
4199 Editor::cut_copy_points (Editing::CutCopyOp op, Evoral::Beats earliest, bool midi)
4201 if (selection->points.empty ()) {
4205 /* XXX: not ideal, as there may be more than one track involved in the point selection */
4206 _last_cut_copy_source_track = &selection->points.front()->line().trackview;
4208 /* Keep a record of the AutomationLists that we end up using in this operation */
4209 typedef std::map<boost::shared_ptr<AutomationList>, AutomationRecord> Lists;
4212 /* user could select points in any order */
4213 selection->points.sort(PointsSelectionPositionSorter ());
4215 /* Go through all selected points, making an AutomationRecord for each distinct AutomationList */
4216 for (PointSelection::iterator sel_point = selection->points.begin(); sel_point != selection->points.end(); ++sel_point) {
4217 const AutomationLine& line = (*sel_point)->line();
4218 const boost::shared_ptr<AutomationList> al = line.the_list();
4219 if (lists.find (al) == lists.end ()) {
4220 /* We haven't seen this list yet, so make a record for it. This includes
4221 taking a copy of its current state, in case this is needed for undo later.
4223 lists[al] = AutomationRecord (&al->get_state (), &line);
4227 if (op == Cut || op == Copy) {
4228 /* This operation will involve putting things in the cut buffer, so create an empty
4229 ControlList for each of our source lists to put the cut buffer data in.
4231 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
4232 i->second.copy = i->first->create (i->first->parameter (), i->first->descriptor());
4235 /* Add all selected points to the relevant copy ControlLists */
4236 framepos_t start = std::numeric_limits<framepos_t>::max();
4237 for (PointSelection::iterator sel_point = selection->points.begin(); sel_point != selection->points.end(); ++sel_point) {
4238 boost::shared_ptr<AutomationList> al = (*sel_point)->line().the_list();
4239 AutomationList::const_iterator ctrl_evt = (*sel_point)->model ();
4241 lists[al].copy->fast_simple_add ((*ctrl_evt)->when, (*ctrl_evt)->value);
4243 /* Update earliest MIDI start time in beats */
4244 earliest = std::min(earliest, Evoral::Beats((*ctrl_evt)->when));
4246 /* Update earliest session start time in frames */
4247 start = std::min(start, (*sel_point)->line().session_position(ctrl_evt));
4251 /* Snap start time backwards, so copy/paste is snap aligned. */
4253 if (earliest == Evoral::Beats::max()) {
4254 earliest = Evoral::Beats(); // Weird... don't offset
4256 earliest.round_down_to_beat();
4258 if (start == std::numeric_limits<double>::max()) {
4259 start = 0; // Weird... don't offset
4261 snap_to(start, RoundDownMaybe);
4264 const double line_offset = midi ? earliest.to_double() : start;
4265 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
4266 /* Correct this copy list so that it is relative to the earliest
4267 start time, so relative ordering between points is preserved
4268 when copying from several lists and the paste starts at the
4269 earliest copied piece of data. */
4270 boost::shared_ptr<Evoral::ControlList> &al_cpy = i->second.copy;
4271 for (AutomationList::iterator ctrl_evt = al_cpy->begin(); ctrl_evt != al_cpy->end(); ++ctrl_evt) {
4272 (*ctrl_evt)->when -= line_offset;
4275 /* And add it to the cut buffer */
4276 cut_buffer->add (al_cpy);
4280 if (op == Delete || op == Cut) {
4281 /* This operation needs to remove things from the main AutomationList, so do that now */
4283 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
4284 i->first->freeze ();
4287 /* Remove each selected point from its AutomationList */
4288 for (PointSelection::iterator sel_point = selection->points.begin(); sel_point != selection->points.end(); ++sel_point) {
4289 AutomationLine& line = (*sel_point)->line ();
4290 boost::shared_ptr<AutomationList> al = line.the_list();
4294 if (dynamic_cast<AudioRegionGainLine*> (&line)) {
4295 /* removing of first and last gain point in region gain lines is prohibited*/
4296 if (line.is_last_point (*(*sel_point)) || line.is_first_point (*(*sel_point))) {
4302 al->erase ((*sel_point)->model ());
4306 /* Thaw the lists and add undo records for them */
4307 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
4308 boost::shared_ptr<AutomationList> al = i->first;
4310 _session->add_command (new MementoCommand<AutomationList> (*al.get(), i->second.state, &(al->get_state ())));
4315 /** Cut, copy or clear selected automation points.
4316 * @param op Operation (Cut, Copy or Clear)
4319 Editor::cut_copy_midi (CutCopyOp op)
4321 Evoral::Beats earliest = Evoral::Beats::max();
4322 for (MidiRegionSelection::iterator i = selection->midi_regions.begin(); i != selection->midi_regions.end(); ++i) {
4323 MidiRegionView* mrv = dynamic_cast<MidiRegionView*>(*i);
4325 if (!mrv->selection().empty()) {
4326 earliest = std::min(earliest, (*mrv->selection().begin())->note()->time());
4328 mrv->cut_copy_clear (op);
4330 /* XXX: not ideal, as there may be more than one track involved in the selection */
4331 _last_cut_copy_source_track = &mrv->get_time_axis_view();
4335 if (!selection->points.empty()) {
4336 cut_copy_points (op, earliest, true);
4337 if (op == Cut || op == Delete) {
4338 selection->clear_points ();
4343 struct lt_playlist {
4344 bool operator () (const PlaylistState& a, const PlaylistState& b) {
4345 return a.playlist < b.playlist;
4349 struct PlaylistMapping {
4351 boost::shared_ptr<Playlist> pl;
4353 PlaylistMapping (TimeAxisView* tvp) : tv (tvp) {}
4356 /** Remove `clicked_regionview' */
4358 Editor::remove_clicked_region ()
4360 if (clicked_routeview == 0 || clicked_regionview == 0) {
4364 begin_reversible_command (_("remove region"));
4366 boost::shared_ptr<Playlist> playlist = clicked_routeview->playlist();
4368 playlist->clear_changes ();
4369 playlist->clear_owned_changes ();
4370 playlist->remove_region (clicked_regionview->region());
4371 if (Config->get_edit_mode() == Ripple)
4372 playlist->ripple (clicked_regionview->region()->position(), -clicked_regionview->region()->length(), boost::shared_ptr<Region>());
4374 /* We might have removed regions, which alters other regions' layering_index,
4375 so we need to do a recursive diff here.
4377 vector<Command*> cmds;
4378 playlist->rdiff (cmds);
4379 _session->add_commands (cmds);
4381 _session->add_command(new StatefulDiffCommand (playlist));
4382 commit_reversible_command ();
4386 /** Remove the selected regions */
4388 Editor::remove_selected_regions ()
4390 RegionSelection rs = get_regions_from_selection_and_entered ();
4392 if (!_session || rs.empty()) {
4396 list<boost::shared_ptr<Region> > regions_to_remove;
4398 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
4399 // we can't just remove the region(s) in this loop because
4400 // this removes them from the RegionSelection, and they thus
4401 // disappear from underneath the iterator, and the ++i above
4402 // SEGVs in a puzzling fashion.
4404 // so, first iterate over the regions to be removed from rs and
4405 // add them to the regions_to_remove list, and then
4406 // iterate over the list to actually remove them.
4408 regions_to_remove.push_back ((*i)->region());
4411 vector<boost::shared_ptr<Playlist> > playlists;
4413 for (list<boost::shared_ptr<Region> >::iterator rl = regions_to_remove.begin(); rl != regions_to_remove.end(); ++rl) {
4415 boost::shared_ptr<Playlist> playlist = (*rl)->playlist();
4418 // is this check necessary?
4422 /* get_regions_from_selection_and_entered() guarantees that
4423 the playlists involved are unique, so there is no need
4427 playlists.push_back (playlist);
4429 playlist->clear_changes ();
4430 playlist->clear_owned_changes ();
4431 playlist->freeze ();
4432 playlist->remove_region (*rl);
4433 if (Config->get_edit_mode() == Ripple)
4434 playlist->ripple ((*rl)->position(), -(*rl)->length(), boost::shared_ptr<Region>());
4438 vector<boost::shared_ptr<Playlist> >::iterator pl;
4439 bool in_command = false;
4441 for (pl = playlists.begin(); pl != playlists.end(); ++pl) {
4444 /* We might have removed regions, which alters other regions' layering_index,
4445 so we need to do a recursive diff here.
4449 begin_reversible_command (_("remove region"));
4452 vector<Command*> cmds;
4453 (*pl)->rdiff (cmds);
4454 _session->add_commands (cmds);
4456 _session->add_command(new StatefulDiffCommand (*pl));
4460 commit_reversible_command ();
4464 /** Cut, copy or clear selected regions.
4465 * @param op Operation (Cut, Copy or Clear)
4468 Editor::cut_copy_regions (CutCopyOp op, RegionSelection& rs)
4470 /* we can't use a std::map here because the ordering is important, and we can't trivially sort
4471 a map when we want ordered access to both elements. i think.
4474 vector<PlaylistMapping> pmap;
4476 framepos_t first_position = max_framepos;
4478 typedef set<boost::shared_ptr<Playlist> > FreezeList;
4479 FreezeList freezelist;
4481 /* get ordering correct before we cut/copy */
4483 rs.sort_by_position_and_track ();
4485 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
4487 first_position = min ((framepos_t) (*x)->region()->position(), first_position);
4489 if (op == Cut || op == Clear || op == Delete) {
4490 boost::shared_ptr<Playlist> pl = (*x)->region()->playlist();
4493 FreezeList::iterator fl;
4495 // only take state if this is a new playlist.
4496 for (fl = freezelist.begin(); fl != freezelist.end(); ++fl) {
4502 if (fl == freezelist.end()) {
4503 pl->clear_changes();
4504 pl->clear_owned_changes ();
4506 freezelist.insert (pl);
4511 TimeAxisView* tv = &(*x)->get_time_axis_view();
4512 vector<PlaylistMapping>::iterator z;
4514 for (z = pmap.begin(); z != pmap.end(); ++z) {
4515 if ((*z).tv == tv) {
4520 if (z == pmap.end()) {
4521 pmap.push_back (PlaylistMapping (tv));
4525 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ) {
4527 boost::shared_ptr<Playlist> pl = (*x)->region()->playlist();
4530 /* region not yet associated with a playlist (e.g. unfinished
4537 TimeAxisView& tv = (*x)->get_time_axis_view();
4538 boost::shared_ptr<Playlist> npl;
4539 RegionSelection::iterator tmp;
4546 vector<PlaylistMapping>::iterator z;
4548 for (z = pmap.begin(); z != pmap.end(); ++z) {
4549 if ((*z).tv == &tv) {
4554 assert (z != pmap.end());
4557 npl = PlaylistFactory::create (pl->data_type(), *_session, "cutlist", true);
4565 boost::shared_ptr<Region> r = (*x)->region();
4566 boost::shared_ptr<Region> _xx;
4572 pl->remove_region (r);
4573 if (Config->get_edit_mode() == Ripple)
4574 pl->ripple (r->position(), -r->length(), boost::shared_ptr<Region>());
4578 _xx = RegionFactory::create (r);
4579 npl->add_region (_xx, r->position() - first_position);
4580 pl->remove_region (r);
4581 if (Config->get_edit_mode() == Ripple)
4582 pl->ripple (r->position(), -r->length(), boost::shared_ptr<Region>());
4586 /* copy region before adding, so we're not putting same object into two different playlists */
4587 npl->add_region (RegionFactory::create (r), r->position() - first_position);
4591 pl->remove_region (r);
4592 if (Config->get_edit_mode() == Ripple)
4593 pl->ripple (r->position(), -r->length(), boost::shared_ptr<Region>());
4602 list<boost::shared_ptr<Playlist> > foo;
4604 /* the pmap is in the same order as the tracks in which selected regions occurred */
4606 for (vector<PlaylistMapping>::iterator i = pmap.begin(); i != pmap.end(); ++i) {
4609 foo.push_back ((*i).pl);
4614 cut_buffer->set (foo);
4618 _last_cut_copy_source_track = 0;
4620 _last_cut_copy_source_track = pmap.front().tv;
4624 for (FreezeList::iterator pl = freezelist.begin(); pl != freezelist.end(); ++pl) {
4627 /* We might have removed regions, which alters other regions' layering_index,
4628 so we need to do a recursive diff here.
4630 vector<Command*> cmds;
4631 (*pl)->rdiff (cmds);
4632 _session->add_commands (cmds);
4634 _session->add_command (new StatefulDiffCommand (*pl));
4639 Editor::cut_copy_ranges (CutCopyOp op)
4641 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4643 /* Sort the track selection now, so that it if is used, the playlists
4644 selected by the calls below to cut_copy_clear are in the order that
4645 their tracks appear in the editor. This makes things like paste
4646 of ranges work properly.
4649 sort_track_selection (ts);
4652 if (!entered_track) {
4655 ts.push_back (entered_track);
4658 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4659 (*i)->cut_copy_clear (*selection, op);
4664 Editor::paste (float times, bool from_context)
4666 DEBUG_TRACE (DEBUG::CutNPaste, "paste to preferred edit pos\n");
4668 paste_internal (get_preferred_edit_position (EDIT_IGNORE_NONE, from_context), times, get_grid_music_divisions (0));
4672 Editor::mouse_paste ()
4677 if (!mouse_frame (where, ignored)) {
4682 paste_internal (where, 1, get_grid_music_divisions (0));
4686 Editor::paste_internal (framepos_t position, float times, const int32_t sub_num)
4688 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("apparent paste position is %1\n", position));
4690 if (cut_buffer->empty(internal_editing())) {
4694 if (position == max_framepos) {
4695 position = get_preferred_edit_position();
4696 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("preferred edit position is %1\n", position));
4699 if (position == last_paste_pos) {
4700 /* repeated paste in the same position */
4703 /* paste in new location, reset repeated paste state */
4705 last_paste_pos = position;
4708 /* get everything in the correct order */
4711 if (!selection->tracks.empty()) {
4712 /* If there is a track selection, paste into exactly those tracks and
4713 only those tracks. This allows the user to be explicit and override
4714 the below "do the reasonable thing" logic. */
4715 ts = selection->tracks.filter_to_unique_playlists ();
4716 sort_track_selection (ts);
4718 /* Figure out which track to base the paste at. */
4719 TimeAxisView* base_track = NULL;
4720 if (_edit_point == Editing::EditAtMouse && entered_track) {
4721 /* With the mouse edit point, paste onto the track under the mouse. */
4722 base_track = entered_track;
4723 } else if (_edit_point == Editing::EditAtMouse && entered_regionview) {
4724 /* With the mouse edit point, paste onto the track of the region under the mouse. */
4725 base_track = &entered_regionview->get_time_axis_view();
4726 } else if (_last_cut_copy_source_track) {
4727 /* Paste to the track that the cut/copy came from (see mantis #333). */
4728 base_track = _last_cut_copy_source_track;
4730 /* This is "impossible" since we've copied... well, do nothing. */
4734 /* Walk up to parent if necessary, so base track is a route. */
4735 while (base_track->get_parent()) {
4736 base_track = base_track->get_parent();
4739 /* Add base track and all tracks below it. The paste logic will select
4740 the appropriate object types from the cut buffer in relative order. */
4741 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4742 if ((*i)->order() >= base_track->order()) {
4747 /* Sort tracks so the nth track of type T will pick the nth object of type T. */
4748 sort_track_selection (ts);
4750 /* Add automation children of each track in order, for pasting several lines. */
4751 for (TrackViewList::iterator i = ts.begin(); i != ts.end();) {
4752 /* Add any automation children for pasting several lines */
4753 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*i++);
4758 typedef RouteTimeAxisView::AutomationTracks ATracks;
4759 const ATracks& atracks = rtv->automation_tracks();
4760 for (ATracks::const_iterator a = atracks.begin(); a != atracks.end(); ++a) {
4761 i = ts.insert(i, a->second.get());
4766 /* We now have a list of trackviews starting at base_track, including
4767 automation children, in the order shown in the editor, e.g. R1,
4768 R1.A1, R1.A2, R2, R2.A1, ... */
4771 begin_reversible_command (Operations::paste);
4773 if (ts.size() == 1 && cut_buffer->lines.size() == 1 &&
4774 dynamic_cast<AutomationTimeAxisView*>(ts.front())) {
4775 /* Only one line copied, and one automation track selected. Do a
4776 "greedy" paste from one automation type to another. */
4778 PasteContext ctx(paste_count, times, ItemCounts(), true);
4779 ts.front()->paste (position, *cut_buffer, ctx, sub_num);
4783 /* Paste into tracks */
4785 PasteContext ctx(paste_count, times, ItemCounts(), false);
4786 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4787 (*i)->paste (position, *cut_buffer, ctx, sub_num);
4791 commit_reversible_command ();
4795 Editor::duplicate_some_regions (RegionSelection& regions, float times)
4797 if (regions.empty ()) {
4801 boost::shared_ptr<Playlist> playlist;
4802 RegionSelection sel = regions; // clear (below) may clear the argument list if its the current region selection
4803 RegionSelection foo;
4805 framepos_t const start_frame = regions.start ();
4806 framepos_t const end_frame = regions.end_frame ();
4807 framecnt_t const gap = end_frame - start_frame + 1;
4809 begin_reversible_command (Operations::duplicate_region);
4811 selection->clear_regions ();
4813 for (RegionSelection::iterator i = sel.begin(); i != sel.end(); ++i) {
4815 boost::shared_ptr<Region> r ((*i)->region());
4817 TimeAxisView& tv = (*i)->get_time_axis_view();
4818 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (&tv);
4819 latest_regionviews.clear ();
4820 sigc::connection c = rtv->view()->RegionViewAdded.connect (sigc::mem_fun(*this, &Editor::collect_new_region_view));
4822 framepos_t const position = end_frame + (r->first_frame() - start_frame + 1);
4823 playlist = (*i)->region()->playlist();
4824 playlist->clear_changes ();
4825 playlist->duplicate (r, position, gap, times);
4826 _session->add_command(new StatefulDiffCommand (playlist));
4830 foo.insert (foo.end(), latest_regionviews.begin(), latest_regionviews.end());
4834 selection->set (foo);
4837 commit_reversible_command ();
4841 Editor::duplicate_selection (float times)
4843 if (selection->time.empty() || selection->tracks.empty()) {
4847 boost::shared_ptr<Playlist> playlist;
4849 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4851 bool in_command = false;
4853 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4854 if ((playlist = (*i)->playlist()) == 0) {
4857 playlist->clear_changes ();
4859 if (clicked_selection) {
4860 playlist->duplicate_range (selection->time[clicked_selection], times);
4862 playlist->duplicate_ranges (selection->time, times);
4866 begin_reversible_command (_("duplicate range selection"));
4869 _session->add_command (new StatefulDiffCommand (playlist));
4874 // now "move" range selection to after the current range selection
4875 framecnt_t distance = 0;
4877 if (clicked_selection) {
4878 distance = selection->time[clicked_selection].end -
4879 selection->time[clicked_selection].start;
4881 distance = selection->time.end_frame() - selection->time.start();
4884 selection->move_time (distance);
4886 commit_reversible_command ();
4890 /** Reset all selected points to the relevant default value */
4892 Editor::reset_point_selection ()
4894 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
4895 ARDOUR::AutomationList::iterator j = (*i)->model ();
4896 (*j)->value = (*i)->line().the_list()->default_value ();
4901 Editor::center_playhead ()
4903 float const page = _visible_canvas_width * samples_per_pixel;
4904 center_screen_internal (playhead_cursor->current_frame (), page);
4908 Editor::center_edit_point ()
4910 float const page = _visible_canvas_width * samples_per_pixel;
4911 center_screen_internal (get_preferred_edit_position(), page);
4914 /** Caller must begin and commit a reversible command */
4916 Editor::clear_playlist (boost::shared_ptr<Playlist> playlist)
4918 playlist->clear_changes ();
4920 _session->add_command (new StatefulDiffCommand (playlist));
4924 Editor::nudge_track (bool use_edit, bool forwards)
4926 boost::shared_ptr<Playlist> playlist;
4927 framepos_t distance;
4928 framepos_t next_distance;
4932 start = get_preferred_edit_position();
4937 if ((distance = get_nudge_distance (start, next_distance)) == 0) {
4941 if (selection->tracks.empty()) {
4945 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4946 bool in_command = false;
4948 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4950 if ((playlist = (*i)->playlist()) == 0) {
4954 playlist->clear_changes ();
4955 playlist->clear_owned_changes ();
4957 playlist->nudge_after (start, distance, forwards);
4960 begin_reversible_command (_("nudge track"));
4963 vector<Command*> cmds;
4965 playlist->rdiff (cmds);
4966 _session->add_commands (cmds);
4968 _session->add_command (new StatefulDiffCommand (playlist));
4972 commit_reversible_command ();
4977 Editor::remove_last_capture ()
4979 vector<string> choices;
4986 if (Config->get_verify_remove_last_capture()) {
4987 prompt = _("Do you really want to destroy the last capture?"
4988 "\n(This is destructive and cannot be undone)");
4990 choices.push_back (_("No, do nothing."));
4991 choices.push_back (_("Yes, destroy it."));
4993 Gtkmm2ext::Choice prompter (_("Destroy last capture"), prompt, choices);
4995 if (prompter.run () == 1) {
4996 _session->remove_last_capture ();
4997 _regions->redisplay ();
5001 _session->remove_last_capture();
5002 _regions->redisplay ();
5007 Editor::normalize_region ()
5013 RegionSelection rs = get_regions_from_selection_and_entered ();
5019 NormalizeDialog dialog (rs.size() > 1);
5021 if (dialog.run () == RESPONSE_CANCEL) {
5025 CursorContext::Handle cursor_ctx = CursorContext::create(*this, _cursors->wait);
5028 /* XXX: should really only count audio regions here */
5029 int const regions = rs.size ();
5031 /* Make a list of the selected audio regions' maximum amplitudes, and also
5032 obtain the maximum amplitude of them all.
5034 list<double> max_amps;
5035 list<double> rms_vals;
5038 bool use_rms = dialog.constrain_rms ();
5040 for (RegionSelection::const_iterator i = rs.begin(); i != rs.end(); ++i) {
5041 AudioRegionView const * arv = dynamic_cast<AudioRegionView const *> (*i);
5045 dialog.descend (1.0 / regions);
5046 double const a = arv->audio_region()->maximum_amplitude (&dialog);
5048 double r = arv->audio_region()->rms (&dialog);
5049 max_rms = max (max_rms, r);
5050 rms_vals.push_back (r);
5054 /* the user cancelled the operation */
5058 max_amps.push_back (a);
5059 max_amp = max (max_amp, a);
5063 list<double>::const_iterator a = max_amps.begin ();
5064 list<double>::const_iterator l = rms_vals.begin ();
5065 bool in_command = false;
5067 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
5068 AudioRegionView* const arv = dynamic_cast<AudioRegionView*> (*r);
5073 arv->region()->clear_changes ();
5075 double amp = dialog.normalize_individually() ? *a : max_amp;
5076 double target = dialog.target_peak (); // dB
5079 double const amp_rms = dialog.normalize_individually() ? *l : max_rms;
5080 const double t_rms = dialog.target_rms ();
5081 const gain_t c_peak = dB_to_coefficient (target);
5082 const gain_t c_rms = dB_to_coefficient (t_rms);
5083 if ((amp_rms / c_rms) > (amp / c_peak)) {
5089 arv->audio_region()->normalize (amp, target);
5092 begin_reversible_command (_("normalize"));
5095 _session->add_command (new StatefulDiffCommand (arv->region()));
5102 commit_reversible_command ();
5108 Editor::reset_region_scale_amplitude ()
5114 RegionSelection rs = get_regions_from_selection_and_entered ();
5120 bool in_command = false;
5122 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
5123 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
5126 arv->region()->clear_changes ();
5127 arv->audio_region()->set_scale_amplitude (1.0f);
5130 begin_reversible_command ("reset gain");
5133 _session->add_command (new StatefulDiffCommand (arv->region()));
5137 commit_reversible_command ();
5142 Editor::adjust_region_gain (bool up)
5144 RegionSelection rs = get_regions_from_selection_and_entered ();
5146 if (!_session || rs.empty()) {
5150 bool in_command = false;
5152 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
5153 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
5158 arv->region()->clear_changes ();
5160 double dB = accurate_coefficient_to_dB (arv->audio_region()->scale_amplitude ());
5168 arv->audio_region()->set_scale_amplitude (dB_to_coefficient (dB));
5171 begin_reversible_command ("adjust region gain");
5174 _session->add_command (new StatefulDiffCommand (arv->region()));
5178 commit_reversible_command ();
5184 Editor::reverse_region ()
5190 Reverse rev (*_session);
5191 apply_filter (rev, _("reverse regions"));
5195 Editor::strip_region_silence ()
5201 RegionSelection rs = get_regions_from_selection_and_entered ();
5207 std::list<RegionView*> audio_only;
5209 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5210 AudioRegionView* const arv = dynamic_cast<AudioRegionView*> (*i);
5212 audio_only.push_back (arv);
5216 assert (!audio_only.empty());
5218 StripSilenceDialog d (_session, audio_only);
5219 int const r = d.run ();
5223 if (r == Gtk::RESPONSE_OK) {
5224 ARDOUR::AudioIntervalMap silences;
5225 d.silences (silences);
5226 StripSilence s (*_session, silences, d.fade_length());
5228 apply_filter (s, _("strip silence"), &d);
5233 Editor::apply_midi_note_edit_op_to_region (MidiOperator& op, MidiRegionView& mrv)
5235 Evoral::Sequence<Evoral::Beats>::Notes selected;
5236 mrv.selection_as_notelist (selected, true);
5238 vector<Evoral::Sequence<Evoral::Beats>::Notes> v;
5239 v.push_back (selected);
5241 framepos_t pos_frames = mrv.midi_region()->position() - mrv.midi_region()->start();
5242 Evoral::Beats pos_beats = _session->tempo_map().framewalk_to_beats(0, pos_frames);
5244 return op (mrv.midi_region()->model(), pos_beats, v);
5248 Editor::apply_midi_note_edit_op (MidiOperator& op, const RegionSelection& rs)
5254 bool in_command = false;
5256 for (RegionSelection::const_iterator r = rs.begin(); r != rs.end(); ) {
5257 RegionSelection::const_iterator tmp = r;
5260 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*r);
5263 Command* cmd = apply_midi_note_edit_op_to_region (op, *mrv);
5266 begin_reversible_command (op.name ());
5270 _session->add_command (cmd);
5278 commit_reversible_command ();
5283 Editor::fork_region ()
5285 RegionSelection rs = get_regions_from_selection_and_entered ();
5291 CursorContext::Handle cursor_ctx = CursorContext::create(*this, _cursors->wait);
5292 bool in_command = false;
5296 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
5297 RegionSelection::iterator tmp = r;
5300 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*>(*r);
5304 boost::shared_ptr<Playlist> playlist = mrv->region()->playlist();
5305 boost::shared_ptr<MidiSource> new_source = _session->create_midi_source_by_stealing_name (mrv->midi_view()->track());
5306 boost::shared_ptr<MidiRegion> newregion = mrv->midi_region()->clone (new_source);
5309 begin_reversible_command (_("Fork Region(s)"));
5312 playlist->clear_changes ();
5313 playlist->replace_region (mrv->region(), newregion, mrv->region()->position());
5314 _session->add_command(new StatefulDiffCommand (playlist));
5316 error << string_compose (_("Could not unlink %1"), mrv->region()->name()) << endmsg;
5324 commit_reversible_command ();
5329 Editor::quantize_region ()
5332 quantize_regions(get_regions_from_selection_and_entered ());
5337 Editor::quantize_regions (const RegionSelection& rs)
5339 if (rs.n_midi_regions() == 0) {
5343 if (!quantize_dialog) {
5344 quantize_dialog = new QuantizeDialog (*this);
5347 quantize_dialog->present ();
5348 const int r = quantize_dialog->run ();
5349 quantize_dialog->hide ();
5351 if (r == Gtk::RESPONSE_OK) {
5352 Quantize quant (quantize_dialog->snap_start(),
5353 quantize_dialog->snap_end(),
5354 quantize_dialog->start_grid_size(),
5355 quantize_dialog->end_grid_size(),
5356 quantize_dialog->strength(),
5357 quantize_dialog->swing(),
5358 quantize_dialog->threshold());
5360 apply_midi_note_edit_op (quant, rs);
5365 Editor::legatize_region (bool shrink_only)
5368 legatize_regions(get_regions_from_selection_and_entered (), shrink_only);
5373 Editor::legatize_regions (const RegionSelection& rs, bool shrink_only)
5375 if (rs.n_midi_regions() == 0) {
5379 Legatize legatize(shrink_only);
5380 apply_midi_note_edit_op (legatize, rs);
5384 Editor::transform_region ()
5387 transform_regions(get_regions_from_selection_and_entered ());
5392 Editor::transform_regions (const RegionSelection& rs)
5394 if (rs.n_midi_regions() == 0) {
5401 const int r = td.run();
5404 if (r == Gtk::RESPONSE_OK) {
5405 Transform transform(td.get());
5406 apply_midi_note_edit_op(transform, rs);
5411 Editor::transpose_region ()
5414 transpose_regions(get_regions_from_selection_and_entered ());
5419 Editor::transpose_regions (const RegionSelection& rs)
5421 if (rs.n_midi_regions() == 0) {
5426 int const r = d.run ();
5428 if (r == RESPONSE_ACCEPT) {
5429 Transpose transpose(d.semitones ());
5430 apply_midi_note_edit_op (transpose, rs);
5435 Editor::insert_patch_change (bool from_context)
5437 RegionSelection rs = get_regions_from_selection_and_entered ();
5443 const framepos_t p = get_preferred_edit_position (EDIT_IGNORE_NONE, from_context);
5445 /* XXX: bit of a hack; use the MIDNAM from the first selected region;
5446 there may be more than one, but the PatchChangeDialog can only offer
5447 one set of patch menus.
5449 MidiRegionView* first = dynamic_cast<MidiRegionView*> (rs.front ());
5451 Evoral::PatchChange<Evoral::Beats> empty (Evoral::Beats(), 0, 0, 0);
5452 PatchChangeDialog d (0, _session, empty, first->instrument_info(), Gtk::Stock::ADD);
5454 if (d.run() == RESPONSE_CANCEL) {
5458 for (RegionSelection::iterator i = rs.begin (); i != rs.end(); ++i) {
5459 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*i);
5461 if (p >= mrv->region()->first_frame() && p <= mrv->region()->last_frame()) {
5462 mrv->add_patch_change (p - mrv->region()->position(), d.patch ());
5469 Editor::apply_filter (Filter& filter, string command, ProgressReporter* progress)
5471 RegionSelection rs = get_regions_from_selection_and_entered ();
5477 CursorContext::Handle cursor_ctx = CursorContext::create(*this, _cursors->wait);
5478 bool in_command = false;
5483 int const N = rs.size ();
5485 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
5486 RegionSelection::iterator tmp = r;
5489 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
5491 boost::shared_ptr<Playlist> playlist = arv->region()->playlist();
5494 progress->descend (1.0 / N);
5497 if (arv->audio_region()->apply (filter, progress) == 0) {
5499 playlist->clear_changes ();
5500 playlist->clear_owned_changes ();
5503 begin_reversible_command (command);
5507 if (filter.results.empty ()) {
5509 /* no regions returned; remove the old one */
5510 playlist->remove_region (arv->region ());
5514 std::vector<boost::shared_ptr<Region> >::iterator res = filter.results.begin ();
5516 /* first region replaces the old one */
5517 playlist->replace_region (arv->region(), *res, (*res)->position());
5521 while (res != filter.results.end()) {
5522 playlist->add_region (*res, (*res)->position());
5528 /* We might have removed regions, which alters other regions' layering_index,
5529 so we need to do a recursive diff here.
5531 vector<Command*> cmds;
5532 playlist->rdiff (cmds);
5533 _session->add_commands (cmds);
5535 _session->add_command(new StatefulDiffCommand (playlist));
5539 progress->ascend ();
5548 commit_reversible_command ();
5553 Editor::external_edit_region ()
5559 Editor::reset_region_gain_envelopes ()
5561 RegionSelection rs = get_regions_from_selection_and_entered ();
5563 if (!_session || rs.empty()) {
5567 bool in_command = false;
5569 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5570 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
5572 boost::shared_ptr<AutomationList> alist (arv->audio_region()->envelope());
5573 XMLNode& before (alist->get_state());
5575 arv->audio_region()->set_default_envelope ();
5578 begin_reversible_command (_("reset region gain"));
5581 _session->add_command (new MementoCommand<AutomationList>(*arv->audio_region()->envelope().get(), &before, &alist->get_state()));
5586 commit_reversible_command ();
5591 Editor::set_region_gain_visibility (RegionView* rv)
5593 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (rv);
5595 arv->update_envelope_visibility();
5600 Editor::set_gain_envelope_visibility ()
5606 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5607 AudioTimeAxisView* v = dynamic_cast<AudioTimeAxisView*>(*i);
5609 v->audio_view()->foreach_regionview (sigc::mem_fun (this, &Editor::set_region_gain_visibility));
5615 Editor::toggle_gain_envelope_active ()
5617 if (_ignore_region_action) {
5621 RegionSelection rs = get_regions_from_selection_and_entered ();
5623 if (!_session || rs.empty()) {
5627 bool in_command = false;
5629 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5630 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
5632 arv->region()->clear_changes ();
5633 arv->audio_region()->set_envelope_active (!arv->audio_region()->envelope_active());
5636 begin_reversible_command (_("region gain envelope active"));
5639 _session->add_command (new StatefulDiffCommand (arv->region()));
5644 commit_reversible_command ();
5649 Editor::toggle_region_lock ()
5651 if (_ignore_region_action) {
5655 RegionSelection rs = get_regions_from_selection_and_entered ();
5657 if (!_session || rs.empty()) {
5661 begin_reversible_command (_("toggle region lock"));
5663 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5664 (*i)->region()->clear_changes ();
5665 (*i)->region()->set_locked (!(*i)->region()->locked());
5666 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5669 commit_reversible_command ();
5673 Editor::toggle_region_video_lock ()
5675 if (_ignore_region_action) {
5679 RegionSelection rs = get_regions_from_selection_and_entered ();
5681 if (!_session || rs.empty()) {
5685 begin_reversible_command (_("Toggle Video Lock"));
5687 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5688 (*i)->region()->clear_changes ();
5689 (*i)->region()->set_video_locked (!(*i)->region()->video_locked());
5690 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5693 commit_reversible_command ();
5697 Editor::toggle_region_lock_style ()
5699 if (_ignore_region_action) {
5703 RegionSelection rs = get_regions_from_selection_and_entered ();
5705 if (!_session || rs.empty()) {
5709 begin_reversible_command (_("region lock style"));
5711 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5712 (*i)->region()->clear_changes ();
5713 PositionLockStyle const ns = (*i)->region()->position_lock_style() == AudioTime ? MusicTime : AudioTime;
5714 (*i)->region()->set_position_lock_style (ns);
5715 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5718 commit_reversible_command ();
5722 Editor::toggle_opaque_region ()
5724 if (_ignore_region_action) {
5728 RegionSelection rs = get_regions_from_selection_and_entered ();
5730 if (!_session || rs.empty()) {
5734 begin_reversible_command (_("change region opacity"));
5736 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5737 (*i)->region()->clear_changes ();
5738 (*i)->region()->set_opaque (!(*i)->region()->opaque());
5739 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5742 commit_reversible_command ();
5746 Editor::toggle_record_enable ()
5748 bool new_state = false;
5750 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5751 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5754 if (!rtav->is_track())
5758 new_state = !rtav->track()->rec_enable_control()->get_value();
5762 rtav->track()->rec_enable_control()->set_value (new_state, Controllable::UseGroup);
5767 Editor::toggle_solo ()
5769 bool new_state = false;
5771 boost::shared_ptr<ControlList> cl (new ControlList);
5773 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5774 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5781 new_state = !rtav->route()->soloed ();
5785 cl->push_back (rtav->route()->solo_control());
5788 _session->set_controls (cl, new_state ? 1.0 : 0.0, Controllable::UseGroup);
5792 Editor::toggle_mute ()
5794 bool new_state = false;
5796 boost::shared_ptr<RouteList> rl (new RouteList);
5798 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5799 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5806 new_state = !rtav->route()->muted();
5810 rl->push_back (rtav->route());
5813 _session->set_controls (route_list_to_control_list (rl, &Stripable::mute_control), new_state, Controllable::UseGroup);
5817 Editor::toggle_solo_isolate ()
5823 Editor::fade_range ()
5825 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
5827 begin_reversible_command (_("fade range"));
5829 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
5830 (*i)->fade_range (selection->time);
5833 commit_reversible_command ();
5838 Editor::set_fade_length (bool in)
5840 RegionSelection rs = get_regions_from_selection_and_entered ();
5846 /* we need a region to measure the offset from the start */
5848 RegionView* rv = rs.front ();
5850 framepos_t pos = get_preferred_edit_position();
5854 if (pos > rv->region()->last_frame() || pos < rv->region()->first_frame()) {
5855 /* edit point is outside the relevant region */
5860 if (pos <= rv->region()->position()) {
5864 len = pos - rv->region()->position();
5865 cmd = _("set fade in length");
5867 if (pos >= rv->region()->last_frame()) {
5871 len = rv->region()->last_frame() - pos;
5872 cmd = _("set fade out length");
5875 bool in_command = false;
5877 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5878 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5884 boost::shared_ptr<AutomationList> alist;
5886 alist = tmp->audio_region()->fade_in();
5888 alist = tmp->audio_region()->fade_out();
5891 XMLNode &before = alist->get_state();
5894 tmp->audio_region()->set_fade_in_length (len);
5895 tmp->audio_region()->set_fade_in_active (true);
5897 tmp->audio_region()->set_fade_out_length (len);
5898 tmp->audio_region()->set_fade_out_active (true);
5902 begin_reversible_command (cmd);
5905 XMLNode &after = alist->get_state();
5906 _session->add_command(new MementoCommand<AutomationList>(*alist, &before, &after));
5910 commit_reversible_command ();
5915 Editor::set_fade_in_shape (FadeShape shape)
5917 RegionSelection rs = get_regions_from_selection_and_entered ();
5922 bool in_command = false;
5924 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5925 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5931 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_in();
5932 XMLNode &before = alist->get_state();
5934 tmp->audio_region()->set_fade_in_shape (shape);
5937 begin_reversible_command (_("set fade in shape"));
5940 XMLNode &after = alist->get_state();
5941 _session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
5945 commit_reversible_command ();
5950 Editor::set_fade_out_shape (FadeShape shape)
5952 RegionSelection rs = get_regions_from_selection_and_entered ();
5957 bool in_command = false;
5959 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5960 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5966 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_out();
5967 XMLNode &before = alist->get_state();
5969 tmp->audio_region()->set_fade_out_shape (shape);
5972 begin_reversible_command (_("set fade out shape"));
5975 XMLNode &after = alist->get_state();
5976 _session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
5980 commit_reversible_command ();
5985 Editor::set_fade_in_active (bool yn)
5987 RegionSelection rs = get_regions_from_selection_and_entered ();
5992 bool in_command = false;
5994 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5995 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
6002 boost::shared_ptr<AudioRegion> ar (tmp->audio_region());
6004 ar->clear_changes ();
6005 ar->set_fade_in_active (yn);
6008 begin_reversible_command (_("set fade in active"));
6011 _session->add_command (new StatefulDiffCommand (ar));
6015 commit_reversible_command ();
6020 Editor::set_fade_out_active (bool yn)
6022 RegionSelection rs = get_regions_from_selection_and_entered ();
6027 bool in_command = false;
6029 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
6030 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
6036 boost::shared_ptr<AudioRegion> ar (tmp->audio_region());
6038 ar->clear_changes ();
6039 ar->set_fade_out_active (yn);
6042 begin_reversible_command (_("set fade out active"));
6045 _session->add_command(new StatefulDiffCommand (ar));
6049 commit_reversible_command ();
6054 Editor::toggle_region_fades (int dir)
6056 if (_ignore_region_action) {
6060 boost::shared_ptr<AudioRegion> ar;
6063 RegionSelection rs = get_regions_from_selection_and_entered ();
6069 RegionSelection::iterator i;
6070 for (i = rs.begin(); i != rs.end(); ++i) {
6071 if ((ar = boost::dynamic_pointer_cast<AudioRegion>((*i)->region())) != 0) {
6073 yn = ar->fade_out_active ();
6075 yn = ar->fade_in_active ();
6081 if (i == rs.end()) {
6085 /* XXX should this undo-able? */
6086 bool in_command = false;
6088 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
6089 if ((ar = boost::dynamic_pointer_cast<AudioRegion>((*i)->region())) == 0) {
6092 ar->clear_changes ();
6094 if (dir == 1 || dir == 0) {
6095 ar->set_fade_in_active (!yn);
6098 if (dir == -1 || dir == 0) {
6099 ar->set_fade_out_active (!yn);
6102 begin_reversible_command (_("toggle fade active"));
6105 _session->add_command(new StatefulDiffCommand (ar));
6109 commit_reversible_command ();
6114 /** Update region fade visibility after its configuration has been changed */
6116 Editor::update_region_fade_visibility ()
6118 bool _fade_visibility = _session->config.get_show_region_fades ();
6120 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
6121 AudioTimeAxisView* v = dynamic_cast<AudioTimeAxisView*>(*i);
6123 if (_fade_visibility) {
6124 v->audio_view()->show_all_fades ();
6126 v->audio_view()->hide_all_fades ();
6133 Editor::set_edit_point ()
6138 if (!mouse_frame (where, ignored)) {
6144 if (selection->markers.empty()) {
6146 mouse_add_new_marker (where);
6151 Location* loc = find_location_from_marker (selection->markers.front(), ignored);
6154 loc->move_to (where);
6160 Editor::set_playhead_cursor ()
6162 if (entered_marker) {
6163 _session->request_locate (entered_marker->position(), _session->transport_rolling());
6168 if (!mouse_frame (where, ignored)) {
6175 _session->request_locate (where, _session->transport_rolling());
6179 if (UIConfiguration::instance().get_follow_edits() && (!_session || !_session->config.get_external_sync())) {
6180 cancel_time_selection();
6185 Editor::split_region ()
6187 if (_drags->active ()) {
6191 //if a range is selected, separate it
6192 if ( !selection->time.empty()) {
6193 separate_regions_between (selection->time);
6197 //if no range was selected, try to find some regions to split
6198 if (current_mouse_mode() == MouseObject) { //don't try this for Internal Edit, Stretch, Draw, etc.
6200 RegionSelection rs = get_regions_from_selection_and_edit_point ();
6202 framepos_t where = get_preferred_edit_position ();
6208 if (snap_musical()) {
6209 split_regions_at (where, rs, get_grid_music_divisions (0));
6211 split_regions_at (where, rs, 0);
6217 Editor::select_next_route()
6219 if (selection->tracks.empty()) {
6220 selection->set (track_views.front());
6224 TimeAxisView* current = selection->tracks.front();
6228 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
6230 if (*i == current) {
6232 if (i != track_views.end()) {
6235 current = (*(track_views.begin()));
6236 //selection->set (*(track_views.begin()));
6242 rui = dynamic_cast<RouteUI *>(current);
6244 } while (current->hidden() || (rui == NULL) || !rui->route()->active());
6246 selection->set (current);
6248 ensure_time_axis_view_is_visible (*current, false);
6252 Editor::select_prev_route()
6254 if (selection->tracks.empty()) {
6255 selection->set (track_views.front());
6259 TimeAxisView* current = selection->tracks.front();
6263 for (TrackViewList::reverse_iterator i = track_views.rbegin(); i != track_views.rend(); ++i) {
6265 if (*i == current) {
6267 if (i != track_views.rend()) {
6270 current = *(track_views.rbegin());
6275 rui = dynamic_cast<RouteUI *>(current);
6277 } while (current->hidden() || (rui == NULL) || !rui->route()->active());
6279 selection->set (current);
6281 ensure_time_axis_view_is_visible (*current, false);
6285 Editor::set_loop_from_selection (bool play)
6287 if (_session == 0) {
6291 framepos_t start, end;
6292 if (!get_selection_extents ( start, end))
6295 set_loop_range (start, end, _("set loop range from selection"));
6298 _session->request_play_loop (true, true);
6303 Editor::set_loop_from_region (bool play)
6305 framepos_t start, end;
6306 if (!get_selection_extents ( start, end))
6309 set_loop_range (start, end, _("set loop range from region"));
6312 _session->request_locate (start, true);
6313 _session->request_play_loop (true);
6318 Editor::set_punch_from_selection ()
6320 if (_session == 0) {
6324 framepos_t start, end;
6325 if (!get_selection_extents ( start, end))
6328 set_punch_range (start, end, _("set punch range from selection"));
6332 Editor::set_session_extents_from_selection ()
6334 if (_session == 0) {
6338 framepos_t start, end;
6339 if (!get_selection_extents ( start, end))
6343 if ((loc = _session->locations()->session_range_location()) == 0) {
6344 _session->set_session_extents (start, end); // this will create a new session range; no need for UNDO
6346 XMLNode &before = loc->get_state();
6348 _session->set_session_extents (start, end);
6350 XMLNode &after = loc->get_state();
6352 begin_reversible_command (_("set session start/end from selection"));
6354 _session->add_command (new MementoCommand<Location>(*loc, &before, &after));
6356 commit_reversible_command ();
6359 _session->set_end_is_free (false);
6363 Editor::set_punch_start_from_edit_point ()
6367 framepos_t start = 0;
6368 framepos_t end = max_framepos;
6370 //use the existing punch end, if any
6371 Location* tpl = transport_punch_location();
6376 if ((_edit_point == EditAtPlayhead) && _session->transport_rolling()) {
6377 start = _session->audible_frame();
6379 start = get_preferred_edit_position();
6382 //snap the selection start/end
6385 //if there's not already a sensible selection endpoint, go "forever"
6386 if ( start > end ) {
6390 set_punch_range (start, end, _("set punch start from EP"));
6396 Editor::set_punch_end_from_edit_point ()
6400 framepos_t start = 0;
6401 framepos_t end = max_framepos;
6403 //use the existing punch start, if any
6404 Location* tpl = transport_punch_location();
6406 start = tpl->start();
6409 if ((_edit_point == EditAtPlayhead) && _session->transport_rolling()) {
6410 end = _session->audible_frame();
6412 end = get_preferred_edit_position();
6415 //snap the selection start/end
6418 set_punch_range (start, end, _("set punch end from EP"));
6424 Editor::set_loop_start_from_edit_point ()
6428 framepos_t start = 0;
6429 framepos_t end = max_framepos;
6431 //use the existing loop end, if any
6432 Location* tpl = transport_loop_location();
6437 if ((_edit_point == EditAtPlayhead) && _session->transport_rolling()) {
6438 start = _session->audible_frame();
6440 start = get_preferred_edit_position();
6443 //snap the selection start/end
6446 //if there's not already a sensible selection endpoint, go "forever"
6447 if ( start > end ) {
6451 set_loop_range (start, end, _("set loop start from EP"));
6457 Editor::set_loop_end_from_edit_point ()
6461 framepos_t start = 0;
6462 framepos_t end = max_framepos;
6464 //use the existing loop start, if any
6465 Location* tpl = transport_loop_location();
6467 start = tpl->start();
6470 if ((_edit_point == EditAtPlayhead) && _session->transport_rolling()) {
6471 end = _session->audible_frame();
6473 end = get_preferred_edit_position();
6476 //snap the selection start/end
6479 set_loop_range (start, end, _("set loop end from EP"));
6484 Editor::set_punch_from_region ()
6486 framepos_t start, end;
6487 if (!get_selection_extents ( start, end))
6490 set_punch_range (start, end, _("set punch range from region"));
6494 Editor::pitch_shift_region ()
6496 RegionSelection rs = get_regions_from_selection_and_entered ();
6498 RegionSelection audio_rs;
6499 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
6500 if (dynamic_cast<AudioRegionView*> (*i)) {
6501 audio_rs.push_back (*i);
6505 if (audio_rs.empty()) {
6509 pitch_shift (audio_rs, 1.2);
6513 Editor::set_tempo_from_region ()
6515 RegionSelection rs = get_regions_from_selection_and_entered ();
6517 if (!_session || rs.empty()) {
6521 RegionView* rv = rs.front();
6523 define_one_bar (rv->region()->position(), rv->region()->last_frame() + 1);
6527 Editor::use_range_as_bar ()
6529 framepos_t start, end;
6530 if (get_edit_op_range (start, end)) {
6531 define_one_bar (start, end);
6536 Editor::define_one_bar (framepos_t start, framepos_t end)
6538 framepos_t length = end - start;
6540 const Meter& m (_session->tempo_map().meter_at_frame (start));
6542 /* length = 1 bar */
6544 /* We're going to deliver a constant tempo here,
6545 so we can use frames per beat to determine length.
6546 now we want frames per beat.
6547 we have frames per bar, and beats per bar, so ...
6550 /* XXXX METER MATH */
6552 double frames_per_beat = length / m.divisions_per_bar();
6554 /* beats per minute = */
6556 double beats_per_minute = (_session->frame_rate() * 60.0) / frames_per_beat;
6558 /* now decide whether to:
6560 (a) set global tempo
6561 (b) add a new tempo marker
6565 const TempoSection& t (_session->tempo_map().tempo_section_at_frame (start));
6567 bool do_global = false;
6569 if ((_session->tempo_map().n_tempos() == 1) && (_session->tempo_map().n_meters() == 1)) {
6571 /* only 1 tempo & 1 meter: ask if the user wants to set the tempo
6572 at the start, or create a new marker
6575 vector<string> options;
6576 options.push_back (_("Cancel"));
6577 options.push_back (_("Add new marker"));
6578 options.push_back (_("Set global tempo"));
6581 _("Define one bar"),
6582 _("Do you want to set the global tempo or add a new tempo marker?"),
6586 c.set_default_response (2);
6602 /* more than 1 tempo and/or meter section already, go ahead do the "usual":
6603 if the marker is at the region starter, change it, otherwise add
6608 begin_reversible_command (_("set tempo from region"));
6609 XMLNode& before (_session->tempo_map().get_state());
6612 _session->tempo_map().change_initial_tempo (beats_per_minute, t.note_type());
6613 } else if (t.frame() == start) {
6614 _session->tempo_map().change_existing_tempo_at (start, beats_per_minute, t.note_type());
6616 const Tempo tempo (beats_per_minute, t.note_type());
6617 _session->tempo_map().add_tempo (tempo, 0.0, start, TempoSection::Constant, AudioTime);
6620 XMLNode& after (_session->tempo_map().get_state());
6622 _session->add_command (new MementoCommand<TempoMap>(_session->tempo_map(), &before, &after));
6623 commit_reversible_command ();
6627 Editor::split_region_at_transients ()
6629 AnalysisFeatureList positions;
6631 RegionSelection rs = get_regions_from_selection_and_entered ();
6633 if (!_session || rs.empty()) {
6637 begin_reversible_command (_("split regions"));
6639 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ) {
6641 RegionSelection::iterator tmp;
6646 boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion> ((*i)->region());
6649 ar->transients (positions);
6650 split_region_at_points ((*i)->region(), positions, true);
6657 commit_reversible_command ();
6662 Editor::split_region_at_points (boost::shared_ptr<Region> r, AnalysisFeatureList& positions, bool can_ferret, bool select_new)
6664 bool use_rhythmic_rodent = false;
6666 boost::shared_ptr<Playlist> pl = r->playlist();
6668 list<boost::shared_ptr<Region> > new_regions;
6674 if (positions.empty()) {
6678 if (positions.size() > 20 && can_ferret) {
6679 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);
6680 MessageDialog msg (msgstr,
6683 Gtk::BUTTONS_OK_CANCEL);
6686 msg.add_button (_("Call for the Ferret!"), RESPONSE_APPLY);
6687 msg.set_secondary_text (_("Press OK to continue with this split operation\nor ask the Ferret dialog to tune the analysis"));
6689 msg.set_secondary_text (_("Press OK to continue with this split operation"));
6692 msg.set_title (_("Excessive split?"));
6695 int response = msg.run();
6701 case RESPONSE_APPLY:
6702 use_rhythmic_rodent = true;
6709 if (use_rhythmic_rodent) {
6710 show_rhythm_ferret ();
6714 AnalysisFeatureList::const_iterator x;
6716 pl->clear_changes ();
6717 pl->clear_owned_changes ();
6719 x = positions.begin();
6721 if (x == positions.end()) {
6726 pl->remove_region (r);
6730 framepos_t rstart = r->first_frame ();
6731 framepos_t rend = r->last_frame ();
6733 while (x != positions.end()) {
6735 /* deal with positons that are out of scope of present region bounds */
6736 if (*x <= rstart || *x > rend) {
6741 /* file start = original start + how far we from the initial position ? */
6743 framepos_t file_start = r->start() + pos;
6745 /* length = next position - current position */
6747 framepos_t len = (*x) - pos - rstart;
6749 /* XXX we do we really want to allow even single-sample regions?
6750 * shouldn't we have some kind of lower limit on region size?
6759 if (RegionFactory::region_name (new_name, r->name())) {
6763 /* do NOT announce new regions 1 by one, just wait till they are all done */
6767 plist.add (ARDOUR::Properties::start, file_start);
6768 plist.add (ARDOUR::Properties::length, len);
6769 plist.add (ARDOUR::Properties::name, new_name);
6770 plist.add (ARDOUR::Properties::layer, 0);
6771 // TODO set transients_offset
6773 boost::shared_ptr<Region> nr = RegionFactory::create (r->sources(), plist, false);
6774 /* because we set annouce to false, manually add the new region to the
6777 RegionFactory::map_add (nr);
6779 pl->add_region (nr, rstart + pos);
6782 new_regions.push_front(nr);
6791 RegionFactory::region_name (new_name, r->name());
6793 /* Add the final region */
6796 plist.add (ARDOUR::Properties::start, r->start() + pos);
6797 plist.add (ARDOUR::Properties::length, r->last_frame() - (r->position() + pos) + 1);
6798 plist.add (ARDOUR::Properties::name, new_name);
6799 plist.add (ARDOUR::Properties::layer, 0);
6801 boost::shared_ptr<Region> nr = RegionFactory::create (r->sources(), plist, false);
6802 /* because we set annouce to false, manually add the new region to the
6805 RegionFactory::map_add (nr);
6806 pl->add_region (nr, r->position() + pos);
6809 new_regions.push_front(nr);
6814 /* We might have removed regions, which alters other regions' layering_index,
6815 so we need to do a recursive diff here.
6817 vector<Command*> cmds;
6819 _session->add_commands (cmds);
6821 _session->add_command (new StatefulDiffCommand (pl));
6825 for (list<boost::shared_ptr<Region> >::iterator i = new_regions.begin(); i != new_regions.end(); ++i){
6826 set_selected_regionview_from_region_list ((*i), Selection::Add);
6832 Editor::place_transient()
6838 RegionSelection rs = get_regions_from_selection_and_edit_point ();
6844 framepos_t where = get_preferred_edit_position();
6846 begin_reversible_command (_("place transient"));
6848 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6849 (*r)->region()->add_transient(where);
6852 commit_reversible_command ();
6856 Editor::remove_transient(ArdourCanvas::Item* item)
6862 ArdourCanvas::Line* _line = reinterpret_cast<ArdourCanvas::Line*> (item);
6865 AudioRegionView* _arv = reinterpret_cast<AudioRegionView*> (item->get_data ("regionview"));
6866 _arv->remove_transient (*(float*) _line->get_data ("position"));
6870 Editor::snap_regions_to_grid ()
6872 list <boost::shared_ptr<Playlist > > used_playlists;
6874 RegionSelection rs = get_regions_from_selection_and_entered ();
6876 if (!_session || rs.empty()) {
6880 begin_reversible_command (_("snap regions to grid"));
6882 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6884 boost::shared_ptr<Playlist> pl = (*r)->region()->playlist();
6886 if (!pl->frozen()) {
6887 /* we haven't seen this playlist before */
6889 /* remember used playlists so we can thaw them later */
6890 used_playlists.push_back(pl);
6894 framepos_t start_frame = (*r)->region()->first_frame ();
6895 snap_to (start_frame);
6896 (*r)->region()->set_position (start_frame);
6899 while (used_playlists.size() > 0) {
6900 list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
6902 used_playlists.pop_front();
6905 commit_reversible_command ();
6909 Editor::close_region_gaps ()
6911 list <boost::shared_ptr<Playlist > > used_playlists;
6913 RegionSelection rs = get_regions_from_selection_and_entered ();
6915 if (!_session || rs.empty()) {
6919 Dialog dialog (_("Close Region Gaps"));
6922 table.set_spacings (12);
6923 table.set_border_width (12);
6924 Label* l = manage (left_aligned_label (_("Crossfade length")));
6925 table.attach (*l, 0, 1, 0, 1);
6927 SpinButton spin_crossfade (1, 0);
6928 spin_crossfade.set_range (0, 15);
6929 spin_crossfade.set_increments (1, 1);
6930 spin_crossfade.set_value (5);
6931 table.attach (spin_crossfade, 1, 2, 0, 1);
6933 table.attach (*manage (new Label (_("ms"))), 2, 3, 0, 1);
6935 l = manage (left_aligned_label (_("Pull-back length")));
6936 table.attach (*l, 0, 1, 1, 2);
6938 SpinButton spin_pullback (1, 0);
6939 spin_pullback.set_range (0, 100);
6940 spin_pullback.set_increments (1, 1);
6941 spin_pullback.set_value(30);
6942 table.attach (spin_pullback, 1, 2, 1, 2);
6944 table.attach (*manage (new Label (_("ms"))), 2, 3, 1, 2);
6946 dialog.get_vbox()->pack_start (table);
6947 dialog.add_button (Stock::CANCEL, RESPONSE_CANCEL);
6948 dialog.add_button (_("Ok"), RESPONSE_ACCEPT);
6951 if (dialog.run () == RESPONSE_CANCEL) {
6955 framepos_t crossfade_len = spin_crossfade.get_value();
6956 framepos_t pull_back_frames = spin_pullback.get_value();
6958 crossfade_len = lrintf (crossfade_len * _session->frame_rate()/1000);
6959 pull_back_frames = lrintf (pull_back_frames * _session->frame_rate()/1000);
6961 /* Iterate over the region list and make adjacent regions overlap by crossfade_len_ms */
6963 begin_reversible_command (_("close region gaps"));
6966 boost::shared_ptr<Region> last_region;
6968 rs.sort_by_position_and_track();
6970 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6972 boost::shared_ptr<Playlist> pl = (*r)->region()->playlist();
6974 if (!pl->frozen()) {
6975 /* we haven't seen this playlist before */
6977 /* remember used playlists so we can thaw them later */
6978 used_playlists.push_back(pl);
6982 framepos_t position = (*r)->region()->position();
6984 if (idx == 0 || position < last_region->position()){
6985 last_region = (*r)->region();
6990 (*r)->region()->trim_front( (position - pull_back_frames));
6991 last_region->trim_end( (position - pull_back_frames + crossfade_len));
6993 last_region = (*r)->region();
6998 while (used_playlists.size() > 0) {
6999 list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
7001 used_playlists.pop_front();
7004 commit_reversible_command ();
7008 Editor::tab_to_transient (bool forward)
7010 AnalysisFeatureList positions;
7012 RegionSelection rs = get_regions_from_selection_and_entered ();
7018 framepos_t pos = _session->audible_frame ();
7020 if (!selection->tracks.empty()) {
7022 /* don't waste time searching for transients in duplicate playlists.
7025 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
7027 for (TrackViewList::iterator t = ts.begin(); t != ts.end(); ++t) {
7029 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*t);
7032 boost::shared_ptr<Track> tr = rtv->track();
7034 boost::shared_ptr<Playlist> pl = tr->playlist ();
7036 framepos_t result = pl->find_next_transient (pos, forward ? 1 : -1);
7039 positions.push_back (result);
7052 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
7053 (*r)->region()->get_transients (positions);
7057 TransientDetector::cleanup_transients (positions, _session->frame_rate(), 3.0);
7060 AnalysisFeatureList::iterator x;
7062 for (x = positions.begin(); x != positions.end(); ++x) {
7068 if (x != positions.end ()) {
7069 _session->request_locate (*x);
7073 AnalysisFeatureList::reverse_iterator x;
7075 for (x = positions.rbegin(); x != positions.rend(); ++x) {
7081 if (x != positions.rend ()) {
7082 _session->request_locate (*x);
7088 Editor::playhead_forward_to_grid ()
7094 framepos_t pos = playhead_cursor->current_frame ();
7095 if (pos < max_framepos - 1) {
7097 snap_to_internal (pos, RoundUpAlways, false);
7098 _session->request_locate (pos);
7104 Editor::playhead_backward_to_grid ()
7110 framepos_t pos = playhead_cursor->current_frame ();
7113 snap_to_internal (pos, RoundDownAlways, false);
7114 _session->request_locate (pos);
7119 Editor::set_track_height (Height h)
7121 TrackSelection& ts (selection->tracks);
7123 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
7124 (*x)->set_height_enum (h);
7129 Editor::toggle_tracks_active ()
7131 TrackSelection& ts (selection->tracks);
7133 bool target = false;
7139 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
7140 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*x);
7144 target = !rtv->_route->active();
7147 rtv->_route->set_active (target, this);
7153 Editor::remove_tracks ()
7155 /* this will delete GUI objects that may be the subject of an event
7156 handler in which this method is called. Defer actual deletion to the
7157 next idle callback, when all event handling is finished.
7159 Glib::signal_idle().connect (sigc::mem_fun (*this, &Editor::idle_remove_tracks));
7163 Editor::idle_remove_tracks ()
7165 Session::StateProtector sp (_session);
7167 return false; /* do not call again */
7171 Editor::_remove_tracks ()
7173 TrackSelection& ts (selection->tracks);
7179 vector<string> choices;
7183 const char* trackstr;
7185 vector<boost::shared_ptr<Route> > routes;
7186 bool special_bus = false;
7188 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
7189 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*x);
7193 if (rtv->is_track()) {
7198 routes.push_back (rtv->_route);
7200 if (rtv->route()->is_master() || rtv->route()->is_monitor()) {
7205 if (special_bus && !Config->get_allow_special_bus_removal()) {
7206 MessageDialog msg (_("That would be bad news ...."),
7210 msg.set_secondary_text (string_compose (_(
7211 "Removing the master or monitor bus is such a bad idea\n\
7212 that %1 is not going to allow it.\n\
7214 If you really want to do this sort of thing\n\
7215 edit your ardour.rc file to set the\n\
7216 \"allow-special-bus-removal\" option to be \"yes\""), PROGRAM_NAME));
7223 if (ntracks + nbusses == 0) {
7227 trackstr = P_("track", "tracks", ntracks);
7228 busstr = P_("bus", "busses", nbusses);
7232 prompt = string_compose (_("Do you really want to remove %1 %2 and %3 %4?\n"
7233 "(You may also lose the playlists associated with the %2)\n\n"
7234 "This action cannot be undone, and the session file will be overwritten!"),
7235 ntracks, trackstr, nbusses, busstr);
7237 prompt = string_compose (_("Do you really want to remove %1 %2?\n"
7238 "(You may also lose the playlists associated with the %2)\n\n"
7239 "This action cannot be undone, and the session file will be overwritten!"),
7242 } else if (nbusses) {
7243 prompt = string_compose (_("Do you really want to remove %1 %2?\n\n"
7244 "This action cannot be undone, and the session file will be overwritten"),
7248 choices.push_back (_("No, do nothing."));
7249 if (ntracks + nbusses > 1) {
7250 choices.push_back (_("Yes, remove them."));
7252 choices.push_back (_("Yes, remove it."));
7257 title = string_compose (_("Remove %1"), trackstr);
7259 title = string_compose (_("Remove %1"), busstr);
7262 Choice prompter (title, prompt, choices);
7264 if (prompter.run () != 1) {
7269 DisplaySuspender ds;
7270 boost::shared_ptr<RouteList> rl (new RouteList);
7271 for (vector<boost::shared_ptr<Route> >::iterator x = routes.begin(); x != routes.end(); ++x) {
7274 _session->remove_routes (rl);
7276 /* TrackSelection and RouteList leave scope,
7277 * destructors are called,
7278 * diskstream drops references, save_state is called (again for every track)
7283 Editor::do_insert_time ()
7285 if (selection->tracks.empty()) {
7289 InsertRemoveTimeDialog d (*this);
7290 int response = d.run ();
7292 if (response != RESPONSE_OK) {
7296 if (d.distance() == 0) {
7301 get_preferred_edit_position (EDIT_IGNORE_MOUSE),
7303 d.intersected_region_action (),
7307 d.move_glued_markers(),
7308 d.move_locked_markers(),
7314 Editor::insert_time (
7315 framepos_t pos, framecnt_t frames, InsertTimeOption opt,
7316 bool all_playlists, bool ignore_music_glue, bool markers_too, bool glued_markers_too, bool locked_markers_too, bool tempo_too
7320 if (Config->get_edit_mode() == Lock) {
7323 bool in_command = false;
7325 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
7327 for (TrackViewList::iterator x = ts.begin(); x != ts.end(); ++x) {
7331 /* don't operate on any playlist more than once, which could
7332 * happen if "all playlists" is enabled, but there is more
7333 * than 1 track using playlists "from" a given track.
7336 set<boost::shared_ptr<Playlist> > pl;
7338 if (all_playlists) {
7339 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*x);
7340 if (rtav && rtav->track ()) {
7341 vector<boost::shared_ptr<Playlist> > all = _session->playlists->playlists_for_track (rtav->track ());
7342 for (vector<boost::shared_ptr<Playlist> >::iterator p = all.begin(); p != all.end(); ++p) {
7347 if ((*x)->playlist ()) {
7348 pl.insert ((*x)->playlist ());
7352 for (set<boost::shared_ptr<Playlist> >::iterator i = pl.begin(); i != pl.end(); ++i) {
7354 (*i)->clear_changes ();
7355 (*i)->clear_owned_changes ();
7357 if (opt == SplitIntersected) {
7358 /* non musical split */
7359 (*i)->split (pos, 0);
7362 (*i)->shift (pos, frames, (opt == MoveIntersected), ignore_music_glue);
7365 begin_reversible_command (_("insert time"));
7368 vector<Command*> cmds;
7370 _session->add_commands (cmds);
7372 _session->add_command (new StatefulDiffCommand (*i));
7376 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*x);
7379 begin_reversible_command (_("insert time"));
7382 rtav->route ()->shift (pos, frames);
7389 XMLNode& before (_session->locations()->get_state());
7390 Locations::LocationList copy (_session->locations()->list());
7392 for (Locations::LocationList::iterator i = copy.begin(); i != copy.end(); ++i) {
7394 Locations::LocationList::const_iterator tmp;
7396 if ((*i)->position_lock_style() == AudioTime || glued_markers_too) {
7397 bool const was_locked = (*i)->locked ();
7398 if (locked_markers_too) {
7402 if ((*i)->start() >= pos) {
7403 // move end first, in case we're moving by more than the length of the range
7404 if (!(*i)->is_mark()) {
7405 (*i)->set_end ((*i)->end() + frames);
7407 (*i)->set_start ((*i)->start() + frames);
7419 begin_reversible_command (_("insert time"));
7422 XMLNode& after (_session->locations()->get_state());
7423 _session->add_command (new MementoCommand<Locations>(*_session->locations(), &before, &after));
7429 begin_reversible_command (_("insert time"));
7432 XMLNode& before (_session->tempo_map().get_state());
7433 _session->tempo_map().insert_time (pos, frames);
7434 XMLNode& after (_session->tempo_map().get_state());
7435 _session->add_command (new MementoCommand<TempoMap>(_session->tempo_map(), &before, &after));
7439 commit_reversible_command ();
7444 Editor::do_remove_time ()
7446 if (selection->tracks.empty()) {
7450 framepos_t pos = get_preferred_edit_position (EDIT_IGNORE_MOUSE);
7451 InsertRemoveTimeDialog d (*this, true);
7453 int response = d.run ();
7455 if (response != RESPONSE_OK) {
7459 framecnt_t distance = d.distance();
7461 if (distance == 0) {
7471 d.move_glued_markers(),
7472 d.move_locked_markers(),
7478 Editor::remove_time (framepos_t pos, framecnt_t frames, InsertTimeOption opt,
7479 bool ignore_music_glue, bool markers_too, bool glued_markers_too, bool locked_markers_too, bool tempo_too)
7481 if (Config->get_edit_mode() == Lock) {
7482 error << (_("Cannot insert or delete time when in Lock edit.")) << endmsg;
7485 bool in_command = false;
7487 for (TrackSelection::iterator x = selection->tracks.begin(); x != selection->tracks.end(); ++x) {
7489 boost::shared_ptr<Playlist> pl = (*x)->playlist();
7493 XMLNode &before = pl->get_state();
7495 std::list<AudioRange> rl;
7496 AudioRange ar(pos, pos+frames, 0);
7499 pl->shift (pos, -frames, true, ignore_music_glue);
7502 begin_reversible_command (_("remove time"));
7505 XMLNode &after = pl->get_state();
7507 _session->add_command (new MementoCommand<Playlist> (*pl, &before, &after));
7511 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*x);
7514 begin_reversible_command (_("remove time"));
7517 rtav->route ()->shift (pos, -frames);
7521 std::list<Location*> loc_kill_list;
7526 XMLNode& before (_session->locations()->get_state());
7527 Locations::LocationList copy (_session->locations()->list());
7529 for (Locations::LocationList::iterator i = copy.begin(); i != copy.end(); ++i) {
7530 if ((*i)->position_lock_style() == AudioTime || glued_markers_too) {
7532 bool const was_locked = (*i)->locked ();
7533 if (locked_markers_too) {
7537 if (!(*i)->is_mark()) { // it's a range; have to handle both start and end
7538 if ((*i)->end() >= pos
7539 && (*i)->end() < pos+frames
7540 && (*i)->start() >= pos
7541 && (*i)->end() < pos+frames) { // range is completely enclosed; kill it
7543 loc_kill_list.push_back(*i);
7544 } else { // only start or end is included, try to do the right thing
7545 // move start before moving end, to avoid trying to move the end to before the start
7546 // if we're removing more time than the length of the range
7547 if ((*i)->start() >= pos && (*i)->start() < pos+frames) {
7548 // start is within cut
7549 (*i)->set_start (pos); // bring the start marker to the beginning of the cut
7551 } else if ((*i)->start() >= pos+frames) {
7552 // start (and thus entire range) lies beyond end of cut
7553 (*i)->set_start ((*i)->start() - frames); // slip the start marker back
7556 if ((*i)->end() >= pos && (*i)->end() < pos+frames) {
7557 // end is inside cut
7558 (*i)->set_end (pos); // bring the end to the cut
7560 } else if ((*i)->end() >= pos+frames) {
7561 // end is beyond end of cut
7562 (*i)->set_end ((*i)->end() - frames); // slip the end marker back
7567 } else if ((*i)->start() >= pos && (*i)->start() < pos+frames ) {
7568 loc_kill_list.push_back(*i);
7570 } else if ((*i)->start() >= pos) {
7571 (*i)->set_start ((*i)->start() -frames);
7581 for (list<Location*>::iterator i = loc_kill_list.begin(); i != loc_kill_list.end(); ++i) {
7582 _session->locations()->remove( *i );
7587 begin_reversible_command (_("remove time"));
7590 XMLNode& after (_session->locations()->get_state());
7591 _session->add_command (new MementoCommand<Locations>(*_session->locations(), &before, &after));
7596 XMLNode& before (_session->tempo_map().get_state());
7598 if (_session->tempo_map().remove_time (pos, frames) ) {
7600 begin_reversible_command (_("remove time"));
7603 XMLNode& after (_session->tempo_map().get_state());
7604 _session->add_command (new MementoCommand<TempoMap>(_session->tempo_map(), &before, &after));
7609 commit_reversible_command ();
7614 Editor::fit_selection ()
7616 if (!selection->tracks.empty()) {
7617 fit_tracks (selection->tracks);
7621 /* no selected tracks - use tracks with selected regions */
7623 if (!selection->regions.empty()) {
7624 for (RegionSelection::iterator r = selection->regions.begin(); r != selection->regions.end(); ++r) {
7625 tvl.push_back (&(*r)->get_time_axis_view ());
7631 } else if (internal_editing()) {
7632 /* no selected tracks, or regions, but in internal edit mode, so follow the mouse and use
7635 if (entered_track) {
7636 tvl.push_back (entered_track);
7645 Editor::fit_tracks (TrackViewList & tracks)
7647 if (tracks.empty()) {
7651 uint32_t child_heights = 0;
7652 int visible_tracks = 0;
7654 for (TrackSelection::iterator t = tracks.begin(); t != tracks.end(); ++t) {
7656 if (!(*t)->marked_for_display()) {
7660 child_heights += (*t)->effective_height() - (*t)->current_height();
7664 /* compute the per-track height from:
7666 total canvas visible height -
7667 height that will be taken by visible children of selected
7668 tracks - height of the ruler/hscroll area
7670 uint32_t h = (uint32_t) floor ((trackviews_height() - child_heights) / visible_tracks);
7671 double first_y_pos = DBL_MAX;
7673 if (h < TimeAxisView::preset_height (HeightSmall)) {
7674 MessageDialog msg (_("There are too many tracks to fit in the current window"));
7675 /* too small to be displayed */
7679 undo_visual_stack.push_back (current_visual_state (true));
7680 PBD::Unwinder<bool> nsv (no_save_visual, true);
7682 /* build a list of all tracks, including children */
7685 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
7687 TimeAxisView::Children c = (*i)->get_child_list ();
7688 for (TimeAxisView::Children::iterator j = c.begin(); j != c.end(); ++j) {
7689 all.push_back (j->get());
7694 // find selection range.
7695 // if someone knows how to user TrackViewList::iterator for this
7697 int selected_top = -1;
7698 int selected_bottom = -1;
7700 for (TrackViewList::iterator t = all.begin(); t != all.end(); ++t, ++i) {
7701 if ((*t)->marked_for_display ()) {
7702 if (tracks.contains(*t)) {
7703 if (selected_top == -1) {
7706 selected_bottom = i;
7712 for (TrackViewList::iterator t = all.begin(); t != all.end(); ++t, ++i) {
7713 if ((*t)->marked_for_display ()) {
7714 if (tracks.contains(*t)) {
7715 (*t)->set_height (h);
7716 first_y_pos = std::min ((*t)->y_position (), first_y_pos);
7718 if (i > selected_top && i < selected_bottom) {
7719 hide_track_in_display (*t);
7726 set the controls_layout height now, because waiting for its size
7727 request signal handler will cause the vertical adjustment setting to fail
7730 controls_layout.property_height () = _full_canvas_height;
7731 vertical_adjustment.set_value (first_y_pos);
7733 redo_visual_stack.push_back (current_visual_state (true));
7735 visible_tracks_selector.set_text (_("Sel"));
7739 Editor::save_visual_state (uint32_t n)
7741 while (visual_states.size() <= n) {
7742 visual_states.push_back (0);
7745 if (visual_states[n] != 0) {
7746 delete visual_states[n];
7749 visual_states[n] = current_visual_state (true);
7754 Editor::goto_visual_state (uint32_t n)
7756 if (visual_states.size() <= n) {
7760 if (visual_states[n] == 0) {
7764 use_visual_state (*visual_states[n]);
7768 Editor::start_visual_state_op (uint32_t n)
7770 save_visual_state (n);
7772 PopUp* pup = new PopUp (WIN_POS_MOUSE, 1000, true);
7774 snprintf (buf, sizeof (buf), _("Saved view %u"), n+1);
7775 pup->set_text (buf);
7780 Editor::cancel_visual_state_op (uint32_t n)
7782 goto_visual_state (n);
7786 Editor::toggle_region_mute ()
7788 if (_ignore_region_action) {
7792 RegionSelection rs = get_regions_from_selection_and_entered ();
7798 if (rs.size() > 1) {
7799 begin_reversible_command (_("mute regions"));
7801 begin_reversible_command (_("mute region"));
7804 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
7806 (*i)->region()->playlist()->clear_changes ();
7807 (*i)->region()->set_muted (!(*i)->region()->muted ());
7808 _session->add_command (new StatefulDiffCommand ((*i)->region()));
7812 commit_reversible_command ();
7816 Editor::combine_regions ()
7818 /* foreach track with selected regions, take all selected regions
7819 and join them into a new region containing the subregions (as a
7823 typedef set<RouteTimeAxisView*> RTVS;
7826 if (selection->regions.empty()) {
7830 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
7831 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(&(*i)->get_time_axis_view());
7834 tracks.insert (rtv);
7838 begin_reversible_command (_("combine regions"));
7840 vector<RegionView*> new_selection;
7842 for (RTVS::iterator i = tracks.begin(); i != tracks.end(); ++i) {
7845 if ((rv = (*i)->combine_regions ()) != 0) {
7846 new_selection.push_back (rv);
7850 selection->clear_regions ();
7851 for (vector<RegionView*>::iterator i = new_selection.begin(); i != new_selection.end(); ++i) {
7852 selection->add (*i);
7855 commit_reversible_command ();
7859 Editor::uncombine_regions ()
7861 typedef set<RouteTimeAxisView*> RTVS;
7864 if (selection->regions.empty()) {
7868 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
7869 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(&(*i)->get_time_axis_view());
7872 tracks.insert (rtv);
7876 begin_reversible_command (_("uncombine regions"));
7878 for (RTVS::iterator i = tracks.begin(); i != tracks.end(); ++i) {
7879 (*i)->uncombine_regions ();
7882 commit_reversible_command ();
7886 Editor::toggle_midi_input_active (bool flip_others)
7889 boost::shared_ptr<RouteList> rl (new RouteList);
7891 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
7892 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
7898 boost::shared_ptr<MidiTrack> mt = rtav->midi_track();
7901 rl->push_back (rtav->route());
7902 onoff = !mt->input_active();
7906 _session->set_exclusive_input_active (rl, onoff, flip_others);
7913 lock_dialog = new Gtk::Dialog (string_compose (_("%1: Locked"), PROGRAM_NAME), true);
7915 Gtk::Image* padlock = manage (new Gtk::Image (ARDOUR_UI_UTILS::get_icon ("padlock_closed")));
7916 lock_dialog->get_vbox()->pack_start (*padlock);
7918 ArdourButton* b = manage (new ArdourButton);
7919 b->set_name ("lock button");
7920 b->set_text (_("Click to unlock"));
7921 b->signal_clicked.connect (sigc::mem_fun (*this, &Editor::unlock));
7922 lock_dialog->get_vbox()->pack_start (*b);
7924 lock_dialog->get_vbox()->show_all ();
7925 lock_dialog->set_size_request (200, 200);
7928 delete _main_menu_disabler;
7929 _main_menu_disabler = new MainMenuDisabler;
7931 lock_dialog->present ();
7937 lock_dialog->hide ();
7939 delete _main_menu_disabler;
7940 _main_menu_disabler = 0;
7942 if (UIConfiguration::instance().get_lock_gui_after_seconds()) {
7943 start_lock_event_timing ();
7948 Editor::bring_in_callback (Gtk::Label* label, uint32_t n, uint32_t total, string name)
7950 Gtkmm2ext::UI::instance()->call_slot (invalidator (*this), boost::bind (&Editor::update_bring_in_message, this, label, n, total, name));
7954 Editor::update_bring_in_message (Gtk::Label* label, uint32_t n, uint32_t total, string name)
7956 Timers::TimerSuspender t;
7957 label->set_text (string_compose ("Copying %1, %2 of %3", name, n, total));
7958 Gtkmm2ext::UI::instance()->flush_pending (1);
7962 Editor::bring_all_sources_into_session ()
7969 ArdourDialog w (_("Moving embedded files into session folder"));
7970 w.get_vbox()->pack_start (msg);
7973 /* flush all pending GUI events because we're about to start copying
7977 Timers::TimerSuspender t;
7978 Gtkmm2ext::UI::instance()->flush_pending (3);
7982 _session->bring_all_sources_into_session (boost::bind (&Editor::bring_in_callback, this, &msg, _1, _2, _3));