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"
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)
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);
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);
438 begin_reversible_command (_("nudge location forward"));
441 XMLNode& after (loc->get_state());
442 _session->add_command (new MementoCommand<Location>(*loc, &before, &after));
447 commit_reversible_command ();
450 distance = get_nudge_distance (playhead_cursor->current_frame (), next_distance);
451 _session->request_locate (playhead_cursor->current_frame () + distance);
456 Editor::nudge_backward (bool next, bool force_playhead)
459 framepos_t next_distance;
465 RegionSelection rs = get_regions_from_selection_and_entered ();
467 if (!force_playhead && !rs.empty()) {
469 begin_reversible_command (_("nudge regions backward"));
471 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
472 boost::shared_ptr<Region> r ((*i)->region());
474 distance = get_nudge_distance (r->position(), next_distance);
477 distance = next_distance;
482 if (r->position() > distance) {
483 r->set_position (r->position() - distance);
487 _session->add_command (new StatefulDiffCommand (r));
490 commit_reversible_command ();
492 } else if (!force_playhead && !selection->markers.empty()) {
495 bool in_command = false;
497 for (MarkerSelection::iterator i = selection->markers.begin(); i != selection->markers.end(); ++i) {
499 Location* loc = find_location_from_marker ((*i), is_start);
503 XMLNode& before (loc->get_state());
506 distance = get_nudge_distance (loc->start(), next_distance);
508 distance = next_distance;
510 if (distance < loc->start()) {
511 loc->set_start (loc->start() - distance);
516 distance = get_nudge_distance (loc->end(), next_distance);
519 distance = next_distance;
522 if (distance < loc->end() - loc->length()) {
523 loc->set_end (loc->end() - distance);
525 loc->set_end (loc->length());
529 begin_reversible_command (_("nudge location forward"));
532 XMLNode& after (loc->get_state());
533 _session->add_command (new MementoCommand<Location>(*loc, &before, &after));
537 commit_reversible_command ();
542 distance = get_nudge_distance (playhead_cursor->current_frame (), next_distance);
544 if (playhead_cursor->current_frame () > distance) {
545 _session->request_locate (playhead_cursor->current_frame () - distance);
547 _session->goto_start();
553 Editor::nudge_forward_capture_offset ()
555 RegionSelection rs = get_regions_from_selection_and_entered ();
557 if (!_session || rs.empty()) {
561 begin_reversible_command (_("nudge forward"));
563 framepos_t const distance = _session->worst_output_latency();
565 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
566 boost::shared_ptr<Region> r ((*i)->region());
569 r->set_position (r->position() + distance);
570 _session->add_command(new StatefulDiffCommand (r));
573 commit_reversible_command ();
577 Editor::nudge_backward_capture_offset ()
579 RegionSelection rs = get_regions_from_selection_and_entered ();
581 if (!_session || rs.empty()) {
585 begin_reversible_command (_("nudge backward"));
587 framepos_t const distance = _session->worst_output_latency();
589 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
590 boost::shared_ptr<Region> r ((*i)->region());
594 if (r->position() > distance) {
595 r->set_position (r->position() - distance);
599 _session->add_command(new StatefulDiffCommand (r));
602 commit_reversible_command ();
605 struct RegionSelectionPositionSorter {
606 bool operator() (RegionView* a, RegionView* b) {
607 return a->region()->position() < b->region()->position();
612 Editor::sequence_regions ()
615 framepos_t r_end_prev;
623 RegionSelection rs = get_regions_from_selection_and_entered ();
624 rs.sort(RegionSelectionPositionSorter());
628 bool in_command = false;
630 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
631 boost::shared_ptr<Region> r ((*i)->region());
639 if(r->position_locked())
646 r->set_position(r_end_prev);
650 begin_reversible_command (_("sequence regions"));
653 _session->add_command (new StatefulDiffCommand (r));
655 r_end=r->position() + r->length();
661 commit_reversible_command ();
670 Editor::move_to_start ()
672 _session->goto_start ();
676 Editor::move_to_end ()
679 _session->request_locate (_session->current_end_frame());
683 Editor::build_region_boundary_cache ()
686 vector<RegionPoint> interesting_points;
687 boost::shared_ptr<Region> r;
688 TrackViewList tracks;
691 region_boundary_cache.clear ();
697 switch (_snap_type) {
698 case SnapToRegionStart:
699 interesting_points.push_back (Start);
701 case SnapToRegionEnd:
702 interesting_points.push_back (End);
704 case SnapToRegionSync:
705 interesting_points.push_back (SyncPoint);
707 case SnapToRegionBoundary:
708 interesting_points.push_back (Start);
709 interesting_points.push_back (End);
712 fatal << string_compose (_("build_region_boundary_cache called with snap_type = %1"), _snap_type) << endmsg;
713 abort(); /*NOTREACHED*/
717 TimeAxisView *ontrack = 0;
720 if (!selection->tracks.empty()) {
721 tlist = selection->tracks.filter_to_unique_playlists ();
723 tlist = track_views.filter_to_unique_playlists ();
726 while (pos < _session->current_end_frame() && !at_end) {
729 framepos_t lpos = max_framepos;
731 for (vector<RegionPoint>::iterator p = interesting_points.begin(); p != interesting_points.end(); ++p) {
733 if ((r = find_next_region (pos, *p, 1, tlist, &ontrack)) == 0) {
734 if (*p == interesting_points.back()) {
737 /* move to next point type */
743 rpos = r->first_frame();
747 rpos = r->last_frame();
751 rpos = r->sync_position ();
759 RouteTimeAxisView *rtav;
761 if (ontrack != 0 && (rtav = dynamic_cast<RouteTimeAxisView*>(ontrack)) != 0 ) {
762 if (rtav->track() != 0) {
763 speed = rtav->track()->speed();
767 rpos = track_frame_to_session_frame (rpos, speed);
773 /* prevent duplicates, but we don't use set<> because we want to be able
777 vector<framepos_t>::iterator ri;
779 for (ri = region_boundary_cache.begin(); ri != region_boundary_cache.end(); ++ri) {
785 if (ri == region_boundary_cache.end()) {
786 region_boundary_cache.push_back (rpos);
793 /* finally sort to be sure that the order is correct */
795 sort (region_boundary_cache.begin(), region_boundary_cache.end());
798 boost::shared_ptr<Region>
799 Editor::find_next_region (framepos_t frame, RegionPoint point, int32_t dir, TrackViewList& tracks, TimeAxisView **ontrack)
801 TrackViewList::iterator i;
802 framepos_t closest = max_framepos;
803 boost::shared_ptr<Region> ret;
807 framepos_t track_frame;
808 RouteTimeAxisView *rtav;
810 for (i = tracks.begin(); i != tracks.end(); ++i) {
813 boost::shared_ptr<Region> r;
816 if ( (rtav = dynamic_cast<RouteTimeAxisView*>(*i)) != 0 ) {
817 if (rtav->track()!=0)
818 track_speed = rtav->track()->speed();
821 track_frame = session_frame_to_track_frame(frame, track_speed);
823 if ((r = (*i)->find_next_region (track_frame, point, dir)) == 0) {
829 rpos = r->first_frame ();
833 rpos = r->last_frame ();
837 rpos = r->sync_position ();
841 // rpos is a "track frame", converting it to "_session frame"
842 rpos = track_frame_to_session_frame(rpos, track_speed);
845 distance = rpos - frame;
847 distance = frame - rpos;
850 if (distance < closest) {
862 Editor::find_next_region_boundary (framepos_t pos, int32_t dir, const TrackViewList& tracks)
864 framecnt_t distance = max_framepos;
865 framepos_t current_nearest = -1;
867 for (TrackViewList::const_iterator i = tracks.begin(); i != tracks.end(); ++i) {
868 framepos_t contender;
871 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*i);
877 if ((contender = rtv->find_next_region_boundary (pos, dir)) < 0) {
881 d = ::llabs (pos - contender);
884 current_nearest = contender;
889 return current_nearest;
893 Editor::get_region_boundary (framepos_t pos, int32_t dir, bool with_selection, bool only_onscreen)
898 if (with_selection && Config->get_region_boundaries_from_selected_tracks()) {
900 if (!selection->tracks.empty()) {
902 target = find_next_region_boundary (pos, dir, selection->tracks);
906 if (only_onscreen || Config->get_region_boundaries_from_onscreen_tracks()) {
907 get_onscreen_tracks (tvl);
908 target = find_next_region_boundary (pos, dir, tvl);
910 target = find_next_region_boundary (pos, dir, track_views);
916 if (only_onscreen || Config->get_region_boundaries_from_onscreen_tracks()) {
917 get_onscreen_tracks (tvl);
918 target = find_next_region_boundary (pos, dir, tvl);
920 target = find_next_region_boundary (pos, dir, track_views);
928 Editor::cursor_to_region_boundary (bool with_selection, int32_t dir)
930 framepos_t pos = playhead_cursor->current_frame ();
937 // so we don't find the current region again..
938 if (dir > 0 || pos > 0) {
942 if ((target = get_region_boundary (pos, dir, with_selection, false)) < 0) {
946 _session->request_locate (target);
950 Editor::cursor_to_next_region_boundary (bool with_selection)
952 cursor_to_region_boundary (with_selection, 1);
956 Editor::cursor_to_previous_region_boundary (bool with_selection)
958 cursor_to_region_boundary (with_selection, -1);
962 Editor::cursor_to_region_point (EditorCursor* cursor, RegionPoint point, int32_t dir)
964 boost::shared_ptr<Region> r;
965 framepos_t pos = cursor->current_frame ();
971 TimeAxisView *ontrack = 0;
973 // so we don't find the current region again..
977 if (!selection->tracks.empty()) {
979 r = find_next_region (pos, point, dir, selection->tracks, &ontrack);
981 } else if (clicked_axisview) {
984 t.push_back (clicked_axisview);
986 r = find_next_region (pos, point, dir, t, &ontrack);
990 r = find_next_region (pos, point, dir, track_views, &ontrack);
999 pos = r->first_frame ();
1003 pos = r->last_frame ();
1007 pos = r->sync_position ();
1012 RouteTimeAxisView *rtav;
1014 if ( ontrack != 0 && (rtav = dynamic_cast<RouteTimeAxisView*>(ontrack)) != 0 ) {
1015 if (rtav->track() != 0) {
1016 speed = rtav->track()->speed();
1020 pos = track_frame_to_session_frame(pos, speed);
1022 if (cursor == playhead_cursor) {
1023 _session->request_locate (pos);
1025 cursor->set_position (pos);
1030 Editor::cursor_to_next_region_point (EditorCursor* cursor, RegionPoint point)
1032 cursor_to_region_point (cursor, point, 1);
1036 Editor::cursor_to_previous_region_point (EditorCursor* cursor, RegionPoint point)
1038 cursor_to_region_point (cursor, point, -1);
1042 Editor::cursor_to_selection_start (EditorCursor *cursor)
1046 switch (mouse_mode) {
1048 if (!selection->regions.empty()) {
1049 pos = selection->regions.start();
1054 if (!selection->time.empty()) {
1055 pos = selection->time.start ();
1063 if (cursor == playhead_cursor) {
1064 _session->request_locate (pos);
1066 cursor->set_position (pos);
1071 Editor::cursor_to_selection_end (EditorCursor *cursor)
1075 switch (mouse_mode) {
1077 if (!selection->regions.empty()) {
1078 pos = selection->regions.end_frame();
1083 if (!selection->time.empty()) {
1084 pos = selection->time.end_frame ();
1092 if (cursor == playhead_cursor) {
1093 _session->request_locate (pos);
1095 cursor->set_position (pos);
1100 Editor::selected_marker_to_region_boundary (bool with_selection, int32_t dir)
1110 if (selection->markers.empty()) {
1114 if (!mouse_frame (mouse, ignored)) {
1118 add_location_mark (mouse);
1121 if ((loc = find_location_from_marker (selection->markers.front(), ignored)) == 0) {
1125 framepos_t pos = loc->start();
1127 // so we don't find the current region again..
1128 if (dir > 0 || pos > 0) {
1132 if ((target = get_region_boundary (pos, dir, with_selection, false)) < 0) {
1136 loc->move_to (target);
1140 Editor::selected_marker_to_next_region_boundary (bool with_selection)
1142 selected_marker_to_region_boundary (with_selection, 1);
1146 Editor::selected_marker_to_previous_region_boundary (bool with_selection)
1148 selected_marker_to_region_boundary (with_selection, -1);
1152 Editor::selected_marker_to_region_point (RegionPoint point, int32_t dir)
1154 boost::shared_ptr<Region> r;
1159 if (!_session || selection->markers.empty()) {
1163 if ((loc = find_location_from_marker (selection->markers.front(), ignored)) == 0) {
1167 TimeAxisView *ontrack = 0;
1171 // so we don't find the current region again..
1175 if (!selection->tracks.empty()) {
1177 r = find_next_region (pos, point, dir, selection->tracks, &ontrack);
1181 r = find_next_region (pos, point, dir, track_views, &ontrack);
1190 pos = r->first_frame ();
1194 pos = r->last_frame ();
1198 pos = r->adjust_to_sync (r->first_frame());
1203 RouteTimeAxisView *rtav;
1205 if (ontrack != 0 && (rtav = dynamic_cast<RouteTimeAxisView*>(ontrack)) != 0) {
1206 if (rtav->track() != 0) {
1207 speed = rtav->track()->speed();
1211 pos = track_frame_to_session_frame(pos, speed);
1217 Editor::selected_marker_to_next_region_point (RegionPoint point)
1219 selected_marker_to_region_point (point, 1);
1223 Editor::selected_marker_to_previous_region_point (RegionPoint point)
1225 selected_marker_to_region_point (point, -1);
1229 Editor::selected_marker_to_selection_start ()
1235 if (!_session || selection->markers.empty()) {
1239 if ((loc = find_location_from_marker (selection->markers.front(), ignored)) == 0) {
1243 switch (mouse_mode) {
1245 if (!selection->regions.empty()) {
1246 pos = selection->regions.start();
1251 if (!selection->time.empty()) {
1252 pos = selection->time.start ();
1264 Editor::selected_marker_to_selection_end ()
1270 if (!_session || selection->markers.empty()) {
1274 if ((loc = find_location_from_marker (selection->markers.front(), ignored)) == 0) {
1278 switch (mouse_mode) {
1280 if (!selection->regions.empty()) {
1281 pos = selection->regions.end_frame();
1286 if (!selection->time.empty()) {
1287 pos = selection->time.end_frame ();
1299 Editor::scroll_playhead (bool forward)
1301 framepos_t pos = playhead_cursor->current_frame ();
1302 framecnt_t delta = (framecnt_t) floor (current_page_samples() / 0.8);
1305 if (pos == max_framepos) {
1309 if (pos < max_framepos - delta) {
1328 _session->request_locate (pos);
1332 Editor::cursor_align (bool playhead_to_edit)
1338 if (playhead_to_edit) {
1340 if (selection->markers.empty()) {
1344 _session->request_locate (selection->markers.front()->position(), _session->transport_rolling());
1347 /* move selected markers to playhead */
1349 for (MarkerSelection::iterator i = selection->markers.begin(); i != selection->markers.end(); ++i) {
1352 Location* loc = find_location_from_marker (*i, ignored);
1354 if (loc->is_mark()) {
1355 loc->set_start (playhead_cursor->current_frame ());
1357 loc->set (playhead_cursor->current_frame (),
1358 playhead_cursor->current_frame () + loc->length());
1365 Editor::scroll_backward (float pages)
1367 framepos_t const one_page = (framepos_t) rint (_visible_canvas_width * samples_per_pixel);
1368 framepos_t const cnt = (framepos_t) floor (pages * one_page);
1371 if (leftmost_frame < cnt) {
1374 frame = leftmost_frame - cnt;
1377 reset_x_origin (frame);
1381 Editor::scroll_forward (float pages)
1383 framepos_t const one_page = (framepos_t) rint (_visible_canvas_width * samples_per_pixel);
1384 framepos_t const cnt = (framepos_t) floor (pages * one_page);
1387 if (max_framepos - cnt < leftmost_frame) {
1388 frame = max_framepos - cnt;
1390 frame = leftmost_frame + cnt;
1393 reset_x_origin (frame);
1397 Editor::scroll_tracks_down ()
1399 double vert_value = vertical_adjustment.get_value() + vertical_adjustment.get_page_size();
1400 if (vert_value > vertical_adjustment.get_upper() - _visible_canvas_height) {
1401 vert_value = vertical_adjustment.get_upper() - _visible_canvas_height;
1404 vertical_adjustment.set_value (vert_value);
1408 Editor::scroll_tracks_up ()
1410 vertical_adjustment.set_value (vertical_adjustment.get_value() - vertical_adjustment.get_page_size());
1414 Editor::scroll_tracks_down_line ()
1416 double vert_value = vertical_adjustment.get_value() + 60;
1418 if (vert_value > vertical_adjustment.get_upper() - _visible_canvas_height) {
1419 vert_value = vertical_adjustment.get_upper() - _visible_canvas_height;
1422 vertical_adjustment.set_value (vert_value);
1426 Editor::scroll_tracks_up_line ()
1428 reset_y_origin (vertical_adjustment.get_value() - 60);
1432 Editor::scroll_down_one_track (bool skip_child_views)
1434 TrackViewList::reverse_iterator next = track_views.rend();
1435 const double top_of_trackviews = vertical_adjustment.get_value();
1437 for (TrackViewList::reverse_iterator t = track_views.rbegin(); t != track_views.rend(); ++t) {
1438 if ((*t)->hidden()) {
1442 /* If this is the upper-most visible trackview, we want to display
1443 * the one above it (next)
1445 * Note that covers_y_position() is recursive and includes child views
1447 std::pair<TimeAxisView*,double> res = (*t)->covers_y_position (top_of_trackviews);
1450 if (skip_child_views) {
1453 /* automation lane (one level, non-recursive)
1455 * - if no automation lane exists -> move to next tack
1456 * - if the first (here: bottom-most) matches -> move to next tack
1457 * - if no y-axis match is found -> the current track is at the top
1458 * -> move to last (here: top-most) automation lane
1460 TimeAxisView::Children kids = (*t)->get_child_list();
1461 TimeAxisView::Children::reverse_iterator nkid = kids.rend();
1463 for (TimeAxisView::Children::reverse_iterator ci = kids.rbegin(); ci != kids.rend(); ++ci) {
1464 if ((*ci)->hidden()) {
1468 std::pair<TimeAxisView*,double> dev;
1469 dev = (*ci)->covers_y_position (top_of_trackviews);
1471 /* some automation lane is currently at the top */
1472 if (ci == kids.rbegin()) {
1473 /* first (bottom-most) autmation lane is at the top.
1474 * -> move to next track
1483 if (nkid != kids.rend()) {
1484 ensure_time_axis_view_is_visible (**nkid, true);
1492 /* move to the track below the first one that covers the */
1494 if (next != track_views.rend()) {
1495 ensure_time_axis_view_is_visible (**next, true);
1503 Editor::scroll_up_one_track (bool skip_child_views)
1505 TrackViewList::iterator prev = track_views.end();
1506 double top_of_trackviews = vertical_adjustment.get_value ();
1508 for (TrackViewList::iterator t = track_views.begin(); t != track_views.end(); ++t) {
1510 if ((*t)->hidden()) {
1514 /* find the trackview at the top of the trackview group
1516 * Note that covers_y_position() is recursive and includes child views
1518 std::pair<TimeAxisView*,double> res = (*t)->covers_y_position (top_of_trackviews);
1521 if (skip_child_views) {
1524 /* automation lane (one level, non-recursive)
1526 * - if no automation lane exists -> move to prev tack
1527 * - if no y-axis match is found -> the current track is at the top -> move to prev track
1528 * (actually last automation lane of previous track, see below)
1529 * - if first (top-most) lane is at the top -> move to this track
1530 * - else move up one lane
1532 TimeAxisView::Children kids = (*t)->get_child_list();
1533 TimeAxisView::Children::iterator pkid = kids.end();
1535 for (TimeAxisView::Children::iterator ci = kids.begin(); ci != kids.end(); ++ci) {
1536 if ((*ci)->hidden()) {
1540 std::pair<TimeAxisView*,double> dev;
1541 dev = (*ci)->covers_y_position (top_of_trackviews);
1543 /* some automation lane is currently at the top */
1544 if (ci == kids.begin()) {
1545 /* first (top-most) autmation lane is at the top.
1546 * jump directly to this track's top
1548 ensure_time_axis_view_is_visible (**t, true);
1551 else if (pkid != kids.end()) {
1552 /* some other automation lane is at the top.
1553 * move up to prev automation lane.
1555 ensure_time_axis_view_is_visible (**pkid, true);
1558 assert(0); // not reached
1569 if (prev != track_views.end()) {
1570 // move to bottom-most automation-lane of the previous track
1571 TimeAxisView::Children kids = (*prev)->get_child_list();
1572 TimeAxisView::Children::reverse_iterator pkid = kids.rend();
1573 if (!skip_child_views) {
1574 // find the last visible lane
1575 for (TimeAxisView::Children::reverse_iterator ci = kids.rbegin(); ci != kids.rend(); ++ci) {
1576 if (!(*ci)->hidden()) {
1582 if (pkid != kids.rend()) {
1583 ensure_time_axis_view_is_visible (**pkid, true);
1585 ensure_time_axis_view_is_visible (**prev, true);
1594 Editor::scroll_left_step ()
1596 framepos_t xdelta = (current_page_samples() / 8);
1598 if (leftmost_frame > xdelta) {
1599 reset_x_origin (leftmost_frame - xdelta);
1607 Editor::scroll_right_step ()
1609 framepos_t xdelta = (current_page_samples() / 8);
1611 if (max_framepos - xdelta > leftmost_frame) {
1612 reset_x_origin (leftmost_frame + xdelta);
1614 reset_x_origin (max_framepos - current_page_samples());
1619 Editor::scroll_left_half_page ()
1621 framepos_t xdelta = (current_page_samples() / 2);
1622 if (leftmost_frame > xdelta) {
1623 reset_x_origin (leftmost_frame - xdelta);
1630 Editor::scroll_right_half_page ()
1632 framepos_t xdelta = (current_page_samples() / 2);
1633 if (max_framepos - xdelta > leftmost_frame) {
1634 reset_x_origin (leftmost_frame + xdelta);
1636 reset_x_origin (max_framepos - current_page_samples());
1643 Editor::tav_zoom_step (bool coarser)
1645 DisplaySuspender ds;
1649 if (selection->tracks.empty()) {
1652 ts = &selection->tracks;
1655 for (TrackViewList::iterator i = ts->begin(); i != ts->end(); ++i) {
1656 TimeAxisView *tv = (static_cast<TimeAxisView*>(*i));
1657 tv->step_height (coarser);
1662 Editor::tav_zoom_smooth (bool coarser, bool force_all)
1664 DisplaySuspender ds;
1668 if (selection->tracks.empty() || force_all) {
1671 ts = &selection->tracks;
1674 for (TrackViewList::iterator i = ts->begin(); i != ts->end(); ++i) {
1675 TimeAxisView *tv = (static_cast<TimeAxisView*>(*i));
1676 uint32_t h = tv->current_height ();
1681 if (h >= TimeAxisView::preset_height (HeightSmall)) {
1686 tv->set_height (h + 5);
1692 Editor::temporal_zoom_step_mouse_focus (bool coarser)
1694 Editing::ZoomFocus temp_focus = zoom_focus;
1695 zoom_focus = Editing::ZoomFocusMouse;
1696 temporal_zoom_step (coarser);
1697 zoom_focus = temp_focus;
1701 Editor::temporal_zoom_step (bool coarser)
1703 ENSURE_GUI_THREAD (*this, &Editor::temporal_zoom_step, coarser)
1705 framecnt_t nspp = samples_per_pixel;
1713 temporal_zoom (nspp);
1717 Editor::temporal_zoom (framecnt_t fpp)
1723 framepos_t current_page = current_page_samples();
1724 framepos_t current_leftmost = leftmost_frame;
1725 framepos_t current_rightmost;
1726 framepos_t current_center;
1727 framepos_t new_page_size;
1728 framepos_t half_page_size;
1729 framepos_t leftmost_after_zoom = 0;
1731 bool in_track_canvas;
1735 if (fpp == samples_per_pixel) {
1739 // Imposing an arbitrary limit to zoom out as too much zoom out produces
1740 // segfaults for lack of memory. If somebody decides this is not high enough I
1741 // believe it can be raisen to higher values but some limit must be in place.
1743 // This constant represents 1 day @ 48kHz on a 1600 pixel wide display
1744 // all of which is used for the editor track displays. The whole day
1745 // would be 4147200000 samples, so 2592000 samples per pixel.
1747 nfpp = min (fpp, (framecnt_t) 2592000);
1748 nfpp = max ((framecnt_t) 1, nfpp);
1750 new_page_size = (framepos_t) floor (_visible_canvas_width * nfpp);
1751 half_page_size = new_page_size / 2;
1753 switch (zoom_focus) {
1755 leftmost_after_zoom = current_leftmost;
1758 case ZoomFocusRight:
1759 current_rightmost = leftmost_frame + current_page;
1760 if (current_rightmost < new_page_size) {
1761 leftmost_after_zoom = 0;
1763 leftmost_after_zoom = current_rightmost - new_page_size;
1767 case ZoomFocusCenter:
1768 current_center = current_leftmost + (current_page/2);
1769 if (current_center < half_page_size) {
1770 leftmost_after_zoom = 0;
1772 leftmost_after_zoom = current_center - half_page_size;
1776 case ZoomFocusPlayhead:
1777 /* centre playhead */
1778 l = playhead_cursor->current_frame () - (new_page_size * 0.5);
1781 leftmost_after_zoom = 0;
1782 } else if (l > max_framepos) {
1783 leftmost_after_zoom = max_framepos - new_page_size;
1785 leftmost_after_zoom = (framepos_t) l;
1789 case ZoomFocusMouse:
1790 /* try to keep the mouse over the same point in the display */
1792 if (!mouse_frame (where, in_track_canvas)) {
1793 /* use playhead instead */
1794 where = playhead_cursor->current_frame ();
1796 if (where < half_page_size) {
1797 leftmost_after_zoom = 0;
1799 leftmost_after_zoom = where - half_page_size;
1804 l = - ((new_page_size * ((where - current_leftmost)/(double)current_page)) - where);
1807 leftmost_after_zoom = 0;
1808 } else if (l > max_framepos) {
1809 leftmost_after_zoom = max_framepos - new_page_size;
1811 leftmost_after_zoom = (framepos_t) l;
1818 /* try to keep the edit point in the same place */
1819 where = get_preferred_edit_position ();
1823 double l = - ((new_page_size * ((where - current_leftmost)/(double)current_page)) - where);
1826 leftmost_after_zoom = 0;
1827 } else if (l > max_framepos) {
1828 leftmost_after_zoom = max_framepos - new_page_size;
1830 leftmost_after_zoom = (framepos_t) l;
1834 /* edit point not defined */
1841 // leftmost_after_zoom = min (leftmost_after_zoom, _session->current_end_frame());
1843 reposition_and_zoom (leftmost_after_zoom, nfpp);
1847 Editor::calc_extra_zoom_edges(framepos_t &start, framepos_t &end)
1849 /* this func helps make sure we leave a little space
1850 at each end of the editor so that the zoom doesn't fit the region
1851 precisely to the screen.
1854 GdkScreen* screen = gdk_screen_get_default ();
1855 const gint pixwidth = gdk_screen_get_width (screen);
1856 const gint mmwidth = gdk_screen_get_width_mm (screen);
1857 const double pix_per_mm = (double) pixwidth/ (double) mmwidth;
1858 const double one_centimeter_in_pixels = pix_per_mm * 10.0;
1860 const framepos_t range = end - start;
1861 const framecnt_t new_fpp = (framecnt_t) ceil ((double) range / (double) _visible_canvas_width);
1862 const framepos_t extra_samples = (framepos_t) floor (one_centimeter_in_pixels * new_fpp);
1864 if (start > extra_samples) {
1865 start -= extra_samples;
1870 if (max_framepos - extra_samples > end) {
1871 end += extra_samples;
1878 Editor::temporal_zoom_region (bool both_axes)
1880 framepos_t start = max_framepos;
1882 set<TimeAxisView*> tracks;
1884 if ( !get_selection_extents(start, end) )
1887 calc_extra_zoom_edges (start, end);
1889 /* if we're zooming on both axes we need to save track heights etc.
1892 undo_visual_stack.push_back (current_visual_state (both_axes));
1894 PBD::Unwinder<bool> nsv (no_save_visual, true);
1896 temporal_zoom_by_frame (start, end);
1899 uint32_t per_track_height = (uint32_t) floor ((_visible_canvas_height - 10.0) / tracks.size());
1901 /* set visible track heights appropriately */
1903 for (set<TimeAxisView*>::iterator t = tracks.begin(); t != tracks.end(); ++t) {
1904 (*t)->set_height (per_track_height);
1907 /* hide irrelevant tracks */
1909 DisplaySuspender ds;
1911 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1912 if (find (tracks.begin(), tracks.end(), (*i)) == tracks.end()) {
1913 hide_track_in_display (*i);
1917 vertical_adjustment.set_value (0.0);
1920 redo_visual_stack.push_back (current_visual_state (both_axes));
1925 Editor::get_selection_extents (framepos_t &start, framepos_t &end) const
1927 start = max_framepos;
1931 //ToDo: if notes are selected, set extents to that selection
1933 //ToDo: if control points are selected, set extents to that selection
1935 if ( !selection->regions.empty() ) {
1936 RegionSelection rs = get_regions_from_selection_and_entered ();
1938 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
1940 if ((*i)->region()->position() < start) {
1941 start = (*i)->region()->position();
1944 if ((*i)->region()->last_frame() + 1 > end) {
1945 end = (*i)->region()->last_frame() + 1;
1949 } else if (!selection->time.empty()) {
1950 start = selection->time.start();
1951 end = selection->time.end_frame();
1953 ret = false; //no selection found
1956 if ((start == 0 && end == 0) || end < start) {
1965 Editor::temporal_zoom_selection (bool both_axes)
1967 if (!selection) return;
1969 //ToDo: if notes are selected, zoom to that
1971 //ToDo: if control points are selected, zoom to that
1973 //if region(s) are selected, zoom to that
1974 if ( !selection->regions.empty() )
1975 temporal_zoom_region (both_axes);
1977 //if a range is selected, zoom to that
1978 if (!selection->time.empty()) {
1980 framepos_t start, end;
1981 if (get_selection_extents (start, end)) {
1982 calc_extra_zoom_edges(start, end);
1983 temporal_zoom_by_frame (start, end);
1993 Editor::temporal_zoom_session ()
1995 ENSURE_GUI_THREAD (*this, &Editor::temporal_zoom_session)
1998 framecnt_t start = _session->current_start_frame();
1999 framecnt_t end = _session->current_end_frame();
2001 if (_session->actively_recording () ) {
2002 framepos_t cur = playhead_cursor->current_frame ();
2004 /* recording beyond the end marker; zoom out
2005 * by 5 seconds more so that if 'follow
2006 * playhead' is active we don't immediately
2009 end = cur + _session->frame_rate() * 5;
2013 if ((start == 0 && end == 0) || end < start) {
2017 calc_extra_zoom_edges(start, end);
2019 temporal_zoom_by_frame (start, end);
2024 Editor::temporal_zoom_by_frame (framepos_t start, framepos_t end)
2026 if (!_session) return;
2028 if ((start == 0 && end == 0) || end < start) {
2032 framepos_t range = end - start;
2034 const framecnt_t new_fpp = (framecnt_t) ceil ((double) range / (double) _visible_canvas_width);
2036 framepos_t new_page = range;
2037 framepos_t middle = (framepos_t) floor ((double) start + ((double) range / 2.0f));
2038 framepos_t new_leftmost = (framepos_t) floor ((double) middle - ((double) new_page / 2.0f));
2040 if (new_leftmost > middle) {
2044 if (new_leftmost < 0) {
2048 reposition_and_zoom (new_leftmost, new_fpp);
2052 Editor::temporal_zoom_to_frame (bool coarser, framepos_t frame)
2058 framecnt_t range_before = frame - leftmost_frame;
2062 if (samples_per_pixel <= 1) {
2065 new_spp = samples_per_pixel + (samples_per_pixel/2);
2067 range_before += range_before/2;
2069 if (samples_per_pixel >= 1) {
2070 new_spp = samples_per_pixel - (samples_per_pixel/2);
2072 /* could bail out here since we cannot zoom any finer,
2073 but leave that to the equality test below
2075 new_spp = samples_per_pixel;
2078 range_before -= range_before/2;
2081 if (new_spp == samples_per_pixel) {
2085 /* zoom focus is automatically taken as @param frame when this
2089 framepos_t new_leftmost = frame - (framepos_t)range_before;
2091 if (new_leftmost > frame) {
2095 if (new_leftmost < 0) {
2099 reposition_and_zoom (new_leftmost, new_spp);
2104 Editor::choose_new_marker_name(string &name) {
2106 if (!UIConfiguration::instance().get_name_new_markers()) {
2107 /* don't prompt user for a new name */
2111 ArdourPrompter dialog (true);
2113 dialog.set_prompt (_("New Name:"));
2115 dialog.set_title (_("New Location Marker"));
2117 dialog.set_name ("MarkNameWindow");
2118 dialog.set_size_request (250, -1);
2119 dialog.set_position (Gtk::WIN_POS_MOUSE);
2121 dialog.add_button (Stock::OK, RESPONSE_ACCEPT);
2122 dialog.set_initial_text (name);
2126 switch (dialog.run ()) {
2127 case RESPONSE_ACCEPT:
2133 dialog.get_result(name);
2140 Editor::add_location_from_selection ()
2144 if (selection->time.empty()) {
2148 if (_session == 0 || clicked_axisview == 0) {
2152 framepos_t start = selection->time[clicked_selection].start;
2153 framepos_t end = selection->time[clicked_selection].end;
2155 _session->locations()->next_available_name(rangename,"selection");
2156 Location *location = new Location (*_session, start, end, rangename, Location::IsRangeMarker);
2158 begin_reversible_command (_("add marker"));
2160 XMLNode &before = _session->locations()->get_state();
2161 _session->locations()->add (location, true);
2162 XMLNode &after = _session->locations()->get_state();
2163 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2165 commit_reversible_command ();
2169 Editor::add_location_mark (framepos_t where)
2173 select_new_marker = true;
2175 _session->locations()->next_available_name(markername,"mark");
2176 if (!choose_new_marker_name(markername)) {
2179 Location *location = new Location (*_session, where, where, markername, Location::IsMark);
2180 begin_reversible_command (_("add marker"));
2182 XMLNode &before = _session->locations()->get_state();
2183 _session->locations()->add (location, true);
2184 XMLNode &after = _session->locations()->get_state();
2185 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2187 commit_reversible_command ();
2191 Editor::set_session_start_from_playhead ()
2197 if ((loc = _session->locations()->session_range_location()) == 0) { //should never happen
2198 _session->set_session_extents ( _session->audible_frame(), _session->audible_frame() );
2200 XMLNode &before = loc->get_state();
2202 _session->set_session_extents ( _session->audible_frame(), loc->end() );
2204 XMLNode &after = loc->get_state();
2206 begin_reversible_command (_("Set session start"));
2208 _session->add_command (new MementoCommand<Location>(*loc, &before, &after));
2210 commit_reversible_command ();
2215 Editor::set_session_end_from_playhead ()
2221 if ((loc = _session->locations()->session_range_location()) == 0) { //should never happen
2222 _session->set_session_extents ( _session->audible_frame(), _session->audible_frame() );
2224 XMLNode &before = loc->get_state();
2226 _session->set_session_extents ( loc->start(), _session->audible_frame() );
2228 XMLNode &after = loc->get_state();
2230 begin_reversible_command (_("Set session start"));
2232 _session->add_command (new MementoCommand<Location>(*loc, &before, &after));
2234 commit_reversible_command ();
2239 Editor::add_location_from_playhead_cursor ()
2241 add_location_mark (_session->audible_frame());
2245 Editor::remove_location_at_playhead_cursor ()
2249 XMLNode &before = _session->locations()->get_state();
2250 bool removed = false;
2252 //find location(s) at this time
2253 Locations::LocationList locs;
2254 _session->locations()->find_all_between (_session->audible_frame(), _session->audible_frame()+1, locs, Location::Flags(0));
2255 for (Locations::LocationList::iterator i = locs.begin(); i != locs.end(); ++i) {
2256 if ((*i)->is_mark()) {
2257 _session->locations()->remove (*i);
2264 begin_reversible_command (_("remove marker"));
2265 XMLNode &after = _session->locations()->get_state();
2266 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2267 commit_reversible_command ();
2272 /** Add a range marker around each selected region */
2274 Editor::add_locations_from_region ()
2276 RegionSelection rs = get_regions_from_selection_and_entered ();
2281 bool commit = false;
2283 XMLNode &before = _session->locations()->get_state();
2285 for (RegionSelection::iterator i = rs.begin (); i != rs.end (); ++i) {
2287 boost::shared_ptr<Region> region = (*i)->region ();
2289 Location *location = new Location (*_session, region->position(), region->last_frame(), region->name(), Location::IsRangeMarker);
2291 _session->locations()->add (location, true);
2296 begin_reversible_command (selection->regions.size () > 1 ? _("add markers") : _("add marker"));
2297 XMLNode &after = _session->locations()->get_state();
2298 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2299 commit_reversible_command ();
2303 /** Add a single range marker around all selected regions */
2305 Editor::add_location_from_region ()
2307 RegionSelection rs = get_regions_from_selection_and_entered ();
2313 XMLNode &before = _session->locations()->get_state();
2317 if (rs.size() > 1) {
2318 _session->locations()->next_available_name(markername, "regions");
2320 RegionView* rv = *(rs.begin());
2321 boost::shared_ptr<Region> region = rv->region();
2322 markername = region->name();
2325 if (!choose_new_marker_name(markername)) {
2329 // single range spanning all selected
2330 Location *location = new Location (*_session, selection->regions.start(), selection->regions.end_frame(), markername, Location::IsRangeMarker);
2331 _session->locations()->add (location, true);
2333 begin_reversible_command (_("add marker"));
2334 XMLNode &after = _session->locations()->get_state();
2335 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2336 commit_reversible_command ();
2342 Editor::jump_forward_to_mark ()
2348 framepos_t pos = _session->locations()->first_mark_after (playhead_cursor->current_frame());
2354 _session->request_locate (pos, _session->transport_rolling());
2358 Editor::jump_backward_to_mark ()
2364 framepos_t pos = _session->locations()->first_mark_before (playhead_cursor->current_frame());
2370 _session->request_locate (pos, _session->transport_rolling());
2376 framepos_t const pos = _session->audible_frame ();
2379 _session->locations()->next_available_name (markername, "mark");
2381 if (!choose_new_marker_name (markername)) {
2385 _session->locations()->add (new Location (*_session, pos, 0, markername, Location::IsMark), true);
2389 Editor::clear_markers ()
2392 begin_reversible_command (_("clear markers"));
2394 XMLNode &before = _session->locations()->get_state();
2395 _session->locations()->clear_markers ();
2396 XMLNode &after = _session->locations()->get_state();
2397 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2399 commit_reversible_command ();
2404 Editor::clear_ranges ()
2407 begin_reversible_command (_("clear ranges"));
2409 XMLNode &before = _session->locations()->get_state();
2411 _session->locations()->clear_ranges ();
2413 XMLNode &after = _session->locations()->get_state();
2414 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2416 commit_reversible_command ();
2421 Editor::clear_locations ()
2423 begin_reversible_command (_("clear locations"));
2425 XMLNode &before = _session->locations()->get_state();
2426 _session->locations()->clear ();
2427 XMLNode &after = _session->locations()->get_state();
2428 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2430 commit_reversible_command ();
2434 Editor::unhide_markers ()
2436 for (LocationMarkerMap::iterator i = location_markers.begin(); i != location_markers.end(); ++i) {
2437 Location *l = (*i).first;
2438 if (l->is_hidden() && l->is_mark()) {
2439 l->set_hidden(false, this);
2445 Editor::unhide_ranges ()
2447 for (LocationMarkerMap::iterator i = location_markers.begin(); i != location_markers.end(); ++i) {
2448 Location *l = (*i).first;
2449 if (l->is_hidden() && l->is_range_marker()) {
2450 l->set_hidden(false, this);
2455 /* INSERT/REPLACE */
2458 Editor::insert_region_list_selection (float times)
2460 RouteTimeAxisView *tv = 0;
2461 boost::shared_ptr<Playlist> playlist;
2463 if (clicked_routeview != 0) {
2464 tv = clicked_routeview;
2465 } else if (!selection->tracks.empty()) {
2466 if ((tv = dynamic_cast<RouteTimeAxisView*>(selection->tracks.front())) == 0) {
2469 } else if (entered_track != 0) {
2470 if ((tv = dynamic_cast<RouteTimeAxisView*>(entered_track)) == 0) {
2477 if ((playlist = tv->playlist()) == 0) {
2481 boost::shared_ptr<Region> region = _regions->get_single_selection ();
2486 begin_reversible_command (_("insert region"));
2487 playlist->clear_changes ();
2488 playlist->add_region ((RegionFactory::create (region, true)), get_preferred_edit_position(), times);
2489 if (Config->get_edit_mode() == Ripple)
2490 playlist->ripple (get_preferred_edit_position(), region->length() * times, boost::shared_ptr<Region>());
2492 _session->add_command(new StatefulDiffCommand (playlist));
2493 commit_reversible_command ();
2496 /* BUILT-IN EFFECTS */
2499 Editor::reverse_selection ()
2504 /* GAIN ENVELOPE EDITING */
2507 Editor::edit_envelope ()
2514 Editor::transition_to_rolling (bool fwd)
2520 if (_session->config.get_external_sync()) {
2521 switch (Config->get_sync_source()) {
2525 /* transport controlled by the master */
2530 if (_session->is_auditioning()) {
2531 _session->cancel_audition ();
2535 _session->request_transport_speed (fwd ? 1.0f : -1.0f);
2539 Editor::play_from_start ()
2541 _session->request_locate (_session->current_start_frame(), true);
2545 Editor::play_from_edit_point ()
2547 _session->request_locate (get_preferred_edit_position(), true);
2551 Editor::play_from_edit_point_and_return ()
2553 framepos_t start_frame;
2554 framepos_t return_frame;
2556 start_frame = get_preferred_edit_position ( EDIT_IGNORE_PHEAD );
2558 if (_session->transport_rolling()) {
2559 _session->request_locate (start_frame, false);
2563 /* don't reset the return frame if its already set */
2565 if ((return_frame = _session->requested_return_frame()) < 0) {
2566 return_frame = _session->audible_frame();
2569 if (start_frame >= 0) {
2570 _session->request_roll_at_and_return (start_frame, return_frame);
2575 Editor::play_selection ()
2577 framepos_t start, end;
2578 if (!get_selection_extents ( start, end))
2581 AudioRange ar (start, end, 0);
2582 list<AudioRange> lar;
2585 _session->request_play_range (&lar, true);
2589 Editor::get_preroll ()
2591 return Config->get_preroll_seconds() * _session->frame_rate();
2596 Editor::maybe_locate_with_edit_preroll ( framepos_t location )
2598 if ( _session->transport_rolling() || !UIConfiguration::instance().get_follow_edits() || _ignore_follow_edits || _session->config.get_external_sync() )
2601 location -= get_preroll();
2603 //don't try to locate before the beginning of time
2607 //if follow_playhead is on, keep the playhead on the screen
2608 if ( _follow_playhead )
2609 if ( location < leftmost_frame )
2610 location = leftmost_frame;
2612 _session->request_locate( location );
2616 Editor::play_with_preroll ()
2619 framepos_t preroll = get_preroll();
2621 framepos_t start, end;
2622 if (!get_selection_extents ( start, end))
2625 if (start > preroll)
2626 start = start - preroll;
2628 end = end + preroll; //"post-roll"
2630 AudioRange ar (start, end, 0);
2631 list<AudioRange> lar;
2634 _session->request_play_range (&lar, true);
2639 Editor::play_location (Location& location)
2641 if (location.start() <= location.end()) {
2645 _session->request_bounded_roll (location.start(), location.end());
2649 Editor::loop_location (Location& location)
2651 if (location.start() <= location.end()) {
2657 if ((tll = transport_loop_location()) != 0) {
2658 tll->set (location.start(), location.end());
2660 // enable looping, reposition and start rolling
2661 _session->request_locate (tll->start(), true);
2662 _session->request_play_loop (true);
2667 Editor::do_layer_operation (LayerOperation op)
2669 if (selection->regions.empty ()) {
2673 bool const multiple = selection->regions.size() > 1;
2677 begin_reversible_command (_("raise regions"));
2679 begin_reversible_command (_("raise region"));
2685 begin_reversible_command (_("raise regions to top"));
2687 begin_reversible_command (_("raise region to top"));
2693 begin_reversible_command (_("lower regions"));
2695 begin_reversible_command (_("lower region"));
2701 begin_reversible_command (_("lower regions to bottom"));
2703 begin_reversible_command (_("lower region"));
2708 set<boost::shared_ptr<Playlist> > playlists = selection->regions.playlists ();
2709 for (set<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
2710 (*i)->clear_owned_changes ();
2713 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
2714 boost::shared_ptr<Region> r = (*i)->region ();
2726 r->lower_to_bottom ();
2730 for (set<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
2731 vector<Command*> cmds;
2733 _session->add_commands (cmds);
2736 commit_reversible_command ();
2740 Editor::raise_region ()
2742 do_layer_operation (Raise);
2746 Editor::raise_region_to_top ()
2748 do_layer_operation (RaiseToTop);
2752 Editor::lower_region ()
2754 do_layer_operation (Lower);
2758 Editor::lower_region_to_bottom ()
2760 do_layer_operation (LowerToBottom);
2763 /** Show the region editor for the selected regions */
2765 Editor::show_region_properties ()
2767 selection->foreach_regionview (&RegionView::show_region_editor);
2770 /** Show the midi list editor for the selected MIDI regions */
2772 Editor::show_midi_list_editor ()
2774 selection->foreach_midi_regionview (&MidiRegionView::show_list_editor);
2778 Editor::rename_region ()
2780 RegionSelection rs = get_regions_from_selection_and_entered ();
2786 ArdourDialog d (_("Rename Region"), true, false);
2788 Label label (_("New name:"));
2791 hbox.set_spacing (6);
2792 hbox.pack_start (label, false, false);
2793 hbox.pack_start (entry, true, true);
2795 d.get_vbox()->set_border_width (12);
2796 d.get_vbox()->pack_start (hbox, false, false);
2798 d.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
2799 d.add_button(Gtk::Stock::OK, Gtk::RESPONSE_OK);
2801 d.set_size_request (300, -1);
2803 entry.set_text (rs.front()->region()->name());
2804 entry.select_region (0, -1);
2806 entry.signal_activate().connect (sigc::bind (sigc::mem_fun (d, &Dialog::response), RESPONSE_OK));
2812 int const ret = d.run();
2816 if (ret != RESPONSE_OK) {
2820 std::string str = entry.get_text();
2821 strip_whitespace_edges (str);
2823 rs.front()->region()->set_name (str);
2824 _regions->redisplay ();
2828 /** Start an audition of the first selected region */
2830 Editor::play_edit_range ()
2832 framepos_t start, end;
2834 if (get_edit_op_range (start, end)) {
2835 _session->request_bounded_roll (start, end);
2840 Editor::play_selected_region ()
2842 framepos_t start = max_framepos;
2845 RegionSelection rs = get_regions_from_selection_and_entered ();
2851 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
2852 if ((*i)->region()->position() < start) {
2853 start = (*i)->region()->position();
2855 if ((*i)->region()->last_frame() + 1 > end) {
2856 end = (*i)->region()->last_frame() + 1;
2860 _session->request_bounded_roll (start, end);
2864 Editor::audition_playlist_region_standalone (boost::shared_ptr<Region> region)
2866 _session->audition_region (region);
2870 Editor::region_from_selection ()
2872 if (clicked_axisview == 0) {
2876 if (selection->time.empty()) {
2880 framepos_t start = selection->time[clicked_selection].start;
2881 framepos_t end = selection->time[clicked_selection].end;
2883 TrackViewList tracks = get_tracks_for_range_action ();
2885 framepos_t selection_cnt = end - start + 1;
2887 for (TrackSelection::iterator i = tracks.begin(); i != tracks.end(); ++i) {
2888 boost::shared_ptr<Region> current;
2889 boost::shared_ptr<Playlist> pl;
2890 framepos_t internal_start;
2893 if ((pl = (*i)->playlist()) == 0) {
2897 if ((current = pl->top_region_at (start)) == 0) {
2901 internal_start = start - current->position();
2902 RegionFactory::region_name (new_name, current->name(), true);
2906 plist.add (ARDOUR::Properties::start, current->start() + internal_start);
2907 plist.add (ARDOUR::Properties::length, selection_cnt);
2908 plist.add (ARDOUR::Properties::name, new_name);
2909 plist.add (ARDOUR::Properties::layer, 0);
2911 boost::shared_ptr<Region> region (RegionFactory::create (current, plist));
2916 Editor::create_region_from_selection (vector<boost::shared_ptr<Region> >& new_regions)
2918 if (selection->time.empty() || selection->tracks.empty()) {
2922 framepos_t start, end;
2923 if (clicked_selection) {
2924 start = selection->time[clicked_selection].start;
2925 end = selection->time[clicked_selection].end;
2927 start = selection->time.start();
2928 end = selection->time.end_frame();
2931 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
2932 sort_track_selection (ts);
2934 for (TrackSelection::iterator i = ts.begin(); i != ts.end(); ++i) {
2935 boost::shared_ptr<Region> current;
2936 boost::shared_ptr<Playlist> playlist;
2937 framepos_t internal_start;
2940 if ((playlist = (*i)->playlist()) == 0) {
2944 if ((current = playlist->top_region_at(start)) == 0) {
2948 internal_start = start - current->position();
2949 RegionFactory::region_name (new_name, current->name(), true);
2953 plist.add (ARDOUR::Properties::start, current->start() + internal_start);
2954 plist.add (ARDOUR::Properties::length, end - start + 1);
2955 plist.add (ARDOUR::Properties::name, new_name);
2957 new_regions.push_back (RegionFactory::create (current, plist));
2962 Editor::split_multichannel_region ()
2964 RegionSelection rs = get_regions_from_selection_and_entered ();
2970 vector< boost::shared_ptr<Region> > v;
2972 for (list<RegionView*>::iterator x = rs.begin(); x != rs.end(); ++x) {
2973 (*x)->region()->separate_by_channel (*_session, v);
2978 Editor::new_region_from_selection ()
2980 region_from_selection ();
2981 cancel_selection ();
2985 add_if_covered (RegionView* rv, const AudioRange* ar, RegionSelection* rs)
2987 switch (rv->region()->coverage (ar->start, ar->end - 1)) {
2988 // n.b. -1 because AudioRange::end is one past the end, but coverage expects inclusive ranges
2989 case Evoral::OverlapNone:
2997 * - selected tracks, or if there are none...
2998 * - tracks containing selected regions, or if there are none...
3003 Editor::get_tracks_for_range_action () const
3007 if (selection->tracks.empty()) {
3009 /* use tracks with selected regions */
3011 RegionSelection rs = selection->regions;
3013 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3014 TimeAxisView* tv = &(*i)->get_time_axis_view();
3016 if (!t.contains (tv)) {
3022 /* no regions and no tracks: use all tracks */
3028 t = selection->tracks;
3031 return t.filter_to_unique_playlists();
3035 Editor::separate_regions_between (const TimeSelection& ts)
3037 bool in_command = false;
3038 boost::shared_ptr<Playlist> playlist;
3039 RegionSelection new_selection;
3041 TrackViewList tmptracks = get_tracks_for_range_action ();
3042 sort_track_selection (tmptracks);
3044 for (TrackSelection::iterator i = tmptracks.begin(); i != tmptracks.end(); ++i) {
3046 RouteTimeAxisView* rtv;
3048 if ((rtv = dynamic_cast<RouteTimeAxisView*> ((*i))) != 0) {
3050 if (rtv->is_track()) {
3052 /* no edits to destructive tracks */
3054 if (rtv->track()->destructive()) {
3058 if ((playlist = rtv->playlist()) != 0) {
3060 playlist->clear_changes ();
3062 /* XXX need to consider musical time selections here at some point */
3064 double speed = rtv->track()->speed();
3067 for (list<AudioRange>::const_iterator t = ts.begin(); t != ts.end(); ++t) {
3069 sigc::connection c = rtv->view()->RegionViewAdded.connect (
3070 sigc::mem_fun(*this, &Editor::collect_new_region_view));
3072 latest_regionviews.clear ();
3074 playlist->partition ((framepos_t)((*t).start * speed),
3075 (framepos_t)((*t).end * speed), false);
3079 if (!latest_regionviews.empty()) {
3081 rtv->view()->foreach_regionview (sigc::bind (
3082 sigc::ptr_fun (add_if_covered),
3083 &(*t), &new_selection));
3086 begin_reversible_command (_("separate"));
3090 /* pick up changes to existing regions */
3092 vector<Command*> cmds;
3093 playlist->rdiff (cmds);
3094 _session->add_commands (cmds);
3096 /* pick up changes to the playlist itself (adds/removes)
3099 _session->add_command(new StatefulDiffCommand (playlist));
3108 // selection->set (new_selection);
3110 commit_reversible_command ();
3114 struct PlaylistState {
3115 boost::shared_ptr<Playlist> playlist;
3119 /** Take tracks from get_tracks_for_range_action and cut any regions
3120 * on those tracks so that the tracks are empty over the time
3124 Editor::separate_region_from_selection ()
3126 /* preferentially use *all* ranges in the time selection if we're in range mode
3127 to allow discontiguous operation, since get_edit_op_range() currently
3128 returns a single range.
3131 if (!selection->time.empty()) {
3133 separate_regions_between (selection->time);
3140 if (get_edit_op_range (start, end)) {
3142 AudioRange ar (start, end, 1);
3146 separate_regions_between (ts);
3152 Editor::separate_region_from_punch ()
3154 Location* loc = _session->locations()->auto_punch_location();
3156 separate_regions_using_location (*loc);
3161 Editor::separate_region_from_loop ()
3163 Location* loc = _session->locations()->auto_loop_location();
3165 separate_regions_using_location (*loc);
3170 Editor::separate_regions_using_location (Location& loc)
3172 if (loc.is_mark()) {
3176 AudioRange ar (loc.start(), loc.end(), 1);
3181 separate_regions_between (ts);
3184 /** Separate regions under the selected region */
3186 Editor::separate_under_selected_regions ()
3188 vector<PlaylistState> playlists;
3192 rs = get_regions_from_selection_and_entered();
3194 if (!_session || rs.empty()) {
3198 begin_reversible_command (_("separate region under"));
3200 list<boost::shared_ptr<Region> > regions_to_remove;
3202 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3203 // we can't just remove the region(s) in this loop because
3204 // this removes them from the RegionSelection, and they thus
3205 // disappear from underneath the iterator, and the ++i above
3206 // SEGVs in a puzzling fashion.
3208 // so, first iterate over the regions to be removed from rs and
3209 // add them to the regions_to_remove list, and then
3210 // iterate over the list to actually remove them.
3212 regions_to_remove.push_back ((*i)->region());
3215 for (list<boost::shared_ptr<Region> >::iterator rl = regions_to_remove.begin(); rl != regions_to_remove.end(); ++rl) {
3217 boost::shared_ptr<Playlist> playlist = (*rl)->playlist();
3220 // is this check necessary?
3224 vector<PlaylistState>::iterator i;
3226 //only take state if this is a new playlist.
3227 for (i = playlists.begin(); i != playlists.end(); ++i) {
3228 if ((*i).playlist == playlist) {
3233 if (i == playlists.end()) {
3235 PlaylistState before;
3236 before.playlist = playlist;
3237 before.before = &playlist->get_state();
3239 playlist->freeze ();
3240 playlists.push_back(before);
3243 //Partition on the region bounds
3244 playlist->partition ((*rl)->first_frame() - 1, (*rl)->last_frame() + 1, true);
3246 //Re-add region that was just removed due to the partition operation
3247 playlist->add_region( (*rl), (*rl)->first_frame() );
3250 vector<PlaylistState>::iterator pl;
3252 for (pl = playlists.begin(); pl != playlists.end(); ++pl) {
3253 (*pl).playlist->thaw ();
3254 _session->add_command(new MementoCommand<Playlist>(*(*pl).playlist, (*pl).before, &(*pl).playlist->get_state()));
3257 commit_reversible_command ();
3261 Editor::crop_region_to_selection ()
3263 if (!selection->time.empty()) {
3265 crop_region_to (selection->time.start(), selection->time.end_frame());
3272 if (get_edit_op_range (start, end)) {
3273 crop_region_to (start, end);
3280 Editor::crop_region_to (framepos_t start, framepos_t end)
3282 vector<boost::shared_ptr<Playlist> > playlists;
3283 boost::shared_ptr<Playlist> playlist;
3286 if (selection->tracks.empty()) {
3287 ts = track_views.filter_to_unique_playlists();
3289 ts = selection->tracks.filter_to_unique_playlists ();
3292 sort_track_selection (ts);
3294 for (TrackSelection::iterator i = ts.begin(); i != ts.end(); ++i) {
3296 RouteTimeAxisView* rtv;
3298 if ((rtv = dynamic_cast<RouteTimeAxisView*> ((*i))) != 0) {
3300 boost::shared_ptr<Track> t = rtv->track();
3302 if (t != 0 && ! t->destructive()) {
3304 if ((playlist = rtv->playlist()) != 0) {
3305 playlists.push_back (playlist);
3311 if (playlists.empty()) {
3316 framepos_t new_start;
3318 framecnt_t new_length;
3319 bool in_command = false;
3321 for (vector<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
3323 /* Only the top regions at start and end have to be cropped */
3324 boost::shared_ptr<Region> region_at_start = (*i)->top_region_at(start);
3325 boost::shared_ptr<Region> region_at_end = (*i)->top_region_at(end);
3327 vector<boost::shared_ptr<Region> > regions;
3329 if (region_at_start != 0) {
3330 regions.push_back (region_at_start);
3332 if (region_at_end != 0) {
3333 regions.push_back (region_at_end);
3336 /* now adjust lengths */
3337 for (vector<boost::shared_ptr<Region> >::iterator i = regions.begin(); i != regions.end(); ++i) {
3339 pos = (*i)->position();
3340 new_start = max (start, pos);
3341 if (max_framepos - pos > (*i)->length()) {
3342 new_end = pos + (*i)->length() - 1;
3344 new_end = max_framepos;
3346 new_end = min (end, new_end);
3347 new_length = new_end - new_start + 1;
3350 begin_reversible_command (_("trim to selection"));
3353 (*i)->clear_changes ();
3354 (*i)->trim_to (new_start, new_length);
3355 _session->add_command (new StatefulDiffCommand (*i));
3360 commit_reversible_command ();
3365 Editor::region_fill_track ()
3367 boost::shared_ptr<Playlist> playlist;
3368 RegionSelection regions = get_regions_from_selection_and_entered ();
3369 RegionSelection foo;
3371 framepos_t const end = _session->current_end_frame ();
3373 if (regions.empty () || regions.end_frame () + 1 >= end) {
3377 framepos_t const start_frame = regions.start ();
3378 framepos_t const end_frame = regions.end_frame ();
3379 framecnt_t const gap = end_frame - start_frame + 1;
3381 begin_reversible_command (Operations::region_fill);
3383 selection->clear_regions ();
3385 for (RegionSelection::iterator i = regions.begin(); i != regions.end(); ++i) {
3387 boost::shared_ptr<Region> r ((*i)->region());
3389 TimeAxisView& tv = (*i)->get_time_axis_view();
3390 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (&tv);
3391 latest_regionviews.clear ();
3392 sigc::connection c = rtv->view()->RegionViewAdded.connect (sigc::mem_fun(*this, &Editor::collect_new_region_view));
3394 framepos_t const position = end_frame + (r->first_frame() - start_frame + 1);
3395 playlist = (*i)->region()->playlist();
3396 playlist->clear_changes ();
3397 playlist->duplicate_until (r, position, gap, end);
3398 _session->add_command(new StatefulDiffCommand (playlist));
3402 foo.insert (foo.end(), latest_regionviews.begin(), latest_regionviews.end());
3406 selection->set (foo);
3409 commit_reversible_command ();
3413 Editor::set_region_sync_position ()
3415 set_sync_point (get_preferred_edit_position (), get_regions_from_selection_and_edit_point ());
3419 Editor::set_sync_point (framepos_t where, const RegionSelection& rs)
3421 bool in_command = false;
3423 for (RegionSelection::const_iterator r = rs.begin(); r != rs.end(); ++r) {
3425 if (!(*r)->region()->covers (where)) {
3429 boost::shared_ptr<Region> region ((*r)->region());
3432 begin_reversible_command (_("set sync point"));
3436 region->clear_changes ();
3437 region->set_sync_position (where);
3438 _session->add_command(new StatefulDiffCommand (region));
3442 commit_reversible_command ();
3446 /** Remove the sync positions of the selection */
3448 Editor::remove_region_sync ()
3450 RegionSelection rs = get_regions_from_selection_and_entered ();
3456 begin_reversible_command (_("remove region sync"));
3458 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3460 (*i)->region()->clear_changes ();
3461 (*i)->region()->clear_sync_position ();
3462 _session->add_command(new StatefulDiffCommand ((*i)->region()));
3465 commit_reversible_command ();
3469 Editor::naturalize_region ()
3471 RegionSelection rs = get_regions_from_selection_and_entered ();
3477 if (rs.size() > 1) {
3478 begin_reversible_command (_("move regions to original position"));
3480 begin_reversible_command (_("move region to original position"));
3483 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3484 (*i)->region()->clear_changes ();
3485 (*i)->region()->move_to_natural_position ();
3486 _session->add_command (new StatefulDiffCommand ((*i)->region()));
3489 commit_reversible_command ();
3493 Editor::align_regions (RegionPoint what)
3495 RegionSelection const rs = get_regions_from_selection_and_edit_point ();
3501 begin_reversible_command (_("align selection"));
3503 framepos_t const position = get_preferred_edit_position ();
3505 for (RegionSelection::const_iterator i = rs.begin(); i != rs.end(); ++i) {
3506 align_region_internal ((*i)->region(), what, position);
3509 commit_reversible_command ();
3512 struct RegionSortByTime {
3513 bool operator() (const RegionView* a, const RegionView* b) {
3514 return a->region()->position() < b->region()->position();
3519 Editor::align_regions_relative (RegionPoint point)
3521 RegionSelection const rs = get_regions_from_selection_and_edit_point ();
3527 framepos_t const position = get_preferred_edit_position ();
3529 framepos_t distance = 0;
3533 list<RegionView*> sorted;
3534 rs.by_position (sorted);
3536 boost::shared_ptr<Region> r ((*sorted.begin())->region());
3541 if (position > r->position()) {
3542 distance = position - r->position();
3544 distance = r->position() - position;
3550 if (position > r->last_frame()) {
3551 distance = position - r->last_frame();
3552 pos = r->position() + distance;
3554 distance = r->last_frame() - position;
3555 pos = r->position() - distance;
3561 pos = r->adjust_to_sync (position);
3562 if (pos > r->position()) {
3563 distance = pos - r->position();
3565 distance = r->position() - pos;
3571 if (pos == r->position()) {
3575 begin_reversible_command (_("align selection (relative)"));
3577 /* move first one specially */
3579 r->clear_changes ();
3580 r->set_position (pos);
3581 _session->add_command(new StatefulDiffCommand (r));
3583 /* move rest by the same amount */
3587 for (list<RegionView*>::iterator i = sorted.begin(); i != sorted.end(); ++i) {
3589 boost::shared_ptr<Region> region ((*i)->region());
3591 region->clear_changes ();
3594 region->set_position (region->position() + distance);
3596 region->set_position (region->position() - distance);
3599 _session->add_command(new StatefulDiffCommand (region));
3603 commit_reversible_command ();
3607 Editor::align_region (boost::shared_ptr<Region> region, RegionPoint point, framepos_t position)
3609 begin_reversible_command (_("align region"));
3610 align_region_internal (region, point, position);
3611 commit_reversible_command ();
3615 Editor::align_region_internal (boost::shared_ptr<Region> region, RegionPoint point, framepos_t position)
3617 region->clear_changes ();
3621 region->set_position (region->adjust_to_sync (position));
3625 if (position > region->length()) {
3626 region->set_position (position - region->length());
3631 region->set_position (position);
3635 _session->add_command(new StatefulDiffCommand (region));
3639 Editor::trim_region_front ()
3645 Editor::trim_region_back ()
3647 trim_region (false);
3651 Editor::trim_region (bool front)
3653 framepos_t where = get_preferred_edit_position();
3654 RegionSelection rs = get_regions_from_selection_and_edit_point ();
3660 begin_reversible_command (front ? _("trim front") : _("trim back"));
3662 for (list<RegionView*>::const_iterator i = rs.by_layer().begin(); i != rs.by_layer().end(); ++i) {
3663 if (!(*i)->region()->locked()) {
3665 (*i)->region()->clear_changes ();
3668 (*i)->region()->trim_front (where);
3669 maybe_locate_with_edit_preroll ( where );
3671 (*i)->region()->trim_end (where);
3672 maybe_locate_with_edit_preroll ( where );
3675 _session->add_command (new StatefulDiffCommand ((*i)->region()));
3679 commit_reversible_command ();
3682 /** Trim the end of the selected regions to the position of the edit cursor */
3684 Editor::trim_region_to_loop ()
3686 Location* loc = _session->locations()->auto_loop_location();
3690 trim_region_to_location (*loc, _("trim to loop"));
3694 Editor::trim_region_to_punch ()
3696 Location* loc = _session->locations()->auto_punch_location();
3700 trim_region_to_location (*loc, _("trim to punch"));
3704 Editor::trim_region_to_location (const Location& loc, const char* str)
3706 RegionSelection rs = get_regions_from_selection_and_entered ();
3707 bool in_command = false;
3709 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
3710 RegionView* rv = (*x);
3712 /* require region to span proposed trim */
3713 switch (rv->region()->coverage (loc.start(), loc.end())) {
3714 case Evoral::OverlapInternal:
3720 RouteTimeAxisView* tav = dynamic_cast<RouteTimeAxisView*> (&rv->get_time_axis_view());
3729 if (tav->track() != 0) {
3730 speed = tav->track()->speed();
3733 start = session_frame_to_track_frame (loc.start(), speed);
3734 end = session_frame_to_track_frame (loc.end(), speed);
3736 rv->region()->clear_changes ();
3737 rv->region()->trim_to (start, (end - start));
3740 begin_reversible_command (str);
3743 _session->add_command(new StatefulDiffCommand (rv->region()));
3747 commit_reversible_command ();
3752 Editor::trim_region_to_previous_region_end ()
3754 return trim_to_region(false);
3758 Editor::trim_region_to_next_region_start ()
3760 return trim_to_region(true);
3764 Editor::trim_to_region(bool forward)
3766 RegionSelection rs = get_regions_from_selection_and_entered ();
3767 bool in_command = false;
3769 boost::shared_ptr<Region> next_region;
3771 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
3773 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*x);
3779 AudioTimeAxisView* atav = dynamic_cast<AudioTimeAxisView*> (&arv->get_time_axis_view());
3787 if (atav->track() != 0) {
3788 speed = atav->track()->speed();
3792 boost::shared_ptr<Region> region = arv->region();
3793 boost::shared_ptr<Playlist> playlist (region->playlist());
3795 region->clear_changes ();
3799 next_region = playlist->find_next_region (region->first_frame(), Start, 1);
3805 region->trim_end((framepos_t) ( (next_region->first_frame() - 1) * speed));
3806 arv->region_changed (PropertyChange (ARDOUR::Properties::length));
3810 next_region = playlist->find_next_region (region->first_frame(), Start, 0);
3816 region->trim_front((framepos_t) ((next_region->last_frame() + 1) * speed));
3818 arv->region_changed (ARDOUR::bounds_change);
3822 begin_reversible_command (_("trim to region"));
3825 _session->add_command(new StatefulDiffCommand (region));
3829 commit_reversible_command ();
3834 Editor::unfreeze_route ()
3836 if (clicked_routeview == 0 || !clicked_routeview->is_track()) {
3840 clicked_routeview->track()->unfreeze ();
3844 Editor::_freeze_thread (void* arg)
3846 return static_cast<Editor*>(arg)->freeze_thread ();
3850 Editor::freeze_thread ()
3852 /* create event pool because we may need to talk to the session */
3853 SessionEvent::create_per_thread_pool ("freeze events", 64);
3854 /* create per-thread buffers for process() tree to use */
3855 clicked_routeview->audio_track()->freeze_me (*current_interthread_info);
3856 current_interthread_info->done = true;
3861 Editor::freeze_route ()
3867 /* stop transport before we start. this is important */
3869 _session->request_transport_speed (0.0);
3871 /* wait for just a little while, because the above call is asynchronous */
3873 Glib::usleep (250000);
3875 if (clicked_routeview == 0 || !clicked_routeview->is_audio_track()) {
3879 if (!clicked_routeview->track()->bounceable (clicked_routeview->track()->main_outs(), true)) {
3881 _("This track/bus cannot be frozen because the signal adds or loses channels before reaching the outputs.\n"
3882 "This is typically caused by plugins that generate stereo output from mono input or vice versa.")
3884 d.set_title (_("Cannot freeze"));
3889 if (clicked_routeview->track()->has_external_redirects()) {
3890 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"
3891 "Freezing will only process the signal as far as the first send/insert/return."),
3892 clicked_routeview->track()->name()), true, MESSAGE_INFO, BUTTONS_NONE, true);
3894 d.add_button (_("Freeze anyway"), Gtk::RESPONSE_OK);
3895 d.add_button (_("Don't freeze"), Gtk::RESPONSE_CANCEL);
3896 d.set_title (_("Freeze Limits"));
3898 int response = d.run ();
3901 case Gtk::RESPONSE_CANCEL:
3908 InterThreadInfo itt;
3909 current_interthread_info = &itt;
3911 InterthreadProgressWindow ipw (current_interthread_info, _("Freeze"), _("Cancel Freeze"));
3913 pthread_create_and_store (X_("freezer"), &itt.thread, _freeze_thread, this);
3915 CursorContext::Handle cursor_ctx = CursorContext::create(*this, _cursors->wait);
3917 while (!itt.done && !itt.cancel) {
3918 gtk_main_iteration ();
3921 pthread_join (itt.thread, 0);
3922 current_interthread_info = 0;
3926 Editor::bounce_range_selection (bool replace, bool enable_processing)
3928 if (selection->time.empty()) {
3932 TrackSelection views = selection->tracks;
3934 for (TrackViewList::iterator i = views.begin(); i != views.end(); ++i) {
3936 if (enable_processing) {
3938 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*i);
3940 if (rtv && rtv->track() && replace && enable_processing && !rtv->track()->bounceable (rtv->track()->main_outs(), false)) {
3942 _("You can't perform this operation because the processing of the signal "
3943 "will cause one or more of the tracks to end up with a region with more channels than this track has inputs.\n\n"
3944 "You can do this without processing, which is a different operation.")
3946 d.set_title (_("Cannot bounce"));
3953 framepos_t start = selection->time[clicked_selection].start;
3954 framepos_t end = selection->time[clicked_selection].end;
3955 framepos_t cnt = end - start + 1;
3956 bool in_command = false;
3958 for (TrackViewList::iterator i = views.begin(); i != views.end(); ++i) {
3960 RouteTimeAxisView* rtv;
3962 if ((rtv = dynamic_cast<RouteTimeAxisView*> (*i)) == 0) {
3966 boost::shared_ptr<Playlist> playlist;
3968 if ((playlist = rtv->playlist()) == 0) {
3972 InterThreadInfo itt;
3974 playlist->clear_changes ();
3975 playlist->clear_owned_changes ();
3977 boost::shared_ptr<Region> r;
3979 if (enable_processing) {
3980 r = rtv->track()->bounce_range (start, start+cnt, itt, rtv->track()->main_outs(), false);
3982 r = rtv->track()->bounce_range (start, start+cnt, itt, boost::shared_ptr<Processor>(), false);
3990 list<AudioRange> ranges;
3991 ranges.push_back (AudioRange (start, start+cnt, 0));
3992 playlist->cut (ranges); // discard result
3993 playlist->add_region (r, start);
3997 begin_reversible_command (_("bounce range"));
4000 vector<Command*> cmds;
4001 playlist->rdiff (cmds);
4002 _session->add_commands (cmds);
4004 _session->add_command (new StatefulDiffCommand (playlist));
4008 commit_reversible_command ();
4012 /** Delete selected regions, automation points or a time range */
4016 //special case: if the user is pointing in the editor/mixer strip, they may be trying to delete a plugin.
4017 //we need this because the editor-mixer strip is in the editor window, so it doesn't get the bindings from the mix window
4018 bool deleted = false;
4019 if ( current_mixer_strip && current_mixer_strip == MixerStrip::entered_mixer_strip() )
4020 deleted = current_mixer_strip->delete_processors ();
4026 /** Cut selected regions, automation points or a time range */
4033 /** Copy selected regions, automation points or a time range */
4041 /** @return true if a Cut, Copy or Clear is possible */
4043 Editor::can_cut_copy () const
4045 if (!selection->time.empty() || !selection->regions.empty() || !selection->points.empty())
4052 /** Cut, copy or clear selected regions, automation points or a time range.
4053 * @param op Operation (Delete, Cut, Copy or Clear)
4056 Editor::cut_copy (CutCopyOp op)
4058 /* only cancel selection if cut/copy is successful.*/
4064 opname = _("delete");
4073 opname = _("clear");
4077 /* if we're deleting something, and the mouse is still pressed,
4078 the thing we started a drag for will be gone when we release
4079 the mouse button(s). avoid this. see part 2 at the end of
4083 if (op == Delete || op == Cut || op == Clear) {
4084 if (_drags->active ()) {
4089 if ( op != Delete ) //"Delete" doesn't change copy/paste buf
4090 cut_buffer->clear ();
4092 if (entered_marker) {
4094 /* cut/delete op while pointing at a marker */
4097 Location* loc = find_location_from_marker (entered_marker, ignored);
4099 if (_session && loc) {
4100 entered_marker = NULL;
4101 Glib::signal_idle().connect (sigc::bind (sigc::mem_fun(*this, &Editor::really_remove_marker), loc));
4108 switch (mouse_mode) {
4111 begin_reversible_command (opname + ' ' + X_("MIDI"));
4113 commit_reversible_command ();
4119 bool did_edit = false;
4121 if (!selection->regions.empty() || !selection->points.empty()) {
4122 begin_reversible_command (opname + ' ' + _("objects"));
4125 if (!selection->regions.empty()) {
4126 cut_copy_regions (op, selection->regions);
4128 if (op == Cut || op == Delete) {
4129 selection->clear_regions ();
4133 if (!selection->points.empty()) {
4134 cut_copy_points (op);
4136 if (op == Cut || op == Delete) {
4137 selection->clear_points ();
4140 } else if (selection->time.empty()) {
4141 framepos_t start, end;
4142 /* no time selection, see if we can get an edit range
4145 if (get_edit_op_range (start, end)) {
4146 selection->set (start, end);
4148 } else if (!selection->time.empty()) {
4149 begin_reversible_command (opname + ' ' + _("range"));
4152 cut_copy_ranges (op);
4154 if (op == Cut || op == Delete) {
4155 selection->clear_time ();
4160 /* reset repeated paste state */
4163 commit_reversible_command ();
4166 if (op == Delete || op == Cut || op == Clear) {
4171 struct AutomationRecord {
4172 AutomationRecord () : state (0) , line(NULL) {}
4173 AutomationRecord (XMLNode* s, const AutomationLine* l) : state (s) , line (l) {}
4175 XMLNode* state; ///< state before any operation
4176 const AutomationLine* line; ///< line this came from
4177 boost::shared_ptr<Evoral::ControlList> copy; ///< copied events for the cut buffer
4180 /** Cut, copy or clear selected automation points.
4181 * @param op Operation (Cut, Copy or Clear)
4184 Editor::cut_copy_points (Editing::CutCopyOp op, Evoral::Beats earliest, bool midi)
4186 if (selection->points.empty ()) {
4190 /* XXX: not ideal, as there may be more than one track involved in the point selection */
4191 _last_cut_copy_source_track = &selection->points.front()->line().trackview;
4193 /* Keep a record of the AutomationLists that we end up using in this operation */
4194 typedef std::map<boost::shared_ptr<AutomationList>, AutomationRecord> Lists;
4197 /* Go through all selected points, making an AutomationRecord for each distinct AutomationList */
4198 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
4199 const AutomationLine& line = (*i)->line();
4200 const boost::shared_ptr<AutomationList> al = line.the_list();
4201 if (lists.find (al) == lists.end ()) {
4202 /* We haven't seen this list yet, so make a record for it. This includes
4203 taking a copy of its current state, in case this is needed for undo later.
4205 lists[al] = AutomationRecord (&al->get_state (), &line);
4209 if (op == Cut || op == Copy) {
4210 /* This operation will involve putting things in the cut buffer, so create an empty
4211 ControlList for each of our source lists to put the cut buffer data in.
4213 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
4214 i->second.copy = i->first->create (i->first->parameter (), i->first->descriptor());
4217 /* Add all selected points to the relevant copy ControlLists */
4218 framepos_t start = std::numeric_limits<framepos_t>::max();
4219 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
4220 boost::shared_ptr<AutomationList> al = (*i)->line().the_list();
4221 AutomationList::const_iterator j = (*i)->model();
4223 lists[al].copy->fast_simple_add ((*j)->when, (*j)->value);
4225 /* Update earliest MIDI start time in beats */
4226 earliest = std::min(earliest, Evoral::Beats((*j)->when));
4228 /* Update earliest session start time in frames */
4229 start = std::min(start, (*i)->line().session_position(j));
4233 /* Snap start time backwards, so copy/paste is snap aligned. */
4235 if (earliest == Evoral::Beats::max()) {
4236 earliest = Evoral::Beats(); // Weird... don't offset
4238 earliest.round_down_to_beat();
4240 if (start == std::numeric_limits<double>::max()) {
4241 start = 0; // Weird... don't offset
4243 snap_to(start, RoundDownMaybe);
4246 const double line_offset = midi ? earliest.to_double() : start;
4247 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
4248 /* Correct this copy list so that it is relative to the earliest
4249 start time, so relative ordering between points is preserved
4250 when copying from several lists and the paste starts at the
4251 earliest copied piece of data. */
4252 for (AutomationList::iterator j = i->second.copy->begin(); j != i->second.copy->end(); ++j) {
4253 (*j)->when -= line_offset;
4256 /* And add it to the cut buffer */
4257 cut_buffer->add (i->second.copy);
4261 if (op == Delete || op == Cut) {
4262 /* This operation needs to remove things from the main AutomationList, so do that now */
4264 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
4265 i->first->freeze ();
4268 /* Remove each selected point from its AutomationList */
4269 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
4270 boost::shared_ptr<AutomationList> al = (*i)->line().the_list();
4271 al->erase ((*i)->model ());
4274 /* Thaw the lists and add undo records for them */
4275 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
4276 boost::shared_ptr<AutomationList> al = i->first;
4278 _session->add_command (new MementoCommand<AutomationList> (*al.get(), i->second.state, &(al->get_state ())));
4283 /** Cut, copy or clear selected automation points.
4284 * @param op Operation (Cut, Copy or Clear)
4287 Editor::cut_copy_midi (CutCopyOp op)
4289 Evoral::Beats earliest = Evoral::Beats::max();
4290 for (MidiRegionSelection::iterator i = selection->midi_regions.begin(); i != selection->midi_regions.end(); ++i) {
4291 MidiRegionView* mrv = dynamic_cast<MidiRegionView*>(*i);
4293 if (!mrv->selection().empty()) {
4294 earliest = std::min(earliest, (*mrv->selection().begin())->note()->time());
4296 mrv->cut_copy_clear (op);
4298 /* XXX: not ideal, as there may be more than one track involved in the selection */
4299 _last_cut_copy_source_track = &mrv->get_time_axis_view();
4303 if (!selection->points.empty()) {
4304 cut_copy_points (op, earliest, true);
4305 if (op == Cut || op == Delete) {
4306 selection->clear_points ();
4311 struct lt_playlist {
4312 bool operator () (const PlaylistState& a, const PlaylistState& b) {
4313 return a.playlist < b.playlist;
4317 struct PlaylistMapping {
4319 boost::shared_ptr<Playlist> pl;
4321 PlaylistMapping (TimeAxisView* tvp) : tv (tvp) {}
4324 /** Remove `clicked_regionview' */
4326 Editor::remove_clicked_region ()
4328 if (clicked_routeview == 0 || clicked_regionview == 0) {
4332 begin_reversible_command (_("remove region"));
4334 boost::shared_ptr<Playlist> playlist = clicked_routeview->playlist();
4336 playlist->clear_changes ();
4337 playlist->clear_owned_changes ();
4338 playlist->remove_region (clicked_regionview->region());
4339 if (Config->get_edit_mode() == Ripple)
4340 playlist->ripple (clicked_regionview->region()->position(), -clicked_regionview->region()->length(), boost::shared_ptr<Region>());
4342 /* We might have removed regions, which alters other regions' layering_index,
4343 so we need to do a recursive diff here.
4345 vector<Command*> cmds;
4346 playlist->rdiff (cmds);
4347 _session->add_commands (cmds);
4349 _session->add_command(new StatefulDiffCommand (playlist));
4350 commit_reversible_command ();
4354 /** Remove the selected regions */
4356 Editor::remove_selected_regions ()
4358 RegionSelection rs = get_regions_from_selection_and_entered ();
4360 if (!_session || rs.empty()) {
4364 list<boost::shared_ptr<Region> > regions_to_remove;
4366 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
4367 // we can't just remove the region(s) in this loop because
4368 // this removes them from the RegionSelection, and they thus
4369 // disappear from underneath the iterator, and the ++i above
4370 // SEGVs in a puzzling fashion.
4372 // so, first iterate over the regions to be removed from rs and
4373 // add them to the regions_to_remove list, and then
4374 // iterate over the list to actually remove them.
4376 regions_to_remove.push_back ((*i)->region());
4379 vector<boost::shared_ptr<Playlist> > playlists;
4381 for (list<boost::shared_ptr<Region> >::iterator rl = regions_to_remove.begin(); rl != regions_to_remove.end(); ++rl) {
4383 boost::shared_ptr<Playlist> playlist = (*rl)->playlist();
4386 // is this check necessary?
4390 /* get_regions_from_selection_and_entered() guarantees that
4391 the playlists involved are unique, so there is no need
4395 playlists.push_back (playlist);
4397 playlist->clear_changes ();
4398 playlist->clear_owned_changes ();
4399 playlist->freeze ();
4400 playlist->remove_region (*rl);
4401 if (Config->get_edit_mode() == Ripple)
4402 playlist->ripple ((*rl)->position(), -(*rl)->length(), boost::shared_ptr<Region>());
4406 vector<boost::shared_ptr<Playlist> >::iterator pl;
4407 bool in_command = false;
4409 for (pl = playlists.begin(); pl != playlists.end(); ++pl) {
4412 /* We might have removed regions, which alters other regions' layering_index,
4413 so we need to do a recursive diff here.
4417 begin_reversible_command (_("remove region"));
4420 vector<Command*> cmds;
4421 (*pl)->rdiff (cmds);
4422 _session->add_commands (cmds);
4424 _session->add_command(new StatefulDiffCommand (*pl));
4428 commit_reversible_command ();
4432 /** Cut, copy or clear selected regions.
4433 * @param op Operation (Cut, Copy or Clear)
4436 Editor::cut_copy_regions (CutCopyOp op, RegionSelection& rs)
4438 /* we can't use a std::map here because the ordering is important, and we can't trivially sort
4439 a map when we want ordered access to both elements. i think.
4442 vector<PlaylistMapping> pmap;
4444 framepos_t first_position = max_framepos;
4446 typedef set<boost::shared_ptr<Playlist> > FreezeList;
4447 FreezeList freezelist;
4449 /* get ordering correct before we cut/copy */
4451 rs.sort_by_position_and_track ();
4453 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
4455 first_position = min ((framepos_t) (*x)->region()->position(), first_position);
4457 if (op == Cut || op == Clear || op == Delete) {
4458 boost::shared_ptr<Playlist> pl = (*x)->region()->playlist();
4461 FreezeList::iterator fl;
4463 // only take state if this is a new playlist.
4464 for (fl = freezelist.begin(); fl != freezelist.end(); ++fl) {
4470 if (fl == freezelist.end()) {
4471 pl->clear_changes();
4472 pl->clear_owned_changes ();
4474 freezelist.insert (pl);
4479 TimeAxisView* tv = &(*x)->get_time_axis_view();
4480 vector<PlaylistMapping>::iterator z;
4482 for (z = pmap.begin(); z != pmap.end(); ++z) {
4483 if ((*z).tv == tv) {
4488 if (z == pmap.end()) {
4489 pmap.push_back (PlaylistMapping (tv));
4493 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ) {
4495 boost::shared_ptr<Playlist> pl = (*x)->region()->playlist();
4498 /* region not yet associated with a playlist (e.g. unfinished
4505 TimeAxisView& tv = (*x)->get_time_axis_view();
4506 boost::shared_ptr<Playlist> npl;
4507 RegionSelection::iterator tmp;
4514 vector<PlaylistMapping>::iterator z;
4516 for (z = pmap.begin(); z != pmap.end(); ++z) {
4517 if ((*z).tv == &tv) {
4522 assert (z != pmap.end());
4525 npl = PlaylistFactory::create (pl->data_type(), *_session, "cutlist", true);
4533 boost::shared_ptr<Region> r = (*x)->region();
4534 boost::shared_ptr<Region> _xx;
4540 pl->remove_region (r);
4541 if (Config->get_edit_mode() == Ripple)
4542 pl->ripple (r->position(), -r->length(), boost::shared_ptr<Region>());
4546 _xx = RegionFactory::create (r);
4547 npl->add_region (_xx, r->position() - first_position);
4548 pl->remove_region (r);
4549 if (Config->get_edit_mode() == Ripple)
4550 pl->ripple (r->position(), -r->length(), boost::shared_ptr<Region>());
4554 /* copy region before adding, so we're not putting same object into two different playlists */
4555 npl->add_region (RegionFactory::create (r), r->position() - first_position);
4559 pl->remove_region (r);
4560 if (Config->get_edit_mode() == Ripple)
4561 pl->ripple (r->position(), -r->length(), boost::shared_ptr<Region>());
4570 list<boost::shared_ptr<Playlist> > foo;
4572 /* the pmap is in the same order as the tracks in which selected regions occurred */
4574 for (vector<PlaylistMapping>::iterator i = pmap.begin(); i != pmap.end(); ++i) {
4577 foo.push_back ((*i).pl);
4582 cut_buffer->set (foo);
4586 _last_cut_copy_source_track = 0;
4588 _last_cut_copy_source_track = pmap.front().tv;
4592 for (FreezeList::iterator pl = freezelist.begin(); pl != freezelist.end(); ++pl) {
4595 /* We might have removed regions, which alters other regions' layering_index,
4596 so we need to do a recursive diff here.
4598 vector<Command*> cmds;
4599 (*pl)->rdiff (cmds);
4600 _session->add_commands (cmds);
4602 _session->add_command (new StatefulDiffCommand (*pl));
4607 Editor::cut_copy_ranges (CutCopyOp op)
4609 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4611 /* Sort the track selection now, so that it if is used, the playlists
4612 selected by the calls below to cut_copy_clear are in the order that
4613 their tracks appear in the editor. This makes things like paste
4614 of ranges work properly.
4617 sort_track_selection (ts);
4620 if (!entered_track) {
4623 ts.push_back (entered_track);
4626 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4627 (*i)->cut_copy_clear (*selection, op);
4632 Editor::paste (float times, bool from_context)
4634 DEBUG_TRACE (DEBUG::CutNPaste, "paste to preferred edit pos\n");
4636 paste_internal (get_preferred_edit_position (EDIT_IGNORE_NONE, from_context), times);
4640 Editor::mouse_paste ()
4645 if (!mouse_frame (where, ignored)) {
4650 paste_internal (where, 1);
4654 Editor::paste_internal (framepos_t position, float times)
4656 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("apparent paste position is %1\n", position));
4658 if (cut_buffer->empty(internal_editing())) {
4662 if (position == max_framepos) {
4663 position = get_preferred_edit_position();
4664 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("preferred edit position is %1\n", position));
4667 if (position == last_paste_pos) {
4668 /* repeated paste in the same position */
4671 /* paste in new location, reset repeated paste state */
4673 last_paste_pos = position;
4676 /* get everything in the correct order */
4679 if (!selection->tracks.empty()) {
4680 /* If there is a track selection, paste into exactly those tracks and
4681 only those tracks. This allows the user to be explicit and override
4682 the below "do the reasonable thing" logic. */
4683 ts = selection->tracks.filter_to_unique_playlists ();
4684 sort_track_selection (ts);
4686 /* Figure out which track to base the paste at. */
4687 TimeAxisView* base_track = NULL;
4688 if (_edit_point == Editing::EditAtMouse && entered_track) {
4689 /* With the mouse edit point, paste onto the track under the mouse. */
4690 base_track = entered_track;
4691 } else if (_edit_point == Editing::EditAtMouse && entered_regionview) {
4692 /* With the mouse edit point, paste onto the track of the region under the mouse. */
4693 base_track = &entered_regionview->get_time_axis_view();
4694 } else if (_last_cut_copy_source_track) {
4695 /* Paste to the track that the cut/copy came from (see mantis #333). */
4696 base_track = _last_cut_copy_source_track;
4698 /* This is "impossible" since we've copied... well, do nothing. */
4702 /* Walk up to parent if necessary, so base track is a route. */
4703 while (base_track->get_parent()) {
4704 base_track = base_track->get_parent();
4707 /* Add base track and all tracks below it. The paste logic will select
4708 the appropriate object types from the cut buffer in relative order. */
4709 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4710 if ((*i)->order() >= base_track->order()) {
4715 /* Sort tracks so the nth track of type T will pick the nth object of type T. */
4716 sort_track_selection (ts);
4718 /* Add automation children of each track in order, for pasting several lines. */
4719 for (TrackViewList::iterator i = ts.begin(); i != ts.end();) {
4720 /* Add any automation children for pasting several lines */
4721 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*i++);
4726 typedef RouteTimeAxisView::AutomationTracks ATracks;
4727 const ATracks& atracks = rtv->automation_tracks();
4728 for (ATracks::const_iterator a = atracks.begin(); a != atracks.end(); ++a) {
4729 i = ts.insert(i, a->second.get());
4734 /* We now have a list of trackviews starting at base_track, including
4735 automation children, in the order shown in the editor, e.g. R1,
4736 R1.A1, R1.A2, R2, R2.A1, ... */
4739 begin_reversible_command (Operations::paste);
4741 if (ts.size() == 1 && cut_buffer->lines.size() == 1 &&
4742 dynamic_cast<AutomationTimeAxisView*>(ts.front())) {
4743 /* Only one line copied, and one automation track selected. Do a
4744 "greedy" paste from one automation type to another. */
4746 PasteContext ctx(paste_count, times, ItemCounts(), true);
4747 ts.front()->paste (position, *cut_buffer, ctx);
4751 /* Paste into tracks */
4753 PasteContext ctx(paste_count, times, ItemCounts(), false);
4754 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4755 (*i)->paste (position, *cut_buffer, ctx);
4759 commit_reversible_command ();
4763 Editor::duplicate_some_regions (RegionSelection& regions, float times)
4765 if (regions.empty ()) {
4769 boost::shared_ptr<Playlist> playlist;
4770 RegionSelection sel = regions; // clear (below) may clear the argument list if its the current region selection
4771 RegionSelection foo;
4773 framepos_t const start_frame = regions.start ();
4774 framepos_t const end_frame = regions.end_frame ();
4775 framecnt_t const gap = end_frame - start_frame + 1;
4777 begin_reversible_command (Operations::duplicate_region);
4779 selection->clear_regions ();
4781 for (RegionSelection::iterator i = sel.begin(); i != sel.end(); ++i) {
4783 boost::shared_ptr<Region> r ((*i)->region());
4785 TimeAxisView& tv = (*i)->get_time_axis_view();
4786 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (&tv);
4787 latest_regionviews.clear ();
4788 sigc::connection c = rtv->view()->RegionViewAdded.connect (sigc::mem_fun(*this, &Editor::collect_new_region_view));
4790 framepos_t const position = end_frame + (r->first_frame() - start_frame + 1);
4791 playlist = (*i)->region()->playlist();
4792 playlist->clear_changes ();
4793 playlist->duplicate (r, position, gap, times);
4794 _session->add_command(new StatefulDiffCommand (playlist));
4798 foo.insert (foo.end(), latest_regionviews.begin(), latest_regionviews.end());
4802 selection->set (foo);
4805 commit_reversible_command ();
4809 Editor::duplicate_selection (float times)
4811 if (selection->time.empty() || selection->tracks.empty()) {
4815 boost::shared_ptr<Playlist> playlist;
4817 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4819 bool in_command = false;
4821 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4822 if ((playlist = (*i)->playlist()) == 0) {
4825 playlist->clear_changes ();
4827 if (clicked_selection) {
4828 playlist->duplicate_range (selection->time[clicked_selection], times);
4830 playlist->duplicate_ranges (selection->time, times);
4834 begin_reversible_command (_("duplicate range selection"));
4837 _session->add_command (new StatefulDiffCommand (playlist));
4842 // now "move" range selection to after the current range selection
4843 framecnt_t distance = 0;
4845 if (clicked_selection) {
4846 distance = selection->time[clicked_selection].end -
4847 selection->time[clicked_selection].start;
4849 distance = selection->time.end_frame() - selection->time.start();
4852 selection->move_time (distance);
4854 commit_reversible_command ();
4858 /** Reset all selected points to the relevant default value */
4860 Editor::reset_point_selection ()
4862 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
4863 ARDOUR::AutomationList::iterator j = (*i)->model ();
4864 (*j)->value = (*i)->line().the_list()->default_value ();
4869 Editor::center_playhead ()
4871 float const page = _visible_canvas_width * samples_per_pixel;
4872 center_screen_internal (playhead_cursor->current_frame (), page);
4876 Editor::center_edit_point ()
4878 float const page = _visible_canvas_width * samples_per_pixel;
4879 center_screen_internal (get_preferred_edit_position(), page);
4882 /** Caller must begin and commit a reversible command */
4884 Editor::clear_playlist (boost::shared_ptr<Playlist> playlist)
4886 playlist->clear_changes ();
4888 _session->add_command (new StatefulDiffCommand (playlist));
4892 Editor::nudge_track (bool use_edit, bool forwards)
4894 boost::shared_ptr<Playlist> playlist;
4895 framepos_t distance;
4896 framepos_t next_distance;
4900 start = get_preferred_edit_position();
4905 if ((distance = get_nudge_distance (start, next_distance)) == 0) {
4909 if (selection->tracks.empty()) {
4913 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4914 bool in_command = false;
4916 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4918 if ((playlist = (*i)->playlist()) == 0) {
4922 playlist->clear_changes ();
4923 playlist->clear_owned_changes ();
4925 playlist->nudge_after (start, distance, forwards);
4928 begin_reversible_command (_("nudge track"));
4931 vector<Command*> cmds;
4933 playlist->rdiff (cmds);
4934 _session->add_commands (cmds);
4936 _session->add_command (new StatefulDiffCommand (playlist));
4940 commit_reversible_command ();
4945 Editor::remove_last_capture ()
4947 vector<string> choices;
4954 if (Config->get_verify_remove_last_capture()) {
4955 prompt = _("Do you really want to destroy the last capture?"
4956 "\n(This is destructive and cannot be undone)");
4958 choices.push_back (_("No, do nothing."));
4959 choices.push_back (_("Yes, destroy it."));
4961 Gtkmm2ext::Choice prompter (_("Destroy last capture"), prompt, choices);
4963 if (prompter.run () == 1) {
4964 _session->remove_last_capture ();
4965 _regions->redisplay ();
4969 _session->remove_last_capture();
4970 _regions->redisplay ();
4975 Editor::normalize_region ()
4981 RegionSelection rs = get_regions_from_selection_and_entered ();
4987 NormalizeDialog dialog (rs.size() > 1);
4989 if (dialog.run () == RESPONSE_CANCEL) {
4993 CursorContext::Handle cursor_ctx = CursorContext::create(*this, _cursors->wait);
4996 /* XXX: should really only count audio regions here */
4997 int const regions = rs.size ();
4999 /* Make a list of the selected audio regions' maximum amplitudes, and also
5000 obtain the maximum amplitude of them all.
5002 list<double> max_amps;
5004 for (RegionSelection::const_iterator i = rs.begin(); i != rs.end(); ++i) {
5005 AudioRegionView const * arv = dynamic_cast<AudioRegionView const *> (*i);
5007 dialog.descend (1.0 / regions);
5008 double const a = arv->audio_region()->maximum_amplitude (&dialog);
5011 /* the user cancelled the operation */
5015 max_amps.push_back (a);
5016 max_amp = max (max_amp, a);
5021 list<double>::const_iterator a = max_amps.begin ();
5022 bool in_command = false;
5024 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
5025 AudioRegionView* const arv = dynamic_cast<AudioRegionView*> (*r);
5030 arv->region()->clear_changes ();
5032 double const amp = dialog.normalize_individually() ? *a : max_amp;
5034 arv->audio_region()->normalize (amp, dialog.target ());
5037 begin_reversible_command (_("normalize"));
5040 _session->add_command (new StatefulDiffCommand (arv->region()));
5046 commit_reversible_command ();
5052 Editor::reset_region_scale_amplitude ()
5058 RegionSelection rs = get_regions_from_selection_and_entered ();
5064 bool in_command = false;
5066 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
5067 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
5070 arv->region()->clear_changes ();
5071 arv->audio_region()->set_scale_amplitude (1.0f);
5074 begin_reversible_command ("reset gain");
5077 _session->add_command (new StatefulDiffCommand (arv->region()));
5081 commit_reversible_command ();
5086 Editor::adjust_region_gain (bool up)
5088 RegionSelection rs = get_regions_from_selection_and_entered ();
5090 if (!_session || rs.empty()) {
5094 bool in_command = false;
5096 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
5097 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
5102 arv->region()->clear_changes ();
5104 double dB = accurate_coefficient_to_dB (arv->audio_region()->scale_amplitude ());
5112 arv->audio_region()->set_scale_amplitude (dB_to_coefficient (dB));
5115 begin_reversible_command ("adjust region gain");
5118 _session->add_command (new StatefulDiffCommand (arv->region()));
5122 commit_reversible_command ();
5128 Editor::reverse_region ()
5134 Reverse rev (*_session);
5135 apply_filter (rev, _("reverse regions"));
5139 Editor::strip_region_silence ()
5145 RegionSelection rs = get_regions_from_selection_and_entered ();
5151 std::list<RegionView*> audio_only;
5153 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5154 AudioRegionView* const arv = dynamic_cast<AudioRegionView*> (*i);
5156 audio_only.push_back (arv);
5160 assert (!audio_only.empty());
5162 StripSilenceDialog d (_session, audio_only);
5163 int const r = d.run ();
5167 if (r == Gtk::RESPONSE_OK) {
5168 ARDOUR::AudioIntervalMap silences;
5169 d.silences (silences);
5170 StripSilence s (*_session, silences, d.fade_length());
5172 apply_filter (s, _("strip silence"), &d);
5177 Editor::apply_midi_note_edit_op_to_region (MidiOperator& op, MidiRegionView& mrv)
5179 Evoral::Sequence<Evoral::Beats>::Notes selected;
5180 mrv.selection_as_notelist (selected, true);
5182 vector<Evoral::Sequence<Evoral::Beats>::Notes> v;
5183 v.push_back (selected);
5185 framepos_t pos_frames = mrv.midi_region()->position() - mrv.midi_region()->start();
5186 Evoral::Beats pos_beats = _session->tempo_map().framewalk_to_beats(0, pos_frames);
5188 return op (mrv.midi_region()->model(), pos_beats, v);
5192 Editor::apply_midi_note_edit_op (MidiOperator& op, const RegionSelection& rs)
5198 bool in_command = false;
5200 for (RegionSelection::const_iterator r = rs.begin(); r != rs.end(); ) {
5201 RegionSelection::const_iterator tmp = r;
5204 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*r);
5207 Command* cmd = apply_midi_note_edit_op_to_region (op, *mrv);
5210 begin_reversible_command (op.name ());
5214 _session->add_command (cmd);
5222 commit_reversible_command ();
5227 Editor::fork_region ()
5229 RegionSelection rs = get_regions_from_selection_and_entered ();
5235 CursorContext::Handle cursor_ctx = CursorContext::create(*this, _cursors->wait);
5236 bool in_command = false;
5240 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
5241 RegionSelection::iterator tmp = r;
5244 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*>(*r);
5248 boost::shared_ptr<Playlist> playlist = mrv->region()->playlist();
5249 boost::shared_ptr<MidiSource> new_source = _session->create_midi_source_by_stealing_name (mrv->midi_view()->track());
5250 boost::shared_ptr<MidiRegion> newregion = mrv->midi_region()->clone (new_source);
5253 begin_reversible_command (_("Fork Region(s)"));
5256 playlist->clear_changes ();
5257 playlist->replace_region (mrv->region(), newregion, mrv->region()->position());
5258 _session->add_command(new StatefulDiffCommand (playlist));
5260 error << string_compose (_("Could not unlink %1"), mrv->region()->name()) << endmsg;
5268 commit_reversible_command ();
5273 Editor::quantize_region ()
5276 quantize_regions(get_regions_from_selection_and_entered ());
5281 Editor::quantize_regions (const RegionSelection& rs)
5283 if (rs.n_midi_regions() == 0) {
5287 if (!quantize_dialog) {
5288 quantize_dialog = new QuantizeDialog (*this);
5291 quantize_dialog->present ();
5292 const int r = quantize_dialog->run ();
5293 quantize_dialog->hide ();
5295 if (r == Gtk::RESPONSE_OK) {
5296 Quantize quant (quantize_dialog->snap_start(),
5297 quantize_dialog->snap_end(),
5298 quantize_dialog->start_grid_size(),
5299 quantize_dialog->end_grid_size(),
5300 quantize_dialog->strength(),
5301 quantize_dialog->swing(),
5302 quantize_dialog->threshold());
5304 apply_midi_note_edit_op (quant, rs);
5309 Editor::legatize_region (bool shrink_only)
5312 legatize_regions(get_regions_from_selection_and_entered (), shrink_only);
5317 Editor::legatize_regions (const RegionSelection& rs, bool shrink_only)
5319 if (rs.n_midi_regions() == 0) {
5323 Legatize legatize(shrink_only);
5324 apply_midi_note_edit_op (legatize, rs);
5328 Editor::transform_region ()
5331 transform_regions(get_regions_from_selection_and_entered ());
5336 Editor::transform_regions (const RegionSelection& rs)
5338 if (rs.n_midi_regions() == 0) {
5345 const int r = td.run();
5348 if (r == Gtk::RESPONSE_OK) {
5349 Transform transform(td.get());
5350 apply_midi_note_edit_op(transform, rs);
5355 Editor::transpose_region ()
5358 transpose_regions(get_regions_from_selection_and_entered ());
5363 Editor::transpose_regions (const RegionSelection& rs)
5365 if (rs.n_midi_regions() == 0) {
5370 int const r = d.run ();
5372 if (r == RESPONSE_ACCEPT) {
5373 Transpose transpose(d.semitones ());
5374 apply_midi_note_edit_op (transpose, rs);
5379 Editor::insert_patch_change (bool from_context)
5381 RegionSelection rs = get_regions_from_selection_and_entered ();
5387 const framepos_t p = get_preferred_edit_position (EDIT_IGNORE_NONE, from_context);
5389 /* XXX: bit of a hack; use the MIDNAM from the first selected region;
5390 there may be more than one, but the PatchChangeDialog can only offer
5391 one set of patch menus.
5393 MidiRegionView* first = dynamic_cast<MidiRegionView*> (rs.front ());
5395 Evoral::PatchChange<Evoral::Beats> empty (Evoral::Beats(), 0, 0, 0);
5396 PatchChangeDialog d (0, _session, empty, first->instrument_info(), Gtk::Stock::ADD);
5398 if (d.run() == RESPONSE_CANCEL) {
5402 for (RegionSelection::iterator i = rs.begin (); i != rs.end(); ++i) {
5403 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*i);
5405 if (p >= mrv->region()->first_frame() && p <= mrv->region()->last_frame()) {
5406 mrv->add_patch_change (p - mrv->region()->position(), d.patch ());
5413 Editor::apply_filter (Filter& filter, string command, ProgressReporter* progress)
5415 RegionSelection rs = get_regions_from_selection_and_entered ();
5421 CursorContext::Handle cursor_ctx = CursorContext::create(*this, _cursors->wait);
5422 bool in_command = false;
5427 int const N = rs.size ();
5429 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
5430 RegionSelection::iterator tmp = r;
5433 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
5435 boost::shared_ptr<Playlist> playlist = arv->region()->playlist();
5438 progress->descend (1.0 / N);
5441 if (arv->audio_region()->apply (filter, progress) == 0) {
5443 playlist->clear_changes ();
5444 playlist->clear_owned_changes ();
5447 begin_reversible_command (command);
5451 if (filter.results.empty ()) {
5453 /* no regions returned; remove the old one */
5454 playlist->remove_region (arv->region ());
5458 std::vector<boost::shared_ptr<Region> >::iterator res = filter.results.begin ();
5460 /* first region replaces the old one */
5461 playlist->replace_region (arv->region(), *res, (*res)->position());
5465 while (res != filter.results.end()) {
5466 playlist->add_region (*res, (*res)->position());
5472 /* We might have removed regions, which alters other regions' layering_index,
5473 so we need to do a recursive diff here.
5475 vector<Command*> cmds;
5476 playlist->rdiff (cmds);
5477 _session->add_commands (cmds);
5479 _session->add_command(new StatefulDiffCommand (playlist));
5483 progress->ascend ();
5492 commit_reversible_command ();
5497 Editor::external_edit_region ()
5503 Editor::reset_region_gain_envelopes ()
5505 RegionSelection rs = get_regions_from_selection_and_entered ();
5507 if (!_session || rs.empty()) {
5511 bool in_command = false;
5513 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5514 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
5516 boost::shared_ptr<AutomationList> alist (arv->audio_region()->envelope());
5517 XMLNode& before (alist->get_state());
5519 arv->audio_region()->set_default_envelope ();
5522 begin_reversible_command (_("reset region gain"));
5525 _session->add_command (new MementoCommand<AutomationList>(*arv->audio_region()->envelope().get(), &before, &alist->get_state()));
5530 commit_reversible_command ();
5535 Editor::set_region_gain_visibility (RegionView* rv)
5537 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (rv);
5539 arv->update_envelope_visibility();
5544 Editor::set_gain_envelope_visibility ()
5550 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5551 AudioTimeAxisView* v = dynamic_cast<AudioTimeAxisView*>(*i);
5553 v->audio_view()->foreach_regionview (sigc::mem_fun (this, &Editor::set_region_gain_visibility));
5559 Editor::toggle_gain_envelope_active ()
5561 if (_ignore_region_action) {
5565 RegionSelection rs = get_regions_from_selection_and_entered ();
5567 if (!_session || rs.empty()) {
5571 bool in_command = false;
5573 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5574 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
5576 arv->region()->clear_changes ();
5577 arv->audio_region()->set_envelope_active (!arv->audio_region()->envelope_active());
5580 begin_reversible_command (_("region gain envelope active"));
5583 _session->add_command (new StatefulDiffCommand (arv->region()));
5588 commit_reversible_command ();
5593 Editor::toggle_region_lock ()
5595 if (_ignore_region_action) {
5599 RegionSelection rs = get_regions_from_selection_and_entered ();
5601 if (!_session || rs.empty()) {
5605 begin_reversible_command (_("toggle region lock"));
5607 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5608 (*i)->region()->clear_changes ();
5609 (*i)->region()->set_locked (!(*i)->region()->locked());
5610 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5613 commit_reversible_command ();
5617 Editor::toggle_region_video_lock ()
5619 if (_ignore_region_action) {
5623 RegionSelection rs = get_regions_from_selection_and_entered ();
5625 if (!_session || rs.empty()) {
5629 begin_reversible_command (_("Toggle Video Lock"));
5631 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5632 (*i)->region()->clear_changes ();
5633 (*i)->region()->set_video_locked (!(*i)->region()->video_locked());
5634 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5637 commit_reversible_command ();
5641 Editor::toggle_region_lock_style ()
5643 if (_ignore_region_action) {
5647 RegionSelection rs = get_regions_from_selection_and_entered ();
5649 if (!_session || rs.empty()) {
5653 begin_reversible_command (_("region lock style"));
5655 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5656 (*i)->region()->clear_changes ();
5657 PositionLockStyle const ns = (*i)->region()->position_lock_style() == AudioTime ? MusicTime : AudioTime;
5658 (*i)->region()->set_position_lock_style (ns);
5659 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5662 commit_reversible_command ();
5666 Editor::toggle_opaque_region ()
5668 if (_ignore_region_action) {
5672 RegionSelection rs = get_regions_from_selection_and_entered ();
5674 if (!_session || rs.empty()) {
5678 begin_reversible_command (_("change region opacity"));
5680 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5681 (*i)->region()->clear_changes ();
5682 (*i)->region()->set_opaque (!(*i)->region()->opaque());
5683 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5686 commit_reversible_command ();
5690 Editor::toggle_record_enable ()
5692 bool new_state = false;
5694 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5695 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5698 if (!rtav->is_track())
5702 new_state = !rtav->track()->rec_enable_control()->get_value();
5706 rtav->track()->rec_enable_control()->set_value (new_state, Controllable::UseGroup);
5711 Editor::toggle_solo ()
5713 bool new_state = false;
5715 boost::shared_ptr<ControlList> cl (new ControlList);
5717 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5718 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5725 new_state = !rtav->route()->soloed ();
5729 cl->push_back (rtav->route()->solo_control());
5732 _session->set_controls (cl, new_state ? 1.0 : 0.0, Controllable::UseGroup);
5736 Editor::toggle_mute ()
5738 bool new_state = false;
5740 boost::shared_ptr<RouteList> rl (new RouteList);
5742 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5743 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5750 new_state = !rtav->route()->muted();
5754 rl->push_back (rtav->route());
5757 _session->set_controls (route_list_to_control_list (rl, &Route::mute_control), new_state, Controllable::UseGroup);
5761 Editor::toggle_solo_isolate ()
5767 Editor::fade_range ()
5769 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
5771 begin_reversible_command (_("fade range"));
5773 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
5774 (*i)->fade_range (selection->time);
5777 commit_reversible_command ();
5782 Editor::set_fade_length (bool in)
5784 RegionSelection rs = get_regions_from_selection_and_entered ();
5790 /* we need a region to measure the offset from the start */
5792 RegionView* rv = rs.front ();
5794 framepos_t pos = get_preferred_edit_position();
5798 if (pos > rv->region()->last_frame() || pos < rv->region()->first_frame()) {
5799 /* edit point is outside the relevant region */
5804 if (pos <= rv->region()->position()) {
5808 len = pos - rv->region()->position();
5809 cmd = _("set fade in length");
5811 if (pos >= rv->region()->last_frame()) {
5815 len = rv->region()->last_frame() - pos;
5816 cmd = _("set fade out length");
5819 bool in_command = false;
5821 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5822 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5828 boost::shared_ptr<AutomationList> alist;
5830 alist = tmp->audio_region()->fade_in();
5832 alist = tmp->audio_region()->fade_out();
5835 XMLNode &before = alist->get_state();
5838 tmp->audio_region()->set_fade_in_length (len);
5839 tmp->audio_region()->set_fade_in_active (true);
5841 tmp->audio_region()->set_fade_out_length (len);
5842 tmp->audio_region()->set_fade_out_active (true);
5846 begin_reversible_command (cmd);
5849 XMLNode &after = alist->get_state();
5850 _session->add_command(new MementoCommand<AutomationList>(*alist, &before, &after));
5854 commit_reversible_command ();
5859 Editor::set_fade_in_shape (FadeShape shape)
5861 RegionSelection rs = get_regions_from_selection_and_entered ();
5866 bool in_command = false;
5868 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5869 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5875 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_in();
5876 XMLNode &before = alist->get_state();
5878 tmp->audio_region()->set_fade_in_shape (shape);
5881 begin_reversible_command (_("set fade in shape"));
5884 XMLNode &after = alist->get_state();
5885 _session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
5889 commit_reversible_command ();
5894 Editor::set_fade_out_shape (FadeShape shape)
5896 RegionSelection rs = get_regions_from_selection_and_entered ();
5901 bool in_command = false;
5903 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5904 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5910 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_out();
5911 XMLNode &before = alist->get_state();
5913 tmp->audio_region()->set_fade_out_shape (shape);
5916 begin_reversible_command (_("set fade out shape"));
5919 XMLNode &after = alist->get_state();
5920 _session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
5924 commit_reversible_command ();
5929 Editor::set_fade_in_active (bool yn)
5931 RegionSelection rs = get_regions_from_selection_and_entered ();
5936 bool in_command = false;
5938 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5939 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5946 boost::shared_ptr<AudioRegion> ar (tmp->audio_region());
5948 ar->clear_changes ();
5949 ar->set_fade_in_active (yn);
5952 begin_reversible_command (_("set fade in active"));
5955 _session->add_command (new StatefulDiffCommand (ar));
5959 commit_reversible_command ();
5964 Editor::set_fade_out_active (bool yn)
5966 RegionSelection rs = get_regions_from_selection_and_entered ();
5971 bool in_command = false;
5973 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5974 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5980 boost::shared_ptr<AudioRegion> ar (tmp->audio_region());
5982 ar->clear_changes ();
5983 ar->set_fade_out_active (yn);
5986 begin_reversible_command (_("set fade out active"));
5989 _session->add_command(new StatefulDiffCommand (ar));
5993 commit_reversible_command ();
5998 Editor::toggle_region_fades (int dir)
6000 if (_ignore_region_action) {
6004 boost::shared_ptr<AudioRegion> ar;
6007 RegionSelection rs = get_regions_from_selection_and_entered ();
6013 RegionSelection::iterator i;
6014 for (i = rs.begin(); i != rs.end(); ++i) {
6015 if ((ar = boost::dynamic_pointer_cast<AudioRegion>((*i)->region())) != 0) {
6017 yn = ar->fade_out_active ();
6019 yn = ar->fade_in_active ();
6025 if (i == rs.end()) {
6029 /* XXX should this undo-able? */
6030 bool in_command = false;
6032 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
6033 if ((ar = boost::dynamic_pointer_cast<AudioRegion>((*i)->region())) == 0) {
6036 ar->clear_changes ();
6038 if (dir == 1 || dir == 0) {
6039 ar->set_fade_in_active (!yn);
6042 if (dir == -1 || dir == 0) {
6043 ar->set_fade_out_active (!yn);
6046 begin_reversible_command (_("toggle fade active"));
6049 _session->add_command(new StatefulDiffCommand (ar));
6053 commit_reversible_command ();
6058 /** Update region fade visibility after its configuration has been changed */
6060 Editor::update_region_fade_visibility ()
6062 bool _fade_visibility = _session->config.get_show_region_fades ();
6064 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
6065 AudioTimeAxisView* v = dynamic_cast<AudioTimeAxisView*>(*i);
6067 if (_fade_visibility) {
6068 v->audio_view()->show_all_fades ();
6070 v->audio_view()->hide_all_fades ();
6077 Editor::set_edit_point ()
6082 if (!mouse_frame (where, ignored)) {
6088 if (selection->markers.empty()) {
6090 mouse_add_new_marker (where);
6095 Location* loc = find_location_from_marker (selection->markers.front(), ignored);
6098 loc->move_to (where);
6104 Editor::set_playhead_cursor ()
6106 if (entered_marker) {
6107 _session->request_locate (entered_marker->position(), _session->transport_rolling());
6112 if (!mouse_frame (where, ignored)) {
6119 _session->request_locate (where, _session->transport_rolling());
6123 if (UIConfiguration::instance().get_follow_edits() && (!_session || !_session->config.get_external_sync())) {
6124 cancel_time_selection();
6129 Editor::split_region ()
6131 if (_drags->active ()) {
6135 //if a range is selected, separate it
6136 if ( !selection->time.empty()) {
6137 separate_regions_between (selection->time);
6141 //if no range was selected, try to find some regions to split
6142 if (current_mouse_mode() == MouseObject) { //don't try this for Internal Edit, Stretch, Draw, etc.
6144 RegionSelection rs = get_regions_from_selection_and_edit_point ();
6146 framepos_t where = get_preferred_edit_position ();
6152 split_regions_at (where, rs);
6156 struct EditorOrderRouteSorter {
6157 bool operator() (boost::shared_ptr<Route> a, boost::shared_ptr<Route> b) {
6158 return a->order_key () < b->order_key ();
6163 Editor::select_next_route()
6165 if (selection->tracks.empty()) {
6166 selection->set (track_views.front());
6170 TimeAxisView* current = selection->tracks.front();
6174 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
6175 if (*i == current) {
6177 if (i != track_views.end()) {
6180 current = (*(track_views.begin()));
6181 //selection->set (*(track_views.begin()));
6186 rui = dynamic_cast<RouteUI *>(current);
6187 } while ( current->hidden() || (rui != NULL && !rui->route()->active()));
6189 selection->set(current);
6191 ensure_time_axis_view_is_visible (*current, false);
6195 Editor::select_prev_route()
6197 if (selection->tracks.empty()) {
6198 selection->set (track_views.front());
6202 TimeAxisView* current = selection->tracks.front();
6206 for (TrackViewList::reverse_iterator i = track_views.rbegin(); i != track_views.rend(); ++i) {
6207 if (*i == current) {
6209 if (i != track_views.rend()) {
6212 current = *(track_views.rbegin());
6217 rui = dynamic_cast<RouteUI *>(current);
6218 } while ( current->hidden() || (rui != NULL && !rui->route()->active()));
6220 selection->set (current);
6222 ensure_time_axis_view_is_visible (*current, false);
6226 Editor::set_loop_from_selection (bool play)
6228 if (_session == 0) {
6232 framepos_t start, end;
6233 if (!get_selection_extents ( start, end))
6236 set_loop_range (start, end, _("set loop range from selection"));
6239 _session->request_play_loop (true, true);
6244 Editor::set_loop_from_region (bool play)
6246 framepos_t start, end;
6247 if (!get_selection_extents ( start, end))
6250 set_loop_range (start, end, _("set loop range from region"));
6253 _session->request_locate (start, true);
6254 _session->request_play_loop (true);
6259 Editor::set_punch_from_selection ()
6261 if (_session == 0) {
6265 framepos_t start, end;
6266 if (!get_selection_extents ( start, end))
6269 set_punch_range (start, end, _("set punch range from selection"));
6273 Editor::set_session_extents_from_selection ()
6275 if (_session == 0) {
6279 framepos_t start, end;
6280 if (!get_selection_extents ( start, end))
6284 if ((loc = _session->locations()->session_range_location()) == 0) {
6285 _session->set_session_extents ( start, end ); // this will create a new session range; no need for UNDO
6287 XMLNode &before = loc->get_state();
6289 _session->set_session_extents ( start, end );
6291 XMLNode &after = loc->get_state();
6293 begin_reversible_command (_("set session start/end from selection"));
6295 _session->add_command (new MementoCommand<Location>(*loc, &before, &after));
6297 commit_reversible_command ();
6302 Editor::set_punch_start_from_edit_point ()
6306 framepos_t start = 0;
6307 framepos_t end = max_framepos;
6309 //use the existing punch end, if any
6310 Location* tpl = transport_punch_location();
6315 if ((_edit_point == EditAtPlayhead) && _session->transport_rolling()) {
6316 start = _session->audible_frame();
6318 start = get_preferred_edit_position();
6321 //snap the selection start/end
6324 //if there's not already a sensible selection endpoint, go "forever"
6325 if ( start > end ) {
6329 set_punch_range (start, end, _("set punch start from EP"));
6335 Editor::set_punch_end_from_edit_point ()
6339 framepos_t start = 0;
6340 framepos_t end = max_framepos;
6342 //use the existing punch start, if any
6343 Location* tpl = transport_punch_location();
6345 start = tpl->start();
6348 if ((_edit_point == EditAtPlayhead) && _session->transport_rolling()) {
6349 end = _session->audible_frame();
6351 end = get_preferred_edit_position();
6354 //snap the selection start/end
6357 set_punch_range (start, end, _("set punch end from EP"));
6363 Editor::set_loop_start_from_edit_point ()
6367 framepos_t start = 0;
6368 framepos_t end = max_framepos;
6370 //use the existing loop end, if any
6371 Location* tpl = transport_loop_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_loop_range (start, end, _("set loop start from EP"));
6396 Editor::set_loop_end_from_edit_point ()
6400 framepos_t start = 0;
6401 framepos_t end = max_framepos;
6403 //use the existing loop start, if any
6404 Location* tpl = transport_loop_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_loop_range (start, end, _("set loop end from EP"));
6423 Editor::set_punch_from_region ()
6425 framepos_t start, end;
6426 if (!get_selection_extents ( start, end))
6429 set_punch_range (start, end, _("set punch range from region"));
6433 Editor::pitch_shift_region ()
6435 RegionSelection rs = get_regions_from_selection_and_entered ();
6437 RegionSelection audio_rs;
6438 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
6439 if (dynamic_cast<AudioRegionView*> (*i)) {
6440 audio_rs.push_back (*i);
6444 if (audio_rs.empty()) {
6448 pitch_shift (audio_rs, 1.2);
6452 Editor::set_tempo_from_region ()
6454 RegionSelection rs = get_regions_from_selection_and_entered ();
6456 if (!_session || rs.empty()) {
6460 RegionView* rv = rs.front();
6462 define_one_bar (rv->region()->position(), rv->region()->last_frame() + 1);
6466 Editor::use_range_as_bar ()
6468 framepos_t start, end;
6469 if (get_edit_op_range (start, end)) {
6470 define_one_bar (start, end);
6475 Editor::define_one_bar (framepos_t start, framepos_t end)
6477 framepos_t length = end - start;
6479 const Meter& m (_session->tempo_map().meter_at_frame (start));
6481 /* length = 1 bar */
6483 /* We're going to deliver a constant tempo here,
6484 so we can use frames per beat to determine length.
6485 now we want frames per beat.
6486 we have frames per bar, and beats per bar, so ...
6489 /* XXXX METER MATH */
6491 double frames_per_beat = length / m.divisions_per_bar();
6493 /* beats per minute = */
6495 double beats_per_minute = (_session->frame_rate() * 60.0) / frames_per_beat;
6497 /* now decide whether to:
6499 (a) set global tempo
6500 (b) add a new tempo marker
6504 const TempoSection& t (_session->tempo_map().tempo_section_at_frame (start));
6506 bool do_global = false;
6508 if ((_session->tempo_map().n_tempos() == 1) && (_session->tempo_map().n_meters() == 1)) {
6510 /* only 1 tempo & 1 meter: ask if the user wants to set the tempo
6511 at the start, or create a new marker
6514 vector<string> options;
6515 options.push_back (_("Cancel"));
6516 options.push_back (_("Add new marker"));
6517 options.push_back (_("Set global tempo"));
6520 _("Define one bar"),
6521 _("Do you want to set the global tempo or add a new tempo marker?"),
6525 c.set_default_response (2);
6541 /* more than 1 tempo and/or meter section already, go ahead do the "usual":
6542 if the marker is at the region starter, change it, otherwise add
6547 begin_reversible_command (_("set tempo from region"));
6548 XMLNode& before (_session->tempo_map().get_state());
6551 _session->tempo_map().change_initial_tempo (beats_per_minute, t.note_type());
6552 } else if (t.frame() == start) {
6553 _session->tempo_map().change_existing_tempo_at (start, beats_per_minute, t.note_type());
6555 _session->tempo_map().add_tempo (Tempo (beats_per_minute, t.note_type()), 0.0, start, TempoSection::Constant, AudioTime);
6558 XMLNode& after (_session->tempo_map().get_state());
6560 _session->add_command (new MementoCommand<TempoMap>(_session->tempo_map(), &before, &after));
6561 commit_reversible_command ();
6565 Editor::split_region_at_transients ()
6567 AnalysisFeatureList positions;
6569 RegionSelection rs = get_regions_from_selection_and_entered ();
6571 if (!_session || rs.empty()) {
6575 begin_reversible_command (_("split regions"));
6577 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ) {
6579 RegionSelection::iterator tmp;
6584 boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion> ((*i)->region());
6587 ar->transients (positions);
6588 split_region_at_points ((*i)->region(), positions, true);
6595 commit_reversible_command ();
6600 Editor::split_region_at_points (boost::shared_ptr<Region> r, AnalysisFeatureList& positions, bool can_ferret, bool select_new)
6602 bool use_rhythmic_rodent = false;
6604 boost::shared_ptr<Playlist> pl = r->playlist();
6606 list<boost::shared_ptr<Region> > new_regions;
6612 if (positions.empty()) {
6616 if (positions.size() > 20 && can_ferret) {
6617 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);
6618 MessageDialog msg (msgstr,
6621 Gtk::BUTTONS_OK_CANCEL);
6624 msg.add_button (_("Call for the Ferret!"), RESPONSE_APPLY);
6625 msg.set_secondary_text (_("Press OK to continue with this split operation\nor ask the Ferret dialog to tune the analysis"));
6627 msg.set_secondary_text (_("Press OK to continue with this split operation"));
6630 msg.set_title (_("Excessive split?"));
6633 int response = msg.run();
6639 case RESPONSE_APPLY:
6640 use_rhythmic_rodent = true;
6647 if (use_rhythmic_rodent) {
6648 show_rhythm_ferret ();
6652 AnalysisFeatureList::const_iterator x;
6654 pl->clear_changes ();
6655 pl->clear_owned_changes ();
6657 x = positions.begin();
6659 if (x == positions.end()) {
6664 pl->remove_region (r);
6668 framepos_t rstart = r->first_frame ();
6669 framepos_t rend = r->last_frame ();
6671 while (x != positions.end()) {
6673 /* deal with positons that are out of scope of present region bounds */
6674 if (*x <= rstart || *x > rend) {
6679 /* file start = original start + how far we from the initial position ? */
6681 framepos_t file_start = r->start() + pos;
6683 /* length = next position - current position */
6685 framepos_t len = (*x) - pos - rstart;
6687 /* XXX we do we really want to allow even single-sample regions?
6688 * shouldn't we have some kind of lower limit on region size?
6697 if (RegionFactory::region_name (new_name, r->name())) {
6701 /* do NOT announce new regions 1 by one, just wait till they are all done */
6705 plist.add (ARDOUR::Properties::start, file_start);
6706 plist.add (ARDOUR::Properties::length, len);
6707 plist.add (ARDOUR::Properties::name, new_name);
6708 plist.add (ARDOUR::Properties::layer, 0);
6709 // TODO set transients_offset
6711 boost::shared_ptr<Region> nr = RegionFactory::create (r->sources(), plist, false);
6712 /* because we set annouce to false, manually add the new region to the
6715 RegionFactory::map_add (nr);
6717 pl->add_region (nr, rstart + pos);
6720 new_regions.push_front(nr);
6729 RegionFactory::region_name (new_name, r->name());
6731 /* Add the final region */
6734 plist.add (ARDOUR::Properties::start, r->start() + pos);
6735 plist.add (ARDOUR::Properties::length, r->last_frame() - (r->position() + pos) + 1);
6736 plist.add (ARDOUR::Properties::name, new_name);
6737 plist.add (ARDOUR::Properties::layer, 0);
6739 boost::shared_ptr<Region> nr = RegionFactory::create (r->sources(), plist, false);
6740 /* because we set annouce to false, manually add the new region to the
6743 RegionFactory::map_add (nr);
6744 pl->add_region (nr, r->position() + pos);
6747 new_regions.push_front(nr);
6752 /* We might have removed regions, which alters other regions' layering_index,
6753 so we need to do a recursive diff here.
6755 vector<Command*> cmds;
6757 _session->add_commands (cmds);
6759 _session->add_command (new StatefulDiffCommand (pl));
6763 for (list<boost::shared_ptr<Region> >::iterator i = new_regions.begin(); i != new_regions.end(); ++i){
6764 set_selected_regionview_from_region_list ((*i), Selection::Add);
6770 Editor::place_transient()
6776 RegionSelection rs = get_regions_from_selection_and_edit_point ();
6782 framepos_t where = get_preferred_edit_position();
6784 begin_reversible_command (_("place transient"));
6786 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6787 (*r)->region()->add_transient(where);
6790 commit_reversible_command ();
6794 Editor::remove_transient(ArdourCanvas::Item* item)
6800 ArdourCanvas::Line* _line = reinterpret_cast<ArdourCanvas::Line*> (item);
6803 AudioRegionView* _arv = reinterpret_cast<AudioRegionView*> (item->get_data ("regionview"));
6804 _arv->remove_transient (*(float*) _line->get_data ("position"));
6808 Editor::snap_regions_to_grid ()
6810 list <boost::shared_ptr<Playlist > > used_playlists;
6812 RegionSelection rs = get_regions_from_selection_and_entered ();
6814 if (!_session || rs.empty()) {
6818 begin_reversible_command (_("snap regions to grid"));
6820 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6822 boost::shared_ptr<Playlist> pl = (*r)->region()->playlist();
6824 if (!pl->frozen()) {
6825 /* we haven't seen this playlist before */
6827 /* remember used playlists so we can thaw them later */
6828 used_playlists.push_back(pl);
6832 framepos_t start_frame = (*r)->region()->first_frame ();
6833 snap_to (start_frame);
6834 (*r)->region()->set_position (start_frame);
6837 while (used_playlists.size() > 0) {
6838 list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
6840 used_playlists.pop_front();
6843 commit_reversible_command ();
6847 Editor::close_region_gaps ()
6849 list <boost::shared_ptr<Playlist > > used_playlists;
6851 RegionSelection rs = get_regions_from_selection_and_entered ();
6853 if (!_session || rs.empty()) {
6857 Dialog dialog (_("Close Region Gaps"));
6860 table.set_spacings (12);
6861 table.set_border_width (12);
6862 Label* l = manage (left_aligned_label (_("Crossfade length")));
6863 table.attach (*l, 0, 1, 0, 1);
6865 SpinButton spin_crossfade (1, 0);
6866 spin_crossfade.set_range (0, 15);
6867 spin_crossfade.set_increments (1, 1);
6868 spin_crossfade.set_value (5);
6869 table.attach (spin_crossfade, 1, 2, 0, 1);
6871 table.attach (*manage (new Label (_("ms"))), 2, 3, 0, 1);
6873 l = manage (left_aligned_label (_("Pull-back length")));
6874 table.attach (*l, 0, 1, 1, 2);
6876 SpinButton spin_pullback (1, 0);
6877 spin_pullback.set_range (0, 100);
6878 spin_pullback.set_increments (1, 1);
6879 spin_pullback.set_value(30);
6880 table.attach (spin_pullback, 1, 2, 1, 2);
6882 table.attach (*manage (new Label (_("ms"))), 2, 3, 1, 2);
6884 dialog.get_vbox()->pack_start (table);
6885 dialog.add_button (Stock::CANCEL, RESPONSE_CANCEL);
6886 dialog.add_button (_("Ok"), RESPONSE_ACCEPT);
6889 if (dialog.run () == RESPONSE_CANCEL) {
6893 framepos_t crossfade_len = spin_crossfade.get_value();
6894 framepos_t pull_back_frames = spin_pullback.get_value();
6896 crossfade_len = lrintf (crossfade_len * _session->frame_rate()/1000);
6897 pull_back_frames = lrintf (pull_back_frames * _session->frame_rate()/1000);
6899 /* Iterate over the region list and make adjacent regions overlap by crossfade_len_ms */
6901 begin_reversible_command (_("close region gaps"));
6904 boost::shared_ptr<Region> last_region;
6906 rs.sort_by_position_and_track();
6908 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6910 boost::shared_ptr<Playlist> pl = (*r)->region()->playlist();
6912 if (!pl->frozen()) {
6913 /* we haven't seen this playlist before */
6915 /* remember used playlists so we can thaw them later */
6916 used_playlists.push_back(pl);
6920 framepos_t position = (*r)->region()->position();
6922 if (idx == 0 || position < last_region->position()){
6923 last_region = (*r)->region();
6928 (*r)->region()->trim_front( (position - pull_back_frames));
6929 last_region->trim_end( (position - pull_back_frames + crossfade_len));
6931 last_region = (*r)->region();
6936 while (used_playlists.size() > 0) {
6937 list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
6939 used_playlists.pop_front();
6942 commit_reversible_command ();
6946 Editor::tab_to_transient (bool forward)
6948 AnalysisFeatureList positions;
6950 RegionSelection rs = get_regions_from_selection_and_entered ();
6956 framepos_t pos = _session->audible_frame ();
6958 if (!selection->tracks.empty()) {
6960 /* don't waste time searching for transients in duplicate playlists.
6963 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
6965 for (TrackViewList::iterator t = ts.begin(); t != ts.end(); ++t) {
6967 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*t);
6970 boost::shared_ptr<Track> tr = rtv->track();
6972 boost::shared_ptr<Playlist> pl = tr->playlist ();
6974 framepos_t result = pl->find_next_transient (pos, forward ? 1 : -1);
6977 positions.push_back (result);
6990 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6991 (*r)->region()->get_transients (positions);
6995 TransientDetector::cleanup_transients (positions, _session->frame_rate(), 3.0);
6998 AnalysisFeatureList::iterator x;
7000 for (x = positions.begin(); x != positions.end(); ++x) {
7006 if (x != positions.end ()) {
7007 _session->request_locate (*x);
7011 AnalysisFeatureList::reverse_iterator x;
7013 for (x = positions.rbegin(); x != positions.rend(); ++x) {
7019 if (x != positions.rend ()) {
7020 _session->request_locate (*x);
7026 Editor::playhead_forward_to_grid ()
7032 framepos_t pos = playhead_cursor->current_frame ();
7033 if (pos < max_framepos - 1) {
7035 snap_to_internal (pos, RoundUpAlways, false);
7036 _session->request_locate (pos);
7042 Editor::playhead_backward_to_grid ()
7048 framepos_t pos = playhead_cursor->current_frame ();
7051 snap_to_internal (pos, RoundDownAlways, false);
7052 _session->request_locate (pos);
7057 Editor::set_track_height (Height h)
7059 TrackSelection& ts (selection->tracks);
7061 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
7062 (*x)->set_height_enum (h);
7067 Editor::toggle_tracks_active ()
7069 TrackSelection& ts (selection->tracks);
7071 bool target = false;
7077 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
7078 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*x);
7082 target = !rtv->_route->active();
7085 rtv->_route->set_active (target, this);
7091 Editor::remove_tracks ()
7093 /* this will delete GUI objects that may be the subject of an event
7094 handler in which this method is called. Defer actual deletion to the
7095 next idle callback, when all event handling is finished.
7097 Glib::signal_idle().connect (sigc::mem_fun (*this, &Editor::idle_remove_tracks));
7101 Editor::idle_remove_tracks ()
7103 Session::StateProtector sp (_session);
7105 return false; /* do not call again */
7109 Editor::_remove_tracks ()
7111 TrackSelection& ts (selection->tracks);
7117 vector<string> choices;
7121 const char* trackstr;
7123 vector<boost::shared_ptr<Route> > routes;
7124 bool special_bus = false;
7126 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
7127 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*x);
7131 if (rtv->is_track()) {
7136 routes.push_back (rtv->_route);
7138 if (rtv->route()->is_master() || rtv->route()->is_monitor()) {
7143 if (special_bus && !Config->get_allow_special_bus_removal()) {
7144 MessageDialog msg (_("That would be bad news ...."),
7148 msg.set_secondary_text (string_compose (_(
7149 "Removing the master or monitor bus is such a bad idea\n\
7150 that %1 is not going to allow it.\n\
7152 If you really want to do this sort of thing\n\
7153 edit your ardour.rc file to set the\n\
7154 \"allow-special-bus-removal\" option to be \"yes\""), PROGRAM_NAME));
7161 if (ntracks + nbusses == 0) {
7165 trackstr = P_("track", "tracks", ntracks);
7166 busstr = P_("bus", "busses", nbusses);
7170 prompt = string_compose (_("Do you really want to remove %1 %2 and %3 %4?\n"
7171 "(You may also lose the playlists associated with the %2)\n\n"
7172 "This action cannot be undone, and the session file will be overwritten!"),
7173 ntracks, trackstr, nbusses, busstr);
7175 prompt = string_compose (_("Do you really want to remove %1 %2?\n"
7176 "(You may also lose the playlists associated with the %2)\n\n"
7177 "This action cannot be undone, and the session file will be overwritten!"),
7180 } else if (nbusses) {
7181 prompt = string_compose (_("Do you really want to remove %1 %2?\n\n"
7182 "This action cannot be undone, and the session file will be overwritten"),
7186 choices.push_back (_("No, do nothing."));
7187 if (ntracks + nbusses > 1) {
7188 choices.push_back (_("Yes, remove them."));
7190 choices.push_back (_("Yes, remove it."));
7195 title = string_compose (_("Remove %1"), trackstr);
7197 title = string_compose (_("Remove %1"), busstr);
7200 Choice prompter (title, prompt, choices);
7202 if (prompter.run () != 1) {
7207 DisplaySuspender ds;
7208 boost::shared_ptr<RouteList> rl (new RouteList);
7209 for (vector<boost::shared_ptr<Route> >::iterator x = routes.begin(); x != routes.end(); ++x) {
7212 _session->remove_routes (rl);
7214 /* TrackSelection and RouteList leave scope,
7215 * destructors are called,
7216 * diskstream drops references, save_state is called (again for every track)
7221 Editor::do_insert_time ()
7223 if (selection->tracks.empty()) {
7227 InsertRemoveTimeDialog d (*this);
7228 int response = d.run ();
7230 if (response != RESPONSE_OK) {
7234 if (d.distance() == 0) {
7239 get_preferred_edit_position (EDIT_IGNORE_MOUSE),
7241 d.intersected_region_action (),
7245 d.move_glued_markers(),
7246 d.move_locked_markers(),
7252 Editor::insert_time (
7253 framepos_t pos, framecnt_t frames, InsertTimeOption opt,
7254 bool all_playlists, bool ignore_music_glue, bool markers_too, bool glued_markers_too, bool locked_markers_too, bool tempo_too
7258 if (Config->get_edit_mode() == Lock) {
7261 bool in_command = false;
7263 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
7265 for (TrackViewList::iterator x = ts.begin(); x != ts.end(); ++x) {
7269 /* don't operate on any playlist more than once, which could
7270 * happen if "all playlists" is enabled, but there is more
7271 * than 1 track using playlists "from" a given track.
7274 set<boost::shared_ptr<Playlist> > pl;
7276 if (all_playlists) {
7277 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*x);
7278 if (rtav && rtav->track ()) {
7279 vector<boost::shared_ptr<Playlist> > all = _session->playlists->playlists_for_track (rtav->track ());
7280 for (vector<boost::shared_ptr<Playlist> >::iterator p = all.begin(); p != all.end(); ++p) {
7285 if ((*x)->playlist ()) {
7286 pl.insert ((*x)->playlist ());
7290 for (set<boost::shared_ptr<Playlist> >::iterator i = pl.begin(); i != pl.end(); ++i) {
7292 (*i)->clear_changes ();
7293 (*i)->clear_owned_changes ();
7295 if (opt == SplitIntersected) {
7299 (*i)->shift (pos, frames, (opt == MoveIntersected), ignore_music_glue);
7302 begin_reversible_command (_("insert time"));
7305 vector<Command*> cmds;
7307 _session->add_commands (cmds);
7309 _session->add_command (new StatefulDiffCommand (*i));
7313 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*x);
7316 begin_reversible_command (_("insert time"));
7319 rtav->route ()->shift (pos, frames);
7326 XMLNode& before (_session->locations()->get_state());
7327 Locations::LocationList copy (_session->locations()->list());
7329 for (Locations::LocationList::iterator i = copy.begin(); i != copy.end(); ++i) {
7331 Locations::LocationList::const_iterator tmp;
7333 if ((*i)->position_lock_style() == AudioTime || glued_markers_too) {
7334 bool const was_locked = (*i)->locked ();
7335 if (locked_markers_too) {
7339 if ((*i)->start() >= pos) {
7340 // move end first, in case we're moving by more than the length of the range
7341 if (!(*i)->is_mark()) {
7342 (*i)->set_end ((*i)->end() + frames);
7344 (*i)->set_start ((*i)->start() + frames);
7356 begin_reversible_command (_("insert time"));
7359 XMLNode& after (_session->locations()->get_state());
7360 _session->add_command (new MementoCommand<Locations>(*_session->locations(), &before, &after));
7366 begin_reversible_command (_("insert time"));
7369 XMLNode& before (_session->tempo_map().get_state());
7370 _session->tempo_map().insert_time (pos, frames);
7371 XMLNode& after (_session->tempo_map().get_state());
7372 _session->add_command (new MementoCommand<TempoMap>(_session->tempo_map(), &before, &after));
7376 commit_reversible_command ();
7381 Editor::do_remove_time ()
7383 if (selection->tracks.empty()) {
7387 framepos_t pos = get_preferred_edit_position (EDIT_IGNORE_MOUSE);
7388 InsertRemoveTimeDialog d (*this, true);
7390 int response = d.run ();
7392 if (response != RESPONSE_OK) {
7396 framecnt_t distance = d.distance();
7398 if (distance == 0) {
7408 d.move_glued_markers(),
7409 d.move_locked_markers(),
7415 Editor::remove_time (framepos_t pos, framecnt_t frames, InsertTimeOption opt,
7416 bool ignore_music_glue, bool markers_too, bool glued_markers_too, bool locked_markers_too, bool tempo_too)
7418 if (Config->get_edit_mode() == Lock) {
7419 error << (_("Cannot insert or delete time when in Lock edit.")) << endmsg;
7422 bool in_command = false;
7424 for (TrackSelection::iterator x = selection->tracks.begin(); x != selection->tracks.end(); ++x) {
7426 boost::shared_ptr<Playlist> pl = (*x)->playlist();
7430 XMLNode &before = pl->get_state();
7432 std::list<AudioRange> rl;
7433 AudioRange ar(pos, pos+frames, 0);
7436 pl->shift (pos, -frames, true, ignore_music_glue);
7439 begin_reversible_command (_("remove time"));
7442 XMLNode &after = pl->get_state();
7444 _session->add_command (new MementoCommand<Playlist> (*pl, &before, &after));
7448 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*x);
7451 begin_reversible_command (_("remove time"));
7454 rtav->route ()->shift (pos, -frames);
7458 std::list<Location*> loc_kill_list;
7463 XMLNode& before (_session->locations()->get_state());
7464 Locations::LocationList copy (_session->locations()->list());
7466 for (Locations::LocationList::iterator i = copy.begin(); i != copy.end(); ++i) {
7467 if ((*i)->position_lock_style() == AudioTime || glued_markers_too) {
7469 bool const was_locked = (*i)->locked ();
7470 if (locked_markers_too) {
7474 if (!(*i)->is_mark()) { // it's a range; have to handle both start and end
7475 if ((*i)->end() >= pos
7476 && (*i)->end() < pos+frames
7477 && (*i)->start() >= pos
7478 && (*i)->end() < pos+frames) { // range is completely enclosed; kill it
7480 loc_kill_list.push_back(*i);
7481 } else { // only start or end is included, try to do the right thing
7482 // move start before moving end, to avoid trying to move the end to before the start
7483 // if we're removing more time than the length of the range
7484 if ((*i)->start() >= pos && (*i)->start() < pos+frames) {
7485 // start is within cut
7486 (*i)->set_start (pos); // bring the start marker to the beginning of the cut
7488 } else if ((*i)->start() >= pos+frames) {
7489 // start (and thus entire range) lies beyond end of cut
7490 (*i)->set_start ((*i)->start() - frames); // slip the start marker back
7493 if ((*i)->end() >= pos && (*i)->end() < pos+frames) {
7494 // end is inside cut
7495 (*i)->set_end (pos); // bring the end to the cut
7497 } else if ((*i)->end() >= pos+frames) {
7498 // end is beyond end of cut
7499 (*i)->set_end ((*i)->end() - frames); // slip the end marker back
7504 } else if ((*i)->start() >= pos && (*i)->start() < pos+frames ) {
7505 loc_kill_list.push_back(*i);
7507 } else if ((*i)->start() >= pos) {
7508 (*i)->set_start ((*i)->start() -frames);
7518 for (list<Location*>::iterator i = loc_kill_list.begin(); i != loc_kill_list.end(); ++i) {
7519 _session->locations()->remove( *i );
7524 begin_reversible_command (_("remove time"));
7527 XMLNode& after (_session->locations()->get_state());
7528 _session->add_command (new MementoCommand<Locations>(*_session->locations(), &before, &after));
7533 XMLNode& before (_session->tempo_map().get_state());
7535 if (_session->tempo_map().remove_time (pos, frames) ) {
7537 begin_reversible_command (_("remove time"));
7540 XMLNode& after (_session->tempo_map().get_state());
7541 _session->add_command (new MementoCommand<TempoMap>(_session->tempo_map(), &before, &after));
7546 commit_reversible_command ();
7551 Editor::fit_selection ()
7553 if (!selection->tracks.empty()) {
7554 fit_tracks (selection->tracks);
7558 /* no selected tracks - use tracks with selected regions */
7560 if (!selection->regions.empty()) {
7561 for (RegionSelection::iterator r = selection->regions.begin(); r != selection->regions.end(); ++r) {
7562 tvl.push_back (&(*r)->get_time_axis_view ());
7568 } else if (internal_editing()) {
7569 /* no selected tracks, or regions, but in internal edit mode, so follow the mouse and use
7572 if (entered_track) {
7573 tvl.push_back (entered_track);
7582 Editor::fit_tracks (TrackViewList & tracks)
7584 if (tracks.empty()) {
7588 uint32_t child_heights = 0;
7589 int visible_tracks = 0;
7591 for (TrackSelection::iterator t = tracks.begin(); t != tracks.end(); ++t) {
7593 if (!(*t)->marked_for_display()) {
7597 child_heights += (*t)->effective_height() - (*t)->current_height();
7601 /* compute the per-track height from:
7603 total canvas visible height -
7604 height that will be taken by visible children of selected
7605 tracks - height of the ruler/hscroll area
7607 uint32_t h = (uint32_t) floor ((trackviews_height() - child_heights) / visible_tracks);
7608 double first_y_pos = DBL_MAX;
7610 if (h < TimeAxisView::preset_height (HeightSmall)) {
7611 MessageDialog msg (_("There are too many tracks to fit in the current window"));
7612 /* too small to be displayed */
7616 undo_visual_stack.push_back (current_visual_state (true));
7617 PBD::Unwinder<bool> nsv (no_save_visual, true);
7619 /* build a list of all tracks, including children */
7622 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
7624 TimeAxisView::Children c = (*i)->get_child_list ();
7625 for (TimeAxisView::Children::iterator j = c.begin(); j != c.end(); ++j) {
7626 all.push_back (j->get());
7631 // find selection range.
7632 // if someone knows how to user TrackViewList::iterator for this
7634 int selected_top = -1;
7635 int selected_bottom = -1;
7637 for (TrackViewList::iterator t = all.begin(); t != all.end(); ++t, ++i) {
7638 if ((*t)->marked_for_display ()) {
7639 if (tracks.contains(*t)) {
7640 if (selected_top == -1) {
7643 selected_bottom = i;
7649 for (TrackViewList::iterator t = all.begin(); t != all.end(); ++t, ++i) {
7650 if ((*t)->marked_for_display ()) {
7651 if (tracks.contains(*t)) {
7652 (*t)->set_height (h);
7653 first_y_pos = std::min ((*t)->y_position (), first_y_pos);
7655 if (i > selected_top && i < selected_bottom) {
7656 hide_track_in_display (*t);
7663 set the controls_layout height now, because waiting for its size
7664 request signal handler will cause the vertical adjustment setting to fail
7667 controls_layout.property_height () = _full_canvas_height;
7668 vertical_adjustment.set_value (first_y_pos);
7670 redo_visual_stack.push_back (current_visual_state (true));
7672 visible_tracks_selector.set_text (_("Sel"));
7676 Editor::save_visual_state (uint32_t n)
7678 while (visual_states.size() <= n) {
7679 visual_states.push_back (0);
7682 if (visual_states[n] != 0) {
7683 delete visual_states[n];
7686 visual_states[n] = current_visual_state (true);
7691 Editor::goto_visual_state (uint32_t n)
7693 if (visual_states.size() <= n) {
7697 if (visual_states[n] == 0) {
7701 use_visual_state (*visual_states[n]);
7705 Editor::start_visual_state_op (uint32_t n)
7707 save_visual_state (n);
7709 PopUp* pup = new PopUp (WIN_POS_MOUSE, 1000, true);
7711 snprintf (buf, sizeof (buf), _("Saved view %u"), n+1);
7712 pup->set_text (buf);
7717 Editor::cancel_visual_state_op (uint32_t n)
7719 goto_visual_state (n);
7723 Editor::toggle_region_mute ()
7725 if (_ignore_region_action) {
7729 RegionSelection rs = get_regions_from_selection_and_entered ();
7735 if (rs.size() > 1) {
7736 begin_reversible_command (_("mute regions"));
7738 begin_reversible_command (_("mute region"));
7741 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
7743 (*i)->region()->playlist()->clear_changes ();
7744 (*i)->region()->set_muted (!(*i)->region()->muted ());
7745 _session->add_command (new StatefulDiffCommand ((*i)->region()));
7749 commit_reversible_command ();
7753 Editor::combine_regions ()
7755 /* foreach track with selected regions, take all selected regions
7756 and join them into a new region containing the subregions (as a
7760 typedef set<RouteTimeAxisView*> RTVS;
7763 if (selection->regions.empty()) {
7767 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
7768 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(&(*i)->get_time_axis_view());
7771 tracks.insert (rtv);
7775 begin_reversible_command (_("combine regions"));
7777 vector<RegionView*> new_selection;
7779 for (RTVS::iterator i = tracks.begin(); i != tracks.end(); ++i) {
7782 if ((rv = (*i)->combine_regions ()) != 0) {
7783 new_selection.push_back (rv);
7787 selection->clear_regions ();
7788 for (vector<RegionView*>::iterator i = new_selection.begin(); i != new_selection.end(); ++i) {
7789 selection->add (*i);
7792 commit_reversible_command ();
7796 Editor::uncombine_regions ()
7798 typedef set<RouteTimeAxisView*> RTVS;
7801 if (selection->regions.empty()) {
7805 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
7806 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(&(*i)->get_time_axis_view());
7809 tracks.insert (rtv);
7813 begin_reversible_command (_("uncombine regions"));
7815 for (RTVS::iterator i = tracks.begin(); i != tracks.end(); ++i) {
7816 (*i)->uncombine_regions ();
7819 commit_reversible_command ();
7823 Editor::toggle_midi_input_active (bool flip_others)
7826 boost::shared_ptr<RouteList> rl (new RouteList);
7828 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
7829 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
7835 boost::shared_ptr<MidiTrack> mt = rtav->midi_track();
7838 rl->push_back (rtav->route());
7839 onoff = !mt->input_active();
7843 _session->set_exclusive_input_active (rl, onoff, flip_others);
7850 lock_dialog = new Gtk::Dialog (string_compose (_("%1: Locked"), PROGRAM_NAME), true);
7852 Gtk::Image* padlock = manage (new Gtk::Image (ARDOUR_UI_UTILS::get_icon ("padlock_closed")));
7853 lock_dialog->get_vbox()->pack_start (*padlock);
7855 ArdourButton* b = manage (new ArdourButton);
7856 b->set_name ("lock button");
7857 b->set_text (_("Click to unlock"));
7858 b->signal_clicked.connect (sigc::mem_fun (*this, &Editor::unlock));
7859 lock_dialog->get_vbox()->pack_start (*b);
7861 lock_dialog->get_vbox()->show_all ();
7862 lock_dialog->set_size_request (200, 200);
7865 delete _main_menu_disabler;
7866 _main_menu_disabler = new MainMenuDisabler;
7868 lock_dialog->present ();
7874 lock_dialog->hide ();
7876 delete _main_menu_disabler;
7877 _main_menu_disabler = 0;
7879 if (UIConfiguration::instance().get_lock_gui_after_seconds()) {
7880 start_lock_event_timing ();
7885 Editor::bring_in_callback (Gtk::Label* label, uint32_t n, uint32_t total, string name)
7887 Gtkmm2ext::UI::instance()->call_slot (invalidator (*this), boost::bind (&Editor::update_bring_in_message, this, label, n, total, name));
7891 Editor::update_bring_in_message (Gtk::Label* label, uint32_t n, uint32_t total, string name)
7893 Timers::TimerSuspender t;
7894 label->set_text (string_compose ("Copying %1, %2 of %3", name, n, total));
7895 Gtkmm2ext::UI::instance()->flush_pending ();
7899 Editor::bring_all_sources_into_session ()
7906 ArdourDialog w (_("Moving embedded files into session folder"));
7907 w.get_vbox()->pack_start (msg);
7910 /* flush all pending GUI events because we're about to start copying
7914 Timers::TimerSuspender t;
7915 Gtkmm2ext::UI::instance()->flush_pending ();
7919 _session->bring_all_sources_into_session (boost::bind (&Editor::bring_in_callback, this, &msg, _1, _2, _3));