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, const int32_t& sub_num)
158 RegionSelection pre_selected_regions = selection->regions;
159 bool working_on_selection = !pre_selected_regions.empty();
161 list<boost::shared_ptr<Playlist> > used_playlists;
162 list<RouteTimeAxisView*> used_trackviews;
164 if (regions.empty()) {
168 begin_reversible_command (_("split"));
170 // if splitting a single region, and snap-to is using
171 // region boundaries, don't pay attention to them
173 if (regions.size() == 1) {
174 switch (_snap_type) {
175 case SnapToRegionStart:
176 case SnapToRegionSync:
177 case SnapToRegionEnd:
186 EditorFreeze(); /* Emit Signal */
189 for (RegionSelection::iterator a = regions.begin(); a != regions.end(); ) {
191 RegionSelection::iterator tmp;
193 /* XXX this test needs to be more complicated, to make sure we really
194 have something to split.
197 if (!(*a)->region()->covers (where)) {
205 boost::shared_ptr<Playlist> pl = (*a)->region()->playlist();
213 /* we haven't seen this playlist before */
215 /* remember used playlists so we can thaw them later */
216 used_playlists.push_back(pl);
218 TimeAxisView& tv = (*a)->get_time_axis_view();
219 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (&tv);
221 used_trackviews.push_back (rtv);
228 pl->clear_changes ();
229 pl->split_region ((*a)->region(), where, sub_num);
230 _session->add_command (new StatefulDiffCommand (pl));
236 latest_regionviews.clear ();
238 vector<sigc::connection> region_added_connections;
240 for (list<RouteTimeAxisView*>::iterator i = used_trackviews.begin(); i != used_trackviews.end(); ++i) {
241 region_added_connections.push_back ((*i)->view()->RegionViewAdded.connect (sigc::mem_fun(*this, &Editor::collect_new_region_view)));
244 while (used_playlists.size() > 0) {
245 list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
247 used_playlists.pop_front();
250 for (vector<sigc::connection>::iterator c = region_added_connections.begin(); c != region_added_connections.end(); ++c) {
255 EditorThaw(); /* Emit Signal */
258 if (working_on_selection) {
259 // IFF we were working on selected regions, try to reinstate the other region selections that existed before the freeze/thaw.
261 _ignore_follow_edits = true; // a split will change the region selection in mysterious ways; it's not practical or wanted to follow this edit
262 RegionSelectionAfterSplit rsas = Config->get_region_selection_after_split();
263 /* There are three classes of regions that we might want selected after
264 splitting selected regions:
265 - regions selected before the split operation, and unaffected by it
266 - newly-created regions before the split
267 - newly-created regions after the split
270 if (rsas & Existing) {
271 // region selections that existed before the split.
272 selection->add ( pre_selected_regions );
275 for (RegionSelection::iterator ri = latest_regionviews.begin(); ri != latest_regionviews.end(); ri++) {
276 if ((*ri)->region()->position() < where) {
277 // new regions created before the split
278 if (rsas & NewlyCreatedLeft) {
279 selection->add (*ri);
282 // new regions created after the split
283 if (rsas & NewlyCreatedRight) {
284 selection->add (*ri);
288 _ignore_follow_edits = false;
290 _ignore_follow_edits = true;
291 if( working_on_selection ) {
292 selection->add (latest_regionviews); //these are the new regions created after the split
294 _ignore_follow_edits = false;
297 commit_reversible_command ();
300 /** Move one extreme of the current range selection. If more than one range is selected,
301 * the start of the earliest range or the end of the latest range is moved.
303 * @param move_end true to move the end of the current range selection, false to move
305 * @param next true to move the extreme to the next region boundary, false to move to
309 Editor::move_range_selection_start_or_end_to_region_boundary (bool move_end, bool next)
311 if (selection->time.start() == selection->time.end_frame()) {
315 framepos_t start = selection->time.start ();
316 framepos_t end = selection->time.end_frame ();
318 /* the position of the thing we may move */
319 framepos_t pos = move_end ? end : start;
320 int dir = next ? 1 : -1;
322 /* so we don't find the current region again */
323 if (dir > 0 || pos > 0) {
327 framepos_t const target = get_region_boundary (pos, dir, true, false);
342 begin_reversible_selection_op (_("alter selection"));
343 selection->set_preserving_all_ranges (start, end);
344 commit_reversible_selection_op ();
348 Editor::nudge_forward_release (GdkEventButton* ev)
350 if (ev->state & Keyboard::PrimaryModifier) {
351 nudge_forward (false, true);
353 nudge_forward (false, false);
359 Editor::nudge_backward_release (GdkEventButton* ev)
361 if (ev->state & Keyboard::PrimaryModifier) {
362 nudge_backward (false, true);
364 nudge_backward (false, false);
371 Editor::nudge_forward (bool next, bool force_playhead)
374 framepos_t next_distance;
380 RegionSelection rs = get_regions_from_selection_and_entered ();
382 if (!force_playhead && !rs.empty()) {
384 begin_reversible_command (_("nudge regions forward"));
386 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
387 boost::shared_ptr<Region> r ((*i)->region());
389 distance = get_nudge_distance (r->position(), next_distance);
392 distance = next_distance;
396 r->set_position (r->position() + distance);
397 _session->add_command (new StatefulDiffCommand (r));
400 commit_reversible_command ();
403 } else if (!force_playhead && !selection->markers.empty()) {
406 bool in_command = false;
408 for (MarkerSelection::iterator i = selection->markers.begin(); i != selection->markers.end(); ++i) {
410 Location* loc = find_location_from_marker ((*i), is_start);
414 XMLNode& before (loc->get_state());
417 distance = get_nudge_distance (loc->start(), next_distance);
419 distance = next_distance;
421 if (max_framepos - distance > loc->start() + loc->length()) {
422 loc->set_start (loc->start() + distance);
424 loc->set_start (max_framepos - loc->length());
427 distance = get_nudge_distance (loc->end(), next_distance);
429 distance = next_distance;
431 if (max_framepos - distance > loc->end()) {
432 loc->set_end (loc->end() + distance);
434 loc->set_end (max_framepos);
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 = dynamic_cast<RouteTimeAxisView*> ((*i));
3052 if (!rtv->is_track()) {
3056 /* no edits to destructive tracks */
3058 if (rtv->track()->destructive()) {
3062 if ((playlist = rtv->playlist()) != 0) {
3064 playlist->clear_changes ();
3066 /* XXX need to consider musical time selections here at some point */
3068 double speed = rtv->track()->speed();
3070 for (list<AudioRange>::const_iterator t = ts.begin(); t != ts.end(); ++t) {
3072 sigc::connection c = rtv->view()->RegionViewAdded.connect (
3073 sigc::mem_fun(*this, &Editor::collect_new_region_view));
3075 latest_regionviews.clear ();
3077 playlist->partition ((framepos_t)((*t).start * speed),
3078 (framepos_t)((*t).end * speed), false);
3082 if (!latest_regionviews.empty()) {
3084 rtv->view()->foreach_regionview (sigc::bind (
3085 sigc::ptr_fun (add_if_covered),
3086 &(*t), &new_selection));
3089 begin_reversible_command (_("separate"));
3093 /* pick up changes to existing regions */
3095 vector<Command*> cmds;
3096 playlist->rdiff (cmds);
3097 _session->add_commands (cmds);
3099 /* pick up changes to the playlist itself (adds/removes)
3102 _session->add_command(new StatefulDiffCommand (playlist));
3109 // selection->set (new_selection);
3111 commit_reversible_command ();
3115 struct PlaylistState {
3116 boost::shared_ptr<Playlist> playlist;
3120 /** Take tracks from get_tracks_for_range_action and cut any regions
3121 * on those tracks so that the tracks are empty over the time
3125 Editor::separate_region_from_selection ()
3127 /* preferentially use *all* ranges in the time selection if we're in range mode
3128 to allow discontiguous operation, since get_edit_op_range() currently
3129 returns a single range.
3132 if (!selection->time.empty()) {
3134 separate_regions_between (selection->time);
3141 if (get_edit_op_range (start, end)) {
3143 AudioRange ar (start, end, 1);
3147 separate_regions_between (ts);
3153 Editor::separate_region_from_punch ()
3155 Location* loc = _session->locations()->auto_punch_location();
3157 separate_regions_using_location (*loc);
3162 Editor::separate_region_from_loop ()
3164 Location* loc = _session->locations()->auto_loop_location();
3166 separate_regions_using_location (*loc);
3171 Editor::separate_regions_using_location (Location& loc)
3173 if (loc.is_mark()) {
3177 AudioRange ar (loc.start(), loc.end(), 1);
3182 separate_regions_between (ts);
3185 /** Separate regions under the selected region */
3187 Editor::separate_under_selected_regions ()
3189 vector<PlaylistState> playlists;
3193 rs = get_regions_from_selection_and_entered();
3195 if (!_session || rs.empty()) {
3199 begin_reversible_command (_("separate region under"));
3201 list<boost::shared_ptr<Region> > regions_to_remove;
3203 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3204 // we can't just remove the region(s) in this loop because
3205 // this removes them from the RegionSelection, and they thus
3206 // disappear from underneath the iterator, and the ++i above
3207 // SEGVs in a puzzling fashion.
3209 // so, first iterate over the regions to be removed from rs and
3210 // add them to the regions_to_remove list, and then
3211 // iterate over the list to actually remove them.
3213 regions_to_remove.push_back ((*i)->region());
3216 for (list<boost::shared_ptr<Region> >::iterator rl = regions_to_remove.begin(); rl != regions_to_remove.end(); ++rl) {
3218 boost::shared_ptr<Playlist> playlist = (*rl)->playlist();
3221 // is this check necessary?
3225 vector<PlaylistState>::iterator i;
3227 //only take state if this is a new playlist.
3228 for (i = playlists.begin(); i != playlists.end(); ++i) {
3229 if ((*i).playlist == playlist) {
3234 if (i == playlists.end()) {
3236 PlaylistState before;
3237 before.playlist = playlist;
3238 before.before = &playlist->get_state();
3240 playlist->freeze ();
3241 playlists.push_back(before);
3244 //Partition on the region bounds
3245 playlist->partition ((*rl)->first_frame() - 1, (*rl)->last_frame() + 1, true);
3247 //Re-add region that was just removed due to the partition operation
3248 playlist->add_region( (*rl), (*rl)->first_frame() );
3251 vector<PlaylistState>::iterator pl;
3253 for (pl = playlists.begin(); pl != playlists.end(); ++pl) {
3254 (*pl).playlist->thaw ();
3255 _session->add_command(new MementoCommand<Playlist>(*(*pl).playlist, (*pl).before, &(*pl).playlist->get_state()));
3258 commit_reversible_command ();
3262 Editor::crop_region_to_selection ()
3264 if (!selection->time.empty()) {
3266 crop_region_to (selection->time.start(), selection->time.end_frame());
3273 if (get_edit_op_range (start, end)) {
3274 crop_region_to (start, end);
3281 Editor::crop_region_to (framepos_t start, framepos_t end)
3283 vector<boost::shared_ptr<Playlist> > playlists;
3284 boost::shared_ptr<Playlist> playlist;
3287 if (selection->tracks.empty()) {
3288 ts = track_views.filter_to_unique_playlists();
3290 ts = selection->tracks.filter_to_unique_playlists ();
3293 sort_track_selection (ts);
3295 for (TrackSelection::iterator i = ts.begin(); i != ts.end(); ++i) {
3297 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> ((*i));
3303 boost::shared_ptr<Track> t = rtv->track();
3305 if (t != 0 && ! t->destructive()) {
3307 if ((playlist = rtv->playlist()) != 0) {
3308 playlists.push_back (playlist);
3313 if (playlists.empty()) {
3318 framepos_t new_start;
3320 framecnt_t new_length;
3321 bool in_command = false;
3323 for (vector<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
3325 /* Only the top regions at start and end have to be cropped */
3326 boost::shared_ptr<Region> region_at_start = (*i)->top_region_at(start);
3327 boost::shared_ptr<Region> region_at_end = (*i)->top_region_at(end);
3329 vector<boost::shared_ptr<Region> > regions;
3331 if (region_at_start != 0) {
3332 regions.push_back (region_at_start);
3334 if (region_at_end != 0) {
3335 regions.push_back (region_at_end);
3338 /* now adjust lengths */
3339 for (vector<boost::shared_ptr<Region> >::iterator i = regions.begin(); i != regions.end(); ++i) {
3341 pos = (*i)->position();
3342 new_start = max (start, pos);
3343 if (max_framepos - pos > (*i)->length()) {
3344 new_end = pos + (*i)->length() - 1;
3346 new_end = max_framepos;
3348 new_end = min (end, new_end);
3349 new_length = new_end - new_start + 1;
3352 begin_reversible_command (_("trim to selection"));
3355 (*i)->clear_changes ();
3356 (*i)->trim_to (new_start, new_length);
3357 _session->add_command (new StatefulDiffCommand (*i));
3362 commit_reversible_command ();
3367 Editor::region_fill_track ()
3369 boost::shared_ptr<Playlist> playlist;
3370 RegionSelection regions = get_regions_from_selection_and_entered ();
3371 RegionSelection foo;
3373 framepos_t const end = _session->current_end_frame ();
3375 if (regions.empty () || regions.end_frame () + 1 >= end) {
3379 framepos_t const start_frame = regions.start ();
3380 framepos_t const end_frame = regions.end_frame ();
3381 framecnt_t const gap = end_frame - start_frame + 1;
3383 begin_reversible_command (Operations::region_fill);
3385 selection->clear_regions ();
3387 for (RegionSelection::iterator i = regions.begin(); i != regions.end(); ++i) {
3389 boost::shared_ptr<Region> r ((*i)->region());
3391 TimeAxisView& tv = (*i)->get_time_axis_view();
3392 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (&tv);
3393 latest_regionviews.clear ();
3394 sigc::connection c = rtv->view()->RegionViewAdded.connect (sigc::mem_fun(*this, &Editor::collect_new_region_view));
3396 framepos_t const position = end_frame + (r->first_frame() - start_frame + 1);
3397 playlist = (*i)->region()->playlist();
3398 playlist->clear_changes ();
3399 playlist->duplicate_until (r, position, gap, end);
3400 _session->add_command(new StatefulDiffCommand (playlist));
3404 foo.insert (foo.end(), latest_regionviews.begin(), latest_regionviews.end());
3408 selection->set (foo);
3411 commit_reversible_command ();
3415 Editor::set_region_sync_position ()
3417 set_sync_point (get_preferred_edit_position (), get_regions_from_selection_and_edit_point ());
3421 Editor::set_sync_point (framepos_t where, const RegionSelection& rs)
3423 bool in_command = false;
3425 for (RegionSelection::const_iterator r = rs.begin(); r != rs.end(); ++r) {
3427 if (!(*r)->region()->covers (where)) {
3431 boost::shared_ptr<Region> region ((*r)->region());
3434 begin_reversible_command (_("set sync point"));
3438 region->clear_changes ();
3439 region->set_sync_position (where);
3440 _session->add_command(new StatefulDiffCommand (region));
3444 commit_reversible_command ();
3448 /** Remove the sync positions of the selection */
3450 Editor::remove_region_sync ()
3452 RegionSelection rs = get_regions_from_selection_and_entered ();
3458 begin_reversible_command (_("remove region sync"));
3460 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3462 (*i)->region()->clear_changes ();
3463 (*i)->region()->clear_sync_position ();
3464 _session->add_command(new StatefulDiffCommand ((*i)->region()));
3467 commit_reversible_command ();
3471 Editor::naturalize_region ()
3473 RegionSelection rs = get_regions_from_selection_and_entered ();
3479 if (rs.size() > 1) {
3480 begin_reversible_command (_("move regions to original position"));
3482 begin_reversible_command (_("move region to original position"));
3485 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3486 (*i)->region()->clear_changes ();
3487 (*i)->region()->move_to_natural_position ();
3488 _session->add_command (new StatefulDiffCommand ((*i)->region()));
3491 commit_reversible_command ();
3495 Editor::align_regions (RegionPoint what)
3497 RegionSelection const rs = get_regions_from_selection_and_edit_point ();
3503 begin_reversible_command (_("align selection"));
3505 framepos_t const position = get_preferred_edit_position ();
3507 for (RegionSelection::const_iterator i = rs.begin(); i != rs.end(); ++i) {
3508 align_region_internal ((*i)->region(), what, position);
3511 commit_reversible_command ();
3514 struct RegionSortByTime {
3515 bool operator() (const RegionView* a, const RegionView* b) {
3516 return a->region()->position() < b->region()->position();
3521 Editor::align_regions_relative (RegionPoint point)
3523 RegionSelection const rs = get_regions_from_selection_and_edit_point ();
3529 framepos_t const position = get_preferred_edit_position ();
3531 framepos_t distance = 0;
3535 list<RegionView*> sorted;
3536 rs.by_position (sorted);
3538 boost::shared_ptr<Region> r ((*sorted.begin())->region());
3543 if (position > r->position()) {
3544 distance = position - r->position();
3546 distance = r->position() - position;
3552 if (position > r->last_frame()) {
3553 distance = position - r->last_frame();
3554 pos = r->position() + distance;
3556 distance = r->last_frame() - position;
3557 pos = r->position() - distance;
3563 pos = r->adjust_to_sync (position);
3564 if (pos > r->position()) {
3565 distance = pos - r->position();
3567 distance = r->position() - pos;
3573 if (pos == r->position()) {
3577 begin_reversible_command (_("align selection (relative)"));
3579 /* move first one specially */
3581 r->clear_changes ();
3582 r->set_position (pos);
3583 _session->add_command(new StatefulDiffCommand (r));
3585 /* move rest by the same amount */
3589 for (list<RegionView*>::iterator i = sorted.begin(); i != sorted.end(); ++i) {
3591 boost::shared_ptr<Region> region ((*i)->region());
3593 region->clear_changes ();
3596 region->set_position (region->position() + distance);
3598 region->set_position (region->position() - distance);
3601 _session->add_command(new StatefulDiffCommand (region));
3605 commit_reversible_command ();
3609 Editor::align_region (boost::shared_ptr<Region> region, RegionPoint point, framepos_t position)
3611 begin_reversible_command (_("align region"));
3612 align_region_internal (region, point, position);
3613 commit_reversible_command ();
3617 Editor::align_region_internal (boost::shared_ptr<Region> region, RegionPoint point, framepos_t position)
3619 region->clear_changes ();
3623 region->set_position (region->adjust_to_sync (position));
3627 if (position > region->length()) {
3628 region->set_position (position - region->length());
3633 region->set_position (position);
3637 _session->add_command(new StatefulDiffCommand (region));
3641 Editor::trim_region_front ()
3647 Editor::trim_region_back ()
3649 trim_region (false);
3653 Editor::trim_region (bool front)
3655 framepos_t where = get_preferred_edit_position();
3656 RegionSelection rs = get_regions_from_selection_and_edit_point ();
3662 begin_reversible_command (front ? _("trim front") : _("trim back"));
3664 for (list<RegionView*>::const_iterator i = rs.by_layer().begin(); i != rs.by_layer().end(); ++i) {
3665 if (!(*i)->region()->locked()) {
3667 (*i)->region()->clear_changes ();
3670 (*i)->region()->trim_front (where);
3671 maybe_locate_with_edit_preroll ( where );
3673 (*i)->region()->trim_end (where);
3674 maybe_locate_with_edit_preroll ( where );
3677 _session->add_command (new StatefulDiffCommand ((*i)->region()));
3681 commit_reversible_command ();
3684 /** Trim the end of the selected regions to the position of the edit cursor */
3686 Editor::trim_region_to_loop ()
3688 Location* loc = _session->locations()->auto_loop_location();
3692 trim_region_to_location (*loc, _("trim to loop"));
3696 Editor::trim_region_to_punch ()
3698 Location* loc = _session->locations()->auto_punch_location();
3702 trim_region_to_location (*loc, _("trim to punch"));
3706 Editor::trim_region_to_location (const Location& loc, const char* str)
3708 RegionSelection rs = get_regions_from_selection_and_entered ();
3709 bool in_command = false;
3711 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
3712 RegionView* rv = (*x);
3714 /* require region to span proposed trim */
3715 switch (rv->region()->coverage (loc.start(), loc.end())) {
3716 case Evoral::OverlapInternal:
3722 RouteTimeAxisView* tav = dynamic_cast<RouteTimeAxisView*> (&rv->get_time_axis_view());
3731 if (tav->track() != 0) {
3732 speed = tav->track()->speed();
3735 start = session_frame_to_track_frame (loc.start(), speed);
3736 end = session_frame_to_track_frame (loc.end(), speed);
3738 rv->region()->clear_changes ();
3739 rv->region()->trim_to (start, (end - start));
3742 begin_reversible_command (str);
3745 _session->add_command(new StatefulDiffCommand (rv->region()));
3749 commit_reversible_command ();
3754 Editor::trim_region_to_previous_region_end ()
3756 return trim_to_region(false);
3760 Editor::trim_region_to_next_region_start ()
3762 return trim_to_region(true);
3766 Editor::trim_to_region(bool forward)
3768 RegionSelection rs = get_regions_from_selection_and_entered ();
3769 bool in_command = false;
3771 boost::shared_ptr<Region> next_region;
3773 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
3775 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*x);
3781 AudioTimeAxisView* atav = dynamic_cast<AudioTimeAxisView*> (&arv->get_time_axis_view());
3789 if (atav->track() != 0) {
3790 speed = atav->track()->speed();
3794 boost::shared_ptr<Region> region = arv->region();
3795 boost::shared_ptr<Playlist> playlist (region->playlist());
3797 region->clear_changes ();
3801 next_region = playlist->find_next_region (region->first_frame(), Start, 1);
3807 region->trim_end((framepos_t) ( (next_region->first_frame() - 1) * speed));
3808 arv->region_changed (PropertyChange (ARDOUR::Properties::length));
3812 next_region = playlist->find_next_region (region->first_frame(), Start, 0);
3818 region->trim_front((framepos_t) ((next_region->last_frame() + 1) * speed));
3820 arv->region_changed (ARDOUR::bounds_change);
3824 begin_reversible_command (_("trim to region"));
3827 _session->add_command(new StatefulDiffCommand (region));
3831 commit_reversible_command ();
3836 Editor::unfreeze_route ()
3838 if (clicked_routeview == 0 || !clicked_routeview->is_track()) {
3842 clicked_routeview->track()->unfreeze ();
3846 Editor::_freeze_thread (void* arg)
3848 return static_cast<Editor*>(arg)->freeze_thread ();
3852 Editor::freeze_thread ()
3854 /* create event pool because we may need to talk to the session */
3855 SessionEvent::create_per_thread_pool ("freeze events", 64);
3856 /* create per-thread buffers for process() tree to use */
3857 clicked_routeview->audio_track()->freeze_me (*current_interthread_info);
3858 current_interthread_info->done = true;
3863 Editor::freeze_route ()
3869 /* stop transport before we start. this is important */
3871 _session->request_transport_speed (0.0);
3873 /* wait for just a little while, because the above call is asynchronous */
3875 Glib::usleep (250000);
3877 if (clicked_routeview == 0 || !clicked_routeview->is_audio_track()) {
3881 if (!clicked_routeview->track()->bounceable (clicked_routeview->track()->main_outs(), true)) {
3883 _("This track/bus cannot be frozen because the signal adds or loses channels before reaching the outputs.\n"
3884 "This is typically caused by plugins that generate stereo output from mono input or vice versa.")
3886 d.set_title (_("Cannot freeze"));
3891 if (clicked_routeview->track()->has_external_redirects()) {
3892 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"
3893 "Freezing will only process the signal as far as the first send/insert/return."),
3894 clicked_routeview->track()->name()), true, MESSAGE_INFO, BUTTONS_NONE, true);
3896 d.add_button (_("Freeze anyway"), Gtk::RESPONSE_OK);
3897 d.add_button (_("Don't freeze"), Gtk::RESPONSE_CANCEL);
3898 d.set_title (_("Freeze Limits"));
3900 int response = d.run ();
3903 case Gtk::RESPONSE_CANCEL:
3910 InterThreadInfo itt;
3911 current_interthread_info = &itt;
3913 InterthreadProgressWindow ipw (current_interthread_info, _("Freeze"), _("Cancel Freeze"));
3915 pthread_create_and_store (X_("freezer"), &itt.thread, _freeze_thread, this);
3917 CursorContext::Handle cursor_ctx = CursorContext::create(*this, _cursors->wait);
3919 while (!itt.done && !itt.cancel) {
3920 gtk_main_iteration ();
3923 pthread_join (itt.thread, 0);
3924 current_interthread_info = 0;
3928 Editor::bounce_range_selection (bool replace, bool enable_processing)
3930 if (selection->time.empty()) {
3934 TrackSelection views = selection->tracks;
3936 for (TrackViewList::iterator i = views.begin(); i != views.end(); ++i) {
3938 if (enable_processing) {
3940 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*i);
3942 if (rtv && rtv->track() && replace && enable_processing && !rtv->track()->bounceable (rtv->track()->main_outs(), false)) {
3944 _("You can't perform this operation because the processing of the signal "
3945 "will cause one or more of the tracks to end up with a region with more channels than this track has inputs.\n\n"
3946 "You can do this without processing, which is a different operation.")
3948 d.set_title (_("Cannot bounce"));
3955 framepos_t start = selection->time[clicked_selection].start;
3956 framepos_t end = selection->time[clicked_selection].end;
3957 framepos_t cnt = end - start + 1;
3958 bool in_command = false;
3960 for (TrackViewList::iterator i = views.begin(); i != views.end(); ++i) {
3962 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*i);
3968 boost::shared_ptr<Playlist> playlist;
3970 if ((playlist = rtv->playlist()) == 0) {
3974 InterThreadInfo itt;
3976 playlist->clear_changes ();
3977 playlist->clear_owned_changes ();
3979 boost::shared_ptr<Region> r;
3981 if (enable_processing) {
3982 r = rtv->track()->bounce_range (start, start+cnt, itt, rtv->track()->main_outs(), false);
3984 r = rtv->track()->bounce_range (start, start+cnt, itt, boost::shared_ptr<Processor>(), false);
3992 list<AudioRange> ranges;
3993 ranges.push_back (AudioRange (start, start+cnt, 0));
3994 playlist->cut (ranges); // discard result
3995 playlist->add_region (r, start);
3999 begin_reversible_command (_("bounce range"));
4002 vector<Command*> cmds;
4003 playlist->rdiff (cmds);
4004 _session->add_commands (cmds);
4006 _session->add_command (new StatefulDiffCommand (playlist));
4010 commit_reversible_command ();
4014 /** Delete selected regions, automation points or a time range */
4018 //special case: if the user is pointing in the editor/mixer strip, they may be trying to delete a plugin.
4019 //we need this because the editor-mixer strip is in the editor window, so it doesn't get the bindings from the mix window
4020 bool deleted = false;
4021 if ( current_mixer_strip && current_mixer_strip == MixerStrip::entered_mixer_strip() )
4022 deleted = current_mixer_strip->delete_processors ();
4028 /** Cut selected regions, automation points or a time range */
4035 /** Copy selected regions, automation points or a time range */
4043 /** @return true if a Cut, Copy or Clear is possible */
4045 Editor::can_cut_copy () const
4047 if (!selection->time.empty() || !selection->regions.empty() || !selection->points.empty())
4054 /** Cut, copy or clear selected regions, automation points or a time range.
4055 * @param op Operation (Delete, Cut, Copy or Clear)
4058 Editor::cut_copy (CutCopyOp op)
4060 /* only cancel selection if cut/copy is successful.*/
4066 opname = _("delete");
4075 opname = _("clear");
4079 /* if we're deleting something, and the mouse is still pressed,
4080 the thing we started a drag for will be gone when we release
4081 the mouse button(s). avoid this. see part 2 at the end of
4085 if (op == Delete || op == Cut || op == Clear) {
4086 if (_drags->active ()) {
4091 if ( op != Delete ) //"Delete" doesn't change copy/paste buf
4092 cut_buffer->clear ();
4094 if (entered_marker) {
4096 /* cut/delete op while pointing at a marker */
4099 Location* loc = find_location_from_marker (entered_marker, ignored);
4101 if (_session && loc) {
4102 entered_marker = NULL;
4103 Glib::signal_idle().connect (sigc::bind (sigc::mem_fun(*this, &Editor::really_remove_marker), loc));
4110 switch (mouse_mode) {
4113 begin_reversible_command (opname + ' ' + X_("MIDI"));
4115 commit_reversible_command ();
4121 bool did_edit = false;
4123 if (!selection->regions.empty() || !selection->points.empty()) {
4124 begin_reversible_command (opname + ' ' + _("objects"));
4127 if (!selection->regions.empty()) {
4128 cut_copy_regions (op, selection->regions);
4130 if (op == Cut || op == Delete) {
4131 selection->clear_regions ();
4135 if (!selection->points.empty()) {
4136 cut_copy_points (op);
4138 if (op == Cut || op == Delete) {
4139 selection->clear_points ();
4142 } else if (selection->time.empty()) {
4143 framepos_t start, end;
4144 /* no time selection, see if we can get an edit range
4147 if (get_edit_op_range (start, end)) {
4148 selection->set (start, end);
4150 } else if (!selection->time.empty()) {
4151 begin_reversible_command (opname + ' ' + _("range"));
4154 cut_copy_ranges (op);
4156 if (op == Cut || op == Delete) {
4157 selection->clear_time ();
4162 /* reset repeated paste state */
4165 commit_reversible_command ();
4168 if (op == Delete || op == Cut || op == Clear) {
4173 struct AutomationRecord {
4174 AutomationRecord () : state (0) , line(NULL) {}
4175 AutomationRecord (XMLNode* s, const AutomationLine* l) : state (s) , line (l) {}
4177 XMLNode* state; ///< state before any operation
4178 const AutomationLine* line; ///< line this came from
4179 boost::shared_ptr<Evoral::ControlList> copy; ///< copied events for the cut buffer
4182 /** Cut, copy or clear selected automation points.
4183 * @param op Operation (Cut, Copy or Clear)
4186 Editor::cut_copy_points (Editing::CutCopyOp op, Evoral::Beats earliest, bool midi)
4188 if (selection->points.empty ()) {
4192 /* XXX: not ideal, as there may be more than one track involved in the point selection */
4193 _last_cut_copy_source_track = &selection->points.front()->line().trackview;
4195 /* Keep a record of the AutomationLists that we end up using in this operation */
4196 typedef std::map<boost::shared_ptr<AutomationList>, AutomationRecord> Lists;
4199 /* Go through all selected points, making an AutomationRecord for each distinct AutomationList */
4200 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
4201 const AutomationLine& line = (*i)->line();
4202 const boost::shared_ptr<AutomationList> al = line.the_list();
4203 if (lists.find (al) == lists.end ()) {
4204 /* We haven't seen this list yet, so make a record for it. This includes
4205 taking a copy of its current state, in case this is needed for undo later.
4207 lists[al] = AutomationRecord (&al->get_state (), &line);
4211 if (op == Cut || op == Copy) {
4212 /* This operation will involve putting things in the cut buffer, so create an empty
4213 ControlList for each of our source lists to put the cut buffer data in.
4215 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
4216 i->second.copy = i->first->create (i->first->parameter (), i->first->descriptor());
4219 /* Add all selected points to the relevant copy ControlLists */
4220 framepos_t start = std::numeric_limits<framepos_t>::max();
4221 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
4222 boost::shared_ptr<AutomationList> al = (*i)->line().the_list();
4223 AutomationList::const_iterator j = (*i)->model();
4225 lists[al].copy->fast_simple_add ((*j)->when, (*j)->value);
4227 /* Update earliest MIDI start time in beats */
4228 earliest = std::min(earliest, Evoral::Beats((*j)->when));
4230 /* Update earliest session start time in frames */
4231 start = std::min(start, (*i)->line().session_position(j));
4235 /* Snap start time backwards, so copy/paste is snap aligned. */
4237 if (earliest == Evoral::Beats::max()) {
4238 earliest = Evoral::Beats(); // Weird... don't offset
4240 earliest.round_down_to_beat();
4242 if (start == std::numeric_limits<double>::max()) {
4243 start = 0; // Weird... don't offset
4245 snap_to(start, RoundDownMaybe);
4248 const double line_offset = midi ? earliest.to_double() : start;
4249 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
4250 /* Correct this copy list so that it is relative to the earliest
4251 start time, so relative ordering between points is preserved
4252 when copying from several lists and the paste starts at the
4253 earliest copied piece of data. */
4254 for (AutomationList::iterator j = i->second.copy->begin(); j != i->second.copy->end(); ++j) {
4255 (*j)->when -= line_offset;
4258 /* And add it to the cut buffer */
4259 cut_buffer->add (i->second.copy);
4263 if (op == Delete || op == Cut) {
4264 /* This operation needs to remove things from the main AutomationList, so do that now */
4266 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
4267 i->first->freeze ();
4270 /* Remove each selected point from its AutomationList */
4271 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
4272 boost::shared_ptr<AutomationList> al = (*i)->line().the_list();
4273 al->erase ((*i)->model ());
4276 /* Thaw the lists and add undo records for them */
4277 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
4278 boost::shared_ptr<AutomationList> al = i->first;
4280 _session->add_command (new MementoCommand<AutomationList> (*al.get(), i->second.state, &(al->get_state ())));
4285 /** Cut, copy or clear selected automation points.
4286 * @param op Operation (Cut, Copy or Clear)
4289 Editor::cut_copy_midi (CutCopyOp op)
4291 Evoral::Beats earliest = Evoral::Beats::max();
4292 for (MidiRegionSelection::iterator i = selection->midi_regions.begin(); i != selection->midi_regions.end(); ++i) {
4293 MidiRegionView* mrv = dynamic_cast<MidiRegionView*>(*i);
4295 if (!mrv->selection().empty()) {
4296 earliest = std::min(earliest, (*mrv->selection().begin())->note()->time());
4298 mrv->cut_copy_clear (op);
4300 /* XXX: not ideal, as there may be more than one track involved in the selection */
4301 _last_cut_copy_source_track = &mrv->get_time_axis_view();
4305 if (!selection->points.empty()) {
4306 cut_copy_points (op, earliest, true);
4307 if (op == Cut || op == Delete) {
4308 selection->clear_points ();
4313 struct lt_playlist {
4314 bool operator () (const PlaylistState& a, const PlaylistState& b) {
4315 return a.playlist < b.playlist;
4319 struct PlaylistMapping {
4321 boost::shared_ptr<Playlist> pl;
4323 PlaylistMapping (TimeAxisView* tvp) : tv (tvp) {}
4326 /** Remove `clicked_regionview' */
4328 Editor::remove_clicked_region ()
4330 if (clicked_routeview == 0 || clicked_regionview == 0) {
4334 begin_reversible_command (_("remove region"));
4336 boost::shared_ptr<Playlist> playlist = clicked_routeview->playlist();
4338 playlist->clear_changes ();
4339 playlist->clear_owned_changes ();
4340 playlist->remove_region (clicked_regionview->region());
4341 if (Config->get_edit_mode() == Ripple)
4342 playlist->ripple (clicked_regionview->region()->position(), -clicked_regionview->region()->length(), boost::shared_ptr<Region>());
4344 /* We might have removed regions, which alters other regions' layering_index,
4345 so we need to do a recursive diff here.
4347 vector<Command*> cmds;
4348 playlist->rdiff (cmds);
4349 _session->add_commands (cmds);
4351 _session->add_command(new StatefulDiffCommand (playlist));
4352 commit_reversible_command ();
4356 /** Remove the selected regions */
4358 Editor::remove_selected_regions ()
4360 RegionSelection rs = get_regions_from_selection_and_entered ();
4362 if (!_session || rs.empty()) {
4366 list<boost::shared_ptr<Region> > regions_to_remove;
4368 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
4369 // we can't just remove the region(s) in this loop because
4370 // this removes them from the RegionSelection, and they thus
4371 // disappear from underneath the iterator, and the ++i above
4372 // SEGVs in a puzzling fashion.
4374 // so, first iterate over the regions to be removed from rs and
4375 // add them to the regions_to_remove list, and then
4376 // iterate over the list to actually remove them.
4378 regions_to_remove.push_back ((*i)->region());
4381 vector<boost::shared_ptr<Playlist> > playlists;
4383 for (list<boost::shared_ptr<Region> >::iterator rl = regions_to_remove.begin(); rl != regions_to_remove.end(); ++rl) {
4385 boost::shared_ptr<Playlist> playlist = (*rl)->playlist();
4388 // is this check necessary?
4392 /* get_regions_from_selection_and_entered() guarantees that
4393 the playlists involved are unique, so there is no need
4397 playlists.push_back (playlist);
4399 playlist->clear_changes ();
4400 playlist->clear_owned_changes ();
4401 playlist->freeze ();
4402 playlist->remove_region (*rl);
4403 if (Config->get_edit_mode() == Ripple)
4404 playlist->ripple ((*rl)->position(), -(*rl)->length(), boost::shared_ptr<Region>());
4408 vector<boost::shared_ptr<Playlist> >::iterator pl;
4409 bool in_command = false;
4411 for (pl = playlists.begin(); pl != playlists.end(); ++pl) {
4414 /* We might have removed regions, which alters other regions' layering_index,
4415 so we need to do a recursive diff here.
4419 begin_reversible_command (_("remove region"));
4422 vector<Command*> cmds;
4423 (*pl)->rdiff (cmds);
4424 _session->add_commands (cmds);
4426 _session->add_command(new StatefulDiffCommand (*pl));
4430 commit_reversible_command ();
4434 /** Cut, copy or clear selected regions.
4435 * @param op Operation (Cut, Copy or Clear)
4438 Editor::cut_copy_regions (CutCopyOp op, RegionSelection& rs)
4440 /* we can't use a std::map here because the ordering is important, and we can't trivially sort
4441 a map when we want ordered access to both elements. i think.
4444 vector<PlaylistMapping> pmap;
4446 framepos_t first_position = max_framepos;
4448 typedef set<boost::shared_ptr<Playlist> > FreezeList;
4449 FreezeList freezelist;
4451 /* get ordering correct before we cut/copy */
4453 rs.sort_by_position_and_track ();
4455 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
4457 first_position = min ((framepos_t) (*x)->region()->position(), first_position);
4459 if (op == Cut || op == Clear || op == Delete) {
4460 boost::shared_ptr<Playlist> pl = (*x)->region()->playlist();
4463 FreezeList::iterator fl;
4465 // only take state if this is a new playlist.
4466 for (fl = freezelist.begin(); fl != freezelist.end(); ++fl) {
4472 if (fl == freezelist.end()) {
4473 pl->clear_changes();
4474 pl->clear_owned_changes ();
4476 freezelist.insert (pl);
4481 TimeAxisView* tv = &(*x)->get_time_axis_view();
4482 vector<PlaylistMapping>::iterator z;
4484 for (z = pmap.begin(); z != pmap.end(); ++z) {
4485 if ((*z).tv == tv) {
4490 if (z == pmap.end()) {
4491 pmap.push_back (PlaylistMapping (tv));
4495 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ) {
4497 boost::shared_ptr<Playlist> pl = (*x)->region()->playlist();
4500 /* region not yet associated with a playlist (e.g. unfinished
4507 TimeAxisView& tv = (*x)->get_time_axis_view();
4508 boost::shared_ptr<Playlist> npl;
4509 RegionSelection::iterator tmp;
4516 vector<PlaylistMapping>::iterator z;
4518 for (z = pmap.begin(); z != pmap.end(); ++z) {
4519 if ((*z).tv == &tv) {
4524 assert (z != pmap.end());
4527 npl = PlaylistFactory::create (pl->data_type(), *_session, "cutlist", true);
4535 boost::shared_ptr<Region> r = (*x)->region();
4536 boost::shared_ptr<Region> _xx;
4542 pl->remove_region (r);
4543 if (Config->get_edit_mode() == Ripple)
4544 pl->ripple (r->position(), -r->length(), boost::shared_ptr<Region>());
4548 _xx = RegionFactory::create (r);
4549 npl->add_region (_xx, r->position() - first_position);
4550 pl->remove_region (r);
4551 if (Config->get_edit_mode() == Ripple)
4552 pl->ripple (r->position(), -r->length(), boost::shared_ptr<Region>());
4556 /* copy region before adding, so we're not putting same object into two different playlists */
4557 npl->add_region (RegionFactory::create (r), r->position() - first_position);
4561 pl->remove_region (r);
4562 if (Config->get_edit_mode() == Ripple)
4563 pl->ripple (r->position(), -r->length(), boost::shared_ptr<Region>());
4572 list<boost::shared_ptr<Playlist> > foo;
4574 /* the pmap is in the same order as the tracks in which selected regions occurred */
4576 for (vector<PlaylistMapping>::iterator i = pmap.begin(); i != pmap.end(); ++i) {
4579 foo.push_back ((*i).pl);
4584 cut_buffer->set (foo);
4588 _last_cut_copy_source_track = 0;
4590 _last_cut_copy_source_track = pmap.front().tv;
4594 for (FreezeList::iterator pl = freezelist.begin(); pl != freezelist.end(); ++pl) {
4597 /* We might have removed regions, which alters other regions' layering_index,
4598 so we need to do a recursive diff here.
4600 vector<Command*> cmds;
4601 (*pl)->rdiff (cmds);
4602 _session->add_commands (cmds);
4604 _session->add_command (new StatefulDiffCommand (*pl));
4609 Editor::cut_copy_ranges (CutCopyOp op)
4611 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4613 /* Sort the track selection now, so that it if is used, the playlists
4614 selected by the calls below to cut_copy_clear are in the order that
4615 their tracks appear in the editor. This makes things like paste
4616 of ranges work properly.
4619 sort_track_selection (ts);
4622 if (!entered_track) {
4625 ts.push_back (entered_track);
4628 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4629 (*i)->cut_copy_clear (*selection, op);
4634 Editor::paste (float times, bool from_context)
4636 DEBUG_TRACE (DEBUG::CutNPaste, "paste to preferred edit pos\n");
4638 paste_internal (get_preferred_edit_position (EDIT_IGNORE_NONE, from_context), times);
4642 Editor::mouse_paste ()
4647 if (!mouse_frame (where, ignored)) {
4652 paste_internal (where, 1);
4656 Editor::paste_internal (framepos_t position, float times)
4658 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("apparent paste position is %1\n", position));
4660 if (cut_buffer->empty(internal_editing())) {
4664 if (position == max_framepos) {
4665 position = get_preferred_edit_position();
4666 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("preferred edit position is %1\n", position));
4669 if (position == last_paste_pos) {
4670 /* repeated paste in the same position */
4673 /* paste in new location, reset repeated paste state */
4675 last_paste_pos = position;
4678 /* get everything in the correct order */
4681 if (!selection->tracks.empty()) {
4682 /* If there is a track selection, paste into exactly those tracks and
4683 only those tracks. This allows the user to be explicit and override
4684 the below "do the reasonable thing" logic. */
4685 ts = selection->tracks.filter_to_unique_playlists ();
4686 sort_track_selection (ts);
4688 /* Figure out which track to base the paste at. */
4689 TimeAxisView* base_track = NULL;
4690 if (_edit_point == Editing::EditAtMouse && entered_track) {
4691 /* With the mouse edit point, paste onto the track under the mouse. */
4692 base_track = entered_track;
4693 } else if (_edit_point == Editing::EditAtMouse && entered_regionview) {
4694 /* With the mouse edit point, paste onto the track of the region under the mouse. */
4695 base_track = &entered_regionview->get_time_axis_view();
4696 } else if (_last_cut_copy_source_track) {
4697 /* Paste to the track that the cut/copy came from (see mantis #333). */
4698 base_track = _last_cut_copy_source_track;
4700 /* This is "impossible" since we've copied... well, do nothing. */
4704 /* Walk up to parent if necessary, so base track is a route. */
4705 while (base_track->get_parent()) {
4706 base_track = base_track->get_parent();
4709 /* Add base track and all tracks below it. The paste logic will select
4710 the appropriate object types from the cut buffer in relative order. */
4711 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4712 if ((*i)->order() >= base_track->order()) {
4717 /* Sort tracks so the nth track of type T will pick the nth object of type T. */
4718 sort_track_selection (ts);
4720 /* Add automation children of each track in order, for pasting several lines. */
4721 for (TrackViewList::iterator i = ts.begin(); i != ts.end();) {
4722 /* Add any automation children for pasting several lines */
4723 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*i++);
4728 typedef RouteTimeAxisView::AutomationTracks ATracks;
4729 const ATracks& atracks = rtv->automation_tracks();
4730 for (ATracks::const_iterator a = atracks.begin(); a != atracks.end(); ++a) {
4731 i = ts.insert(i, a->second.get());
4736 /* We now have a list of trackviews starting at base_track, including
4737 automation children, in the order shown in the editor, e.g. R1,
4738 R1.A1, R1.A2, R2, R2.A1, ... */
4741 begin_reversible_command (Operations::paste);
4743 if (ts.size() == 1 && cut_buffer->lines.size() == 1 &&
4744 dynamic_cast<AutomationTimeAxisView*>(ts.front())) {
4745 /* Only one line copied, and one automation track selected. Do a
4746 "greedy" paste from one automation type to another. */
4748 PasteContext ctx(paste_count, times, ItemCounts(), true);
4749 ts.front()->paste (position, *cut_buffer, ctx);
4753 /* Paste into tracks */
4755 PasteContext ctx(paste_count, times, ItemCounts(), false);
4756 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4757 (*i)->paste (position, *cut_buffer, ctx);
4761 commit_reversible_command ();
4765 Editor::duplicate_some_regions (RegionSelection& regions, float times)
4767 if (regions.empty ()) {
4771 boost::shared_ptr<Playlist> playlist;
4772 RegionSelection sel = regions; // clear (below) may clear the argument list if its the current region selection
4773 RegionSelection foo;
4775 framepos_t const start_frame = regions.start ();
4776 framepos_t const end_frame = regions.end_frame ();
4777 framecnt_t const gap = end_frame - start_frame + 1;
4779 begin_reversible_command (Operations::duplicate_region);
4781 selection->clear_regions ();
4783 for (RegionSelection::iterator i = sel.begin(); i != sel.end(); ++i) {
4785 boost::shared_ptr<Region> r ((*i)->region());
4787 TimeAxisView& tv = (*i)->get_time_axis_view();
4788 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (&tv);
4789 latest_regionviews.clear ();
4790 sigc::connection c = rtv->view()->RegionViewAdded.connect (sigc::mem_fun(*this, &Editor::collect_new_region_view));
4792 framepos_t const position = end_frame + (r->first_frame() - start_frame + 1);
4793 playlist = (*i)->region()->playlist();
4794 playlist->clear_changes ();
4795 playlist->duplicate (r, position, gap, times);
4796 _session->add_command(new StatefulDiffCommand (playlist));
4800 foo.insert (foo.end(), latest_regionviews.begin(), latest_regionviews.end());
4804 selection->set (foo);
4807 commit_reversible_command ();
4811 Editor::duplicate_selection (float times)
4813 if (selection->time.empty() || selection->tracks.empty()) {
4817 boost::shared_ptr<Playlist> playlist;
4819 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4821 bool in_command = false;
4823 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4824 if ((playlist = (*i)->playlist()) == 0) {
4827 playlist->clear_changes ();
4829 if (clicked_selection) {
4830 playlist->duplicate_range (selection->time[clicked_selection], times);
4832 playlist->duplicate_ranges (selection->time, times);
4836 begin_reversible_command (_("duplicate range selection"));
4839 _session->add_command (new StatefulDiffCommand (playlist));
4844 // now "move" range selection to after the current range selection
4845 framecnt_t distance = 0;
4847 if (clicked_selection) {
4848 distance = selection->time[clicked_selection].end -
4849 selection->time[clicked_selection].start;
4851 distance = selection->time.end_frame() - selection->time.start();
4854 selection->move_time (distance);
4856 commit_reversible_command ();
4860 /** Reset all selected points to the relevant default value */
4862 Editor::reset_point_selection ()
4864 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
4865 ARDOUR::AutomationList::iterator j = (*i)->model ();
4866 (*j)->value = (*i)->line().the_list()->default_value ();
4871 Editor::center_playhead ()
4873 float const page = _visible_canvas_width * samples_per_pixel;
4874 center_screen_internal (playhead_cursor->current_frame (), page);
4878 Editor::center_edit_point ()
4880 float const page = _visible_canvas_width * samples_per_pixel;
4881 center_screen_internal (get_preferred_edit_position(), page);
4884 /** Caller must begin and commit a reversible command */
4886 Editor::clear_playlist (boost::shared_ptr<Playlist> playlist)
4888 playlist->clear_changes ();
4890 _session->add_command (new StatefulDiffCommand (playlist));
4894 Editor::nudge_track (bool use_edit, bool forwards)
4896 boost::shared_ptr<Playlist> playlist;
4897 framepos_t distance;
4898 framepos_t next_distance;
4902 start = get_preferred_edit_position();
4907 if ((distance = get_nudge_distance (start, next_distance)) == 0) {
4911 if (selection->tracks.empty()) {
4915 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4916 bool in_command = false;
4918 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4920 if ((playlist = (*i)->playlist()) == 0) {
4924 playlist->clear_changes ();
4925 playlist->clear_owned_changes ();
4927 playlist->nudge_after (start, distance, forwards);
4930 begin_reversible_command (_("nudge track"));
4933 vector<Command*> cmds;
4935 playlist->rdiff (cmds);
4936 _session->add_commands (cmds);
4938 _session->add_command (new StatefulDiffCommand (playlist));
4942 commit_reversible_command ();
4947 Editor::remove_last_capture ()
4949 vector<string> choices;
4956 if (Config->get_verify_remove_last_capture()) {
4957 prompt = _("Do you really want to destroy the last capture?"
4958 "\n(This is destructive and cannot be undone)");
4960 choices.push_back (_("No, do nothing."));
4961 choices.push_back (_("Yes, destroy it."));
4963 Gtkmm2ext::Choice prompter (_("Destroy last capture"), prompt, choices);
4965 if (prompter.run () == 1) {
4966 _session->remove_last_capture ();
4967 _regions->redisplay ();
4971 _session->remove_last_capture();
4972 _regions->redisplay ();
4977 Editor::normalize_region ()
4983 RegionSelection rs = get_regions_from_selection_and_entered ();
4989 NormalizeDialog dialog (rs.size() > 1);
4991 if (dialog.run () == RESPONSE_CANCEL) {
4995 CursorContext::Handle cursor_ctx = CursorContext::create(*this, _cursors->wait);
4998 /* XXX: should really only count audio regions here */
4999 int const regions = rs.size ();
5001 /* Make a list of the selected audio regions' maximum amplitudes, and also
5002 obtain the maximum amplitude of them all.
5004 list<double> max_amps;
5006 for (RegionSelection::const_iterator i = rs.begin(); i != rs.end(); ++i) {
5007 AudioRegionView const * arv = dynamic_cast<AudioRegionView const *> (*i);
5009 dialog.descend (1.0 / regions);
5010 double const a = arv->audio_region()->maximum_amplitude (&dialog);
5013 /* the user cancelled the operation */
5017 max_amps.push_back (a);
5018 max_amp = max (max_amp, a);
5023 list<double>::const_iterator a = max_amps.begin ();
5024 bool in_command = false;
5026 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
5027 AudioRegionView* const arv = dynamic_cast<AudioRegionView*> (*r);
5032 arv->region()->clear_changes ();
5034 double const amp = dialog.normalize_individually() ? *a : max_amp;
5036 arv->audio_region()->normalize (amp, dialog.target ());
5039 begin_reversible_command (_("normalize"));
5042 _session->add_command (new StatefulDiffCommand (arv->region()));
5048 commit_reversible_command ();
5054 Editor::reset_region_scale_amplitude ()
5060 RegionSelection rs = get_regions_from_selection_and_entered ();
5066 bool in_command = false;
5068 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
5069 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
5072 arv->region()->clear_changes ();
5073 arv->audio_region()->set_scale_amplitude (1.0f);
5076 begin_reversible_command ("reset gain");
5079 _session->add_command (new StatefulDiffCommand (arv->region()));
5083 commit_reversible_command ();
5088 Editor::adjust_region_gain (bool up)
5090 RegionSelection rs = get_regions_from_selection_and_entered ();
5092 if (!_session || rs.empty()) {
5096 bool in_command = false;
5098 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
5099 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
5104 arv->region()->clear_changes ();
5106 double dB = accurate_coefficient_to_dB (arv->audio_region()->scale_amplitude ());
5114 arv->audio_region()->set_scale_amplitude (dB_to_coefficient (dB));
5117 begin_reversible_command ("adjust region gain");
5120 _session->add_command (new StatefulDiffCommand (arv->region()));
5124 commit_reversible_command ();
5130 Editor::reverse_region ()
5136 Reverse rev (*_session);
5137 apply_filter (rev, _("reverse regions"));
5141 Editor::strip_region_silence ()
5147 RegionSelection rs = get_regions_from_selection_and_entered ();
5153 std::list<RegionView*> audio_only;
5155 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5156 AudioRegionView* const arv = dynamic_cast<AudioRegionView*> (*i);
5158 audio_only.push_back (arv);
5162 assert (!audio_only.empty());
5164 StripSilenceDialog d (_session, audio_only);
5165 int const r = d.run ();
5169 if (r == Gtk::RESPONSE_OK) {
5170 ARDOUR::AudioIntervalMap silences;
5171 d.silences (silences);
5172 StripSilence s (*_session, silences, d.fade_length());
5174 apply_filter (s, _("strip silence"), &d);
5179 Editor::apply_midi_note_edit_op_to_region (MidiOperator& op, MidiRegionView& mrv)
5181 Evoral::Sequence<Evoral::Beats>::Notes selected;
5182 mrv.selection_as_notelist (selected, true);
5184 vector<Evoral::Sequence<Evoral::Beats>::Notes> v;
5185 v.push_back (selected);
5187 framepos_t pos_frames = mrv.midi_region()->position() - mrv.midi_region()->start();
5188 Evoral::Beats pos_beats = _session->tempo_map().framewalk_to_beats(0, pos_frames);
5190 return op (mrv.midi_region()->model(), pos_beats, v);
5194 Editor::apply_midi_note_edit_op (MidiOperator& op, const RegionSelection& rs)
5200 bool in_command = false;
5202 for (RegionSelection::const_iterator r = rs.begin(); r != rs.end(); ) {
5203 RegionSelection::const_iterator tmp = r;
5206 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*r);
5209 Command* cmd = apply_midi_note_edit_op_to_region (op, *mrv);
5212 begin_reversible_command (op.name ());
5216 _session->add_command (cmd);
5224 commit_reversible_command ();
5229 Editor::fork_region ()
5231 RegionSelection rs = get_regions_from_selection_and_entered ();
5237 CursorContext::Handle cursor_ctx = CursorContext::create(*this, _cursors->wait);
5238 bool in_command = false;
5242 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
5243 RegionSelection::iterator tmp = r;
5246 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*>(*r);
5250 boost::shared_ptr<Playlist> playlist = mrv->region()->playlist();
5251 boost::shared_ptr<MidiSource> new_source = _session->create_midi_source_by_stealing_name (mrv->midi_view()->track());
5252 boost::shared_ptr<MidiRegion> newregion = mrv->midi_region()->clone (new_source);
5255 begin_reversible_command (_("Fork Region(s)"));
5258 playlist->clear_changes ();
5259 playlist->replace_region (mrv->region(), newregion, mrv->region()->position());
5260 _session->add_command(new StatefulDiffCommand (playlist));
5262 error << string_compose (_("Could not unlink %1"), mrv->region()->name()) << endmsg;
5270 commit_reversible_command ();
5275 Editor::quantize_region ()
5278 quantize_regions(get_regions_from_selection_and_entered ());
5283 Editor::quantize_regions (const RegionSelection& rs)
5285 if (rs.n_midi_regions() == 0) {
5289 if (!quantize_dialog) {
5290 quantize_dialog = new QuantizeDialog (*this);
5293 quantize_dialog->present ();
5294 const int r = quantize_dialog->run ();
5295 quantize_dialog->hide ();
5297 if (r == Gtk::RESPONSE_OK) {
5298 Quantize quant (quantize_dialog->snap_start(),
5299 quantize_dialog->snap_end(),
5300 quantize_dialog->start_grid_size(),
5301 quantize_dialog->end_grid_size(),
5302 quantize_dialog->strength(),
5303 quantize_dialog->swing(),
5304 quantize_dialog->threshold());
5306 apply_midi_note_edit_op (quant, rs);
5311 Editor::legatize_region (bool shrink_only)
5314 legatize_regions(get_regions_from_selection_and_entered (), shrink_only);
5319 Editor::legatize_regions (const RegionSelection& rs, bool shrink_only)
5321 if (rs.n_midi_regions() == 0) {
5325 Legatize legatize(shrink_only);
5326 apply_midi_note_edit_op (legatize, rs);
5330 Editor::transform_region ()
5333 transform_regions(get_regions_from_selection_and_entered ());
5338 Editor::transform_regions (const RegionSelection& rs)
5340 if (rs.n_midi_regions() == 0) {
5347 const int r = td.run();
5350 if (r == Gtk::RESPONSE_OK) {
5351 Transform transform(td.get());
5352 apply_midi_note_edit_op(transform, rs);
5357 Editor::transpose_region ()
5360 transpose_regions(get_regions_from_selection_and_entered ());
5365 Editor::transpose_regions (const RegionSelection& rs)
5367 if (rs.n_midi_regions() == 0) {
5372 int const r = d.run ();
5374 if (r == RESPONSE_ACCEPT) {
5375 Transpose transpose(d.semitones ());
5376 apply_midi_note_edit_op (transpose, rs);
5381 Editor::insert_patch_change (bool from_context)
5383 RegionSelection rs = get_regions_from_selection_and_entered ();
5389 const framepos_t p = get_preferred_edit_position (EDIT_IGNORE_NONE, from_context);
5391 /* XXX: bit of a hack; use the MIDNAM from the first selected region;
5392 there may be more than one, but the PatchChangeDialog can only offer
5393 one set of patch menus.
5395 MidiRegionView* first = dynamic_cast<MidiRegionView*> (rs.front ());
5397 Evoral::PatchChange<Evoral::Beats> empty (Evoral::Beats(), 0, 0, 0);
5398 PatchChangeDialog d (0, _session, empty, first->instrument_info(), Gtk::Stock::ADD);
5400 if (d.run() == RESPONSE_CANCEL) {
5404 for (RegionSelection::iterator i = rs.begin (); i != rs.end(); ++i) {
5405 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*i);
5407 if (p >= mrv->region()->first_frame() && p <= mrv->region()->last_frame()) {
5408 mrv->add_patch_change (p - mrv->region()->position(), d.patch ());
5415 Editor::apply_filter (Filter& filter, string command, ProgressReporter* progress)
5417 RegionSelection rs = get_regions_from_selection_and_entered ();
5423 CursorContext::Handle cursor_ctx = CursorContext::create(*this, _cursors->wait);
5424 bool in_command = false;
5429 int const N = rs.size ();
5431 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
5432 RegionSelection::iterator tmp = r;
5435 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
5437 boost::shared_ptr<Playlist> playlist = arv->region()->playlist();
5440 progress->descend (1.0 / N);
5443 if (arv->audio_region()->apply (filter, progress) == 0) {
5445 playlist->clear_changes ();
5446 playlist->clear_owned_changes ();
5449 begin_reversible_command (command);
5453 if (filter.results.empty ()) {
5455 /* no regions returned; remove the old one */
5456 playlist->remove_region (arv->region ());
5460 std::vector<boost::shared_ptr<Region> >::iterator res = filter.results.begin ();
5462 /* first region replaces the old one */
5463 playlist->replace_region (arv->region(), *res, (*res)->position());
5467 while (res != filter.results.end()) {
5468 playlist->add_region (*res, (*res)->position());
5474 /* We might have removed regions, which alters other regions' layering_index,
5475 so we need to do a recursive diff here.
5477 vector<Command*> cmds;
5478 playlist->rdiff (cmds);
5479 _session->add_commands (cmds);
5481 _session->add_command(new StatefulDiffCommand (playlist));
5485 progress->ascend ();
5494 commit_reversible_command ();
5499 Editor::external_edit_region ()
5505 Editor::reset_region_gain_envelopes ()
5507 RegionSelection rs = get_regions_from_selection_and_entered ();
5509 if (!_session || rs.empty()) {
5513 bool in_command = false;
5515 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5516 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
5518 boost::shared_ptr<AutomationList> alist (arv->audio_region()->envelope());
5519 XMLNode& before (alist->get_state());
5521 arv->audio_region()->set_default_envelope ();
5524 begin_reversible_command (_("reset region gain"));
5527 _session->add_command (new MementoCommand<AutomationList>(*arv->audio_region()->envelope().get(), &before, &alist->get_state()));
5532 commit_reversible_command ();
5537 Editor::set_region_gain_visibility (RegionView* rv)
5539 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (rv);
5541 arv->update_envelope_visibility();
5546 Editor::set_gain_envelope_visibility ()
5552 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5553 AudioTimeAxisView* v = dynamic_cast<AudioTimeAxisView*>(*i);
5555 v->audio_view()->foreach_regionview (sigc::mem_fun (this, &Editor::set_region_gain_visibility));
5561 Editor::toggle_gain_envelope_active ()
5563 if (_ignore_region_action) {
5567 RegionSelection rs = get_regions_from_selection_and_entered ();
5569 if (!_session || rs.empty()) {
5573 bool in_command = false;
5575 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5576 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
5578 arv->region()->clear_changes ();
5579 arv->audio_region()->set_envelope_active (!arv->audio_region()->envelope_active());
5582 begin_reversible_command (_("region gain envelope active"));
5585 _session->add_command (new StatefulDiffCommand (arv->region()));
5590 commit_reversible_command ();
5595 Editor::toggle_region_lock ()
5597 if (_ignore_region_action) {
5601 RegionSelection rs = get_regions_from_selection_and_entered ();
5603 if (!_session || rs.empty()) {
5607 begin_reversible_command (_("toggle region lock"));
5609 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5610 (*i)->region()->clear_changes ();
5611 (*i)->region()->set_locked (!(*i)->region()->locked());
5612 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5615 commit_reversible_command ();
5619 Editor::toggle_region_video_lock ()
5621 if (_ignore_region_action) {
5625 RegionSelection rs = get_regions_from_selection_and_entered ();
5627 if (!_session || rs.empty()) {
5631 begin_reversible_command (_("Toggle Video Lock"));
5633 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5634 (*i)->region()->clear_changes ();
5635 (*i)->region()->set_video_locked (!(*i)->region()->video_locked());
5636 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5639 commit_reversible_command ();
5643 Editor::toggle_region_lock_style ()
5645 if (_ignore_region_action) {
5649 RegionSelection rs = get_regions_from_selection_and_entered ();
5651 if (!_session || rs.empty()) {
5655 begin_reversible_command (_("region lock style"));
5657 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5658 (*i)->region()->clear_changes ();
5659 PositionLockStyle const ns = (*i)->region()->position_lock_style() == AudioTime ? MusicTime : AudioTime;
5660 (*i)->region()->set_position_lock_style (ns);
5661 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5664 commit_reversible_command ();
5668 Editor::toggle_opaque_region ()
5670 if (_ignore_region_action) {
5674 RegionSelection rs = get_regions_from_selection_and_entered ();
5676 if (!_session || rs.empty()) {
5680 begin_reversible_command (_("change region opacity"));
5682 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5683 (*i)->region()->clear_changes ();
5684 (*i)->region()->set_opaque (!(*i)->region()->opaque());
5685 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5688 commit_reversible_command ();
5692 Editor::toggle_record_enable ()
5694 bool new_state = false;
5696 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5697 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5700 if (!rtav->is_track())
5704 new_state = !rtav->track()->rec_enable_control()->get_value();
5708 rtav->track()->rec_enable_control()->set_value (new_state, Controllable::UseGroup);
5713 Editor::toggle_solo ()
5715 bool new_state = false;
5717 boost::shared_ptr<ControlList> cl (new ControlList);
5719 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5720 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5727 new_state = !rtav->route()->soloed ();
5731 cl->push_back (rtav->route()->solo_control());
5734 _session->set_controls (cl, new_state ? 1.0 : 0.0, Controllable::UseGroup);
5738 Editor::toggle_mute ()
5740 bool new_state = false;
5742 boost::shared_ptr<RouteList> rl (new RouteList);
5744 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5745 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5752 new_state = !rtav->route()->muted();
5756 rl->push_back (rtav->route());
5759 _session->set_controls (route_list_to_control_list (rl, &Stripable::mute_control), new_state, Controllable::UseGroup);
5763 Editor::toggle_solo_isolate ()
5769 Editor::fade_range ()
5771 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
5773 begin_reversible_command (_("fade range"));
5775 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
5776 (*i)->fade_range (selection->time);
5779 commit_reversible_command ();
5784 Editor::set_fade_length (bool in)
5786 RegionSelection rs = get_regions_from_selection_and_entered ();
5792 /* we need a region to measure the offset from the start */
5794 RegionView* rv = rs.front ();
5796 framepos_t pos = get_preferred_edit_position();
5800 if (pos > rv->region()->last_frame() || pos < rv->region()->first_frame()) {
5801 /* edit point is outside the relevant region */
5806 if (pos <= rv->region()->position()) {
5810 len = pos - rv->region()->position();
5811 cmd = _("set fade in length");
5813 if (pos >= rv->region()->last_frame()) {
5817 len = rv->region()->last_frame() - pos;
5818 cmd = _("set fade out length");
5821 bool in_command = false;
5823 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5824 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5830 boost::shared_ptr<AutomationList> alist;
5832 alist = tmp->audio_region()->fade_in();
5834 alist = tmp->audio_region()->fade_out();
5837 XMLNode &before = alist->get_state();
5840 tmp->audio_region()->set_fade_in_length (len);
5841 tmp->audio_region()->set_fade_in_active (true);
5843 tmp->audio_region()->set_fade_out_length (len);
5844 tmp->audio_region()->set_fade_out_active (true);
5848 begin_reversible_command (cmd);
5851 XMLNode &after = alist->get_state();
5852 _session->add_command(new MementoCommand<AutomationList>(*alist, &before, &after));
5856 commit_reversible_command ();
5861 Editor::set_fade_in_shape (FadeShape shape)
5863 RegionSelection rs = get_regions_from_selection_and_entered ();
5868 bool in_command = false;
5870 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5871 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5877 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_in();
5878 XMLNode &before = alist->get_state();
5880 tmp->audio_region()->set_fade_in_shape (shape);
5883 begin_reversible_command (_("set fade in shape"));
5886 XMLNode &after = alist->get_state();
5887 _session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
5891 commit_reversible_command ();
5896 Editor::set_fade_out_shape (FadeShape shape)
5898 RegionSelection rs = get_regions_from_selection_and_entered ();
5903 bool in_command = false;
5905 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5906 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5912 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_out();
5913 XMLNode &before = alist->get_state();
5915 tmp->audio_region()->set_fade_out_shape (shape);
5918 begin_reversible_command (_("set fade out shape"));
5921 XMLNode &after = alist->get_state();
5922 _session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
5926 commit_reversible_command ();
5931 Editor::set_fade_in_active (bool yn)
5933 RegionSelection rs = get_regions_from_selection_and_entered ();
5938 bool in_command = false;
5940 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5941 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5948 boost::shared_ptr<AudioRegion> ar (tmp->audio_region());
5950 ar->clear_changes ();
5951 ar->set_fade_in_active (yn);
5954 begin_reversible_command (_("set fade in active"));
5957 _session->add_command (new StatefulDiffCommand (ar));
5961 commit_reversible_command ();
5966 Editor::set_fade_out_active (bool yn)
5968 RegionSelection rs = get_regions_from_selection_and_entered ();
5973 bool in_command = false;
5975 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5976 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5982 boost::shared_ptr<AudioRegion> ar (tmp->audio_region());
5984 ar->clear_changes ();
5985 ar->set_fade_out_active (yn);
5988 begin_reversible_command (_("set fade out active"));
5991 _session->add_command(new StatefulDiffCommand (ar));
5995 commit_reversible_command ();
6000 Editor::toggle_region_fades (int dir)
6002 if (_ignore_region_action) {
6006 boost::shared_ptr<AudioRegion> ar;
6009 RegionSelection rs = get_regions_from_selection_and_entered ();
6015 RegionSelection::iterator i;
6016 for (i = rs.begin(); i != rs.end(); ++i) {
6017 if ((ar = boost::dynamic_pointer_cast<AudioRegion>((*i)->region())) != 0) {
6019 yn = ar->fade_out_active ();
6021 yn = ar->fade_in_active ();
6027 if (i == rs.end()) {
6031 /* XXX should this undo-able? */
6032 bool in_command = false;
6034 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
6035 if ((ar = boost::dynamic_pointer_cast<AudioRegion>((*i)->region())) == 0) {
6038 ar->clear_changes ();
6040 if (dir == 1 || dir == 0) {
6041 ar->set_fade_in_active (!yn);
6044 if (dir == -1 || dir == 0) {
6045 ar->set_fade_out_active (!yn);
6048 begin_reversible_command (_("toggle fade active"));
6051 _session->add_command(new StatefulDiffCommand (ar));
6055 commit_reversible_command ();
6060 /** Update region fade visibility after its configuration has been changed */
6062 Editor::update_region_fade_visibility ()
6064 bool _fade_visibility = _session->config.get_show_region_fades ();
6066 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
6067 AudioTimeAxisView* v = dynamic_cast<AudioTimeAxisView*>(*i);
6069 if (_fade_visibility) {
6070 v->audio_view()->show_all_fades ();
6072 v->audio_view()->hide_all_fades ();
6079 Editor::set_edit_point ()
6084 if (!mouse_frame (where, ignored)) {
6090 if (selection->markers.empty()) {
6092 mouse_add_new_marker (where);
6097 Location* loc = find_location_from_marker (selection->markers.front(), ignored);
6100 loc->move_to (where);
6106 Editor::set_playhead_cursor ()
6108 if (entered_marker) {
6109 _session->request_locate (entered_marker->position(), _session->transport_rolling());
6114 if (!mouse_frame (where, ignored)) {
6121 _session->request_locate (where, _session->transport_rolling());
6125 if (UIConfiguration::instance().get_follow_edits() && (!_session || !_session->config.get_external_sync())) {
6126 cancel_time_selection();
6131 Editor::split_region ()
6133 if (_drags->active ()) {
6137 //if a range is selected, separate it
6138 if ( !selection->time.empty()) {
6139 separate_regions_between (selection->time);
6143 //if no range was selected, try to find some regions to split
6144 if (current_mouse_mode() == MouseObject) { //don't try this for Internal Edit, Stretch, Draw, etc.
6146 RegionSelection rs = get_regions_from_selection_and_edit_point ();
6148 framepos_t where = get_preferred_edit_position ();
6154 if (snap_musical()) {
6155 split_regions_at (where, rs, get_grid_music_divisions (0));
6157 split_regions_at (where, rs, 0);
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) {
6176 if (*i == current) {
6178 if (i != track_views.end()) {
6181 current = (*(track_views.begin()));
6182 //selection->set (*(track_views.begin()));
6188 rui = dynamic_cast<RouteUI *>(current);
6190 } while (current->hidden() || (rui == NULL) || !rui->route()->active());
6192 selection->set (current);
6194 ensure_time_axis_view_is_visible (*current, false);
6198 Editor::select_prev_route()
6200 if (selection->tracks.empty()) {
6201 selection->set (track_views.front());
6205 TimeAxisView* current = selection->tracks.front();
6209 for (TrackViewList::reverse_iterator i = track_views.rbegin(); i != track_views.rend(); ++i) {
6211 if (*i == current) {
6213 if (i != track_views.rend()) {
6216 current = *(track_views.rbegin());
6221 rui = dynamic_cast<RouteUI *>(current);
6223 } while (current->hidden() || (rui == NULL) || !rui->route()->active());
6225 selection->set (current);
6227 ensure_time_axis_view_is_visible (*current, false);
6231 Editor::set_loop_from_selection (bool play)
6233 if (_session == 0) {
6237 framepos_t start, end;
6238 if (!get_selection_extents ( start, end))
6241 set_loop_range (start, end, _("set loop range from selection"));
6244 _session->request_play_loop (true, true);
6249 Editor::set_loop_from_region (bool play)
6251 framepos_t start, end;
6252 if (!get_selection_extents ( start, end))
6255 set_loop_range (start, end, _("set loop range from region"));
6258 _session->request_locate (start, true);
6259 _session->request_play_loop (true);
6264 Editor::set_punch_from_selection ()
6266 if (_session == 0) {
6270 framepos_t start, end;
6271 if (!get_selection_extents ( start, end))
6274 set_punch_range (start, end, _("set punch range from selection"));
6278 Editor::set_session_extents_from_selection ()
6280 if (_session == 0) {
6284 framepos_t start, end;
6285 if (!get_selection_extents ( start, end))
6289 if ((loc = _session->locations()->session_range_location()) == 0) {
6290 _session->set_session_extents ( start, end ); // this will create a new session range; no need for UNDO
6292 XMLNode &before = loc->get_state();
6294 _session->set_session_extents ( start, end );
6296 XMLNode &after = loc->get_state();
6298 begin_reversible_command (_("set session start/end from selection"));
6300 _session->add_command (new MementoCommand<Location>(*loc, &before, &after));
6302 commit_reversible_command ();
6307 Editor::set_punch_start_from_edit_point ()
6311 framepos_t start = 0;
6312 framepos_t end = max_framepos;
6314 //use the existing punch end, if any
6315 Location* tpl = transport_punch_location();
6320 if ((_edit_point == EditAtPlayhead) && _session->transport_rolling()) {
6321 start = _session->audible_frame();
6323 start = get_preferred_edit_position();
6326 //snap the selection start/end
6329 //if there's not already a sensible selection endpoint, go "forever"
6330 if ( start > end ) {
6334 set_punch_range (start, end, _("set punch start from EP"));
6340 Editor::set_punch_end_from_edit_point ()
6344 framepos_t start = 0;
6345 framepos_t end = max_framepos;
6347 //use the existing punch start, if any
6348 Location* tpl = transport_punch_location();
6350 start = tpl->start();
6353 if ((_edit_point == EditAtPlayhead) && _session->transport_rolling()) {
6354 end = _session->audible_frame();
6356 end = get_preferred_edit_position();
6359 //snap the selection start/end
6362 set_punch_range (start, end, _("set punch end from EP"));
6368 Editor::set_loop_start_from_edit_point ()
6372 framepos_t start = 0;
6373 framepos_t end = max_framepos;
6375 //use the existing loop end, if any
6376 Location* tpl = transport_loop_location();
6381 if ((_edit_point == EditAtPlayhead) && _session->transport_rolling()) {
6382 start = _session->audible_frame();
6384 start = get_preferred_edit_position();
6387 //snap the selection start/end
6390 //if there's not already a sensible selection endpoint, go "forever"
6391 if ( start > end ) {
6395 set_loop_range (start, end, _("set loop start from EP"));
6401 Editor::set_loop_end_from_edit_point ()
6405 framepos_t start = 0;
6406 framepos_t end = max_framepos;
6408 //use the existing loop start, if any
6409 Location* tpl = transport_loop_location();
6411 start = tpl->start();
6414 if ((_edit_point == EditAtPlayhead) && _session->transport_rolling()) {
6415 end = _session->audible_frame();
6417 end = get_preferred_edit_position();
6420 //snap the selection start/end
6423 set_loop_range (start, end, _("set loop end from EP"));
6428 Editor::set_punch_from_region ()
6430 framepos_t start, end;
6431 if (!get_selection_extents ( start, end))
6434 set_punch_range (start, end, _("set punch range from region"));
6438 Editor::pitch_shift_region ()
6440 RegionSelection rs = get_regions_from_selection_and_entered ();
6442 RegionSelection audio_rs;
6443 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
6444 if (dynamic_cast<AudioRegionView*> (*i)) {
6445 audio_rs.push_back (*i);
6449 if (audio_rs.empty()) {
6453 pitch_shift (audio_rs, 1.2);
6457 Editor::set_tempo_from_region ()
6459 RegionSelection rs = get_regions_from_selection_and_entered ();
6461 if (!_session || rs.empty()) {
6465 RegionView* rv = rs.front();
6467 define_one_bar (rv->region()->position(), rv->region()->last_frame() + 1);
6471 Editor::use_range_as_bar ()
6473 framepos_t start, end;
6474 if (get_edit_op_range (start, end)) {
6475 define_one_bar (start, end);
6480 Editor::define_one_bar (framepos_t start, framepos_t end)
6482 framepos_t length = end - start;
6484 const Meter& m (_session->tempo_map().meter_at_frame (start));
6486 /* length = 1 bar */
6488 /* We're going to deliver a constant tempo here,
6489 so we can use frames per beat to determine length.
6490 now we want frames per beat.
6491 we have frames per bar, and beats per bar, so ...
6494 /* XXXX METER MATH */
6496 double frames_per_beat = length / m.divisions_per_bar();
6498 /* beats per minute = */
6500 double beats_per_minute = (_session->frame_rate() * 60.0) / frames_per_beat;
6502 /* now decide whether to:
6504 (a) set global tempo
6505 (b) add a new tempo marker
6509 const TempoSection& t (_session->tempo_map().tempo_section_at_frame (start));
6511 bool do_global = false;
6513 if ((_session->tempo_map().n_tempos() == 1) && (_session->tempo_map().n_meters() == 1)) {
6515 /* only 1 tempo & 1 meter: ask if the user wants to set the tempo
6516 at the start, or create a new marker
6519 vector<string> options;
6520 options.push_back (_("Cancel"));
6521 options.push_back (_("Add new marker"));
6522 options.push_back (_("Set global tempo"));
6525 _("Define one bar"),
6526 _("Do you want to set the global tempo or add a new tempo marker?"),
6530 c.set_default_response (2);
6546 /* more than 1 tempo and/or meter section already, go ahead do the "usual":
6547 if the marker is at the region starter, change it, otherwise add
6552 begin_reversible_command (_("set tempo from region"));
6553 XMLNode& before (_session->tempo_map().get_state());
6556 _session->tempo_map().change_initial_tempo (beats_per_minute, t.note_type());
6557 } else if (t.frame() == start) {
6558 _session->tempo_map().change_existing_tempo_at (start, beats_per_minute, t.note_type());
6560 _session->tempo_map().add_tempo (Tempo (beats_per_minute, t.note_type()), 0.0, start, TempoSection::Constant, AudioTime);
6563 XMLNode& after (_session->tempo_map().get_state());
6565 _session->add_command (new MementoCommand<TempoMap>(_session->tempo_map(), &before, &after));
6566 commit_reversible_command ();
6570 Editor::split_region_at_transients ()
6572 AnalysisFeatureList positions;
6574 RegionSelection rs = get_regions_from_selection_and_entered ();
6576 if (!_session || rs.empty()) {
6580 begin_reversible_command (_("split regions"));
6582 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ) {
6584 RegionSelection::iterator tmp;
6589 boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion> ((*i)->region());
6592 ar->transients (positions);
6593 split_region_at_points ((*i)->region(), positions, true);
6600 commit_reversible_command ();
6605 Editor::split_region_at_points (boost::shared_ptr<Region> r, AnalysisFeatureList& positions, bool can_ferret, bool select_new)
6607 bool use_rhythmic_rodent = false;
6609 boost::shared_ptr<Playlist> pl = r->playlist();
6611 list<boost::shared_ptr<Region> > new_regions;
6617 if (positions.empty()) {
6621 if (positions.size() > 20 && can_ferret) {
6622 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);
6623 MessageDialog msg (msgstr,
6626 Gtk::BUTTONS_OK_CANCEL);
6629 msg.add_button (_("Call for the Ferret!"), RESPONSE_APPLY);
6630 msg.set_secondary_text (_("Press OK to continue with this split operation\nor ask the Ferret dialog to tune the analysis"));
6632 msg.set_secondary_text (_("Press OK to continue with this split operation"));
6635 msg.set_title (_("Excessive split?"));
6638 int response = msg.run();
6644 case RESPONSE_APPLY:
6645 use_rhythmic_rodent = true;
6652 if (use_rhythmic_rodent) {
6653 show_rhythm_ferret ();
6657 AnalysisFeatureList::const_iterator x;
6659 pl->clear_changes ();
6660 pl->clear_owned_changes ();
6662 x = positions.begin();
6664 if (x == positions.end()) {
6669 pl->remove_region (r);
6673 framepos_t rstart = r->first_frame ();
6674 framepos_t rend = r->last_frame ();
6676 while (x != positions.end()) {
6678 /* deal with positons that are out of scope of present region bounds */
6679 if (*x <= rstart || *x > rend) {
6684 /* file start = original start + how far we from the initial position ? */
6686 framepos_t file_start = r->start() + pos;
6688 /* length = next position - current position */
6690 framepos_t len = (*x) - pos - rstart;
6692 /* XXX we do we really want to allow even single-sample regions?
6693 * shouldn't we have some kind of lower limit on region size?
6702 if (RegionFactory::region_name (new_name, r->name())) {
6706 /* do NOT announce new regions 1 by one, just wait till they are all done */
6710 plist.add (ARDOUR::Properties::start, file_start);
6711 plist.add (ARDOUR::Properties::length, len);
6712 plist.add (ARDOUR::Properties::name, new_name);
6713 plist.add (ARDOUR::Properties::layer, 0);
6714 // TODO set transients_offset
6716 boost::shared_ptr<Region> nr = RegionFactory::create (r->sources(), plist, false);
6717 /* because we set annouce to false, manually add the new region to the
6720 RegionFactory::map_add (nr);
6722 pl->add_region (nr, rstart + pos);
6725 new_regions.push_front(nr);
6734 RegionFactory::region_name (new_name, r->name());
6736 /* Add the final region */
6739 plist.add (ARDOUR::Properties::start, r->start() + pos);
6740 plist.add (ARDOUR::Properties::length, r->last_frame() - (r->position() + pos) + 1);
6741 plist.add (ARDOUR::Properties::name, new_name);
6742 plist.add (ARDOUR::Properties::layer, 0);
6744 boost::shared_ptr<Region> nr = RegionFactory::create (r->sources(), plist, false);
6745 /* because we set annouce to false, manually add the new region to the
6748 RegionFactory::map_add (nr);
6749 pl->add_region (nr, r->position() + pos);
6752 new_regions.push_front(nr);
6757 /* We might have removed regions, which alters other regions' layering_index,
6758 so we need to do a recursive diff here.
6760 vector<Command*> cmds;
6762 _session->add_commands (cmds);
6764 _session->add_command (new StatefulDiffCommand (pl));
6768 for (list<boost::shared_ptr<Region> >::iterator i = new_regions.begin(); i != new_regions.end(); ++i){
6769 set_selected_regionview_from_region_list ((*i), Selection::Add);
6775 Editor::place_transient()
6781 RegionSelection rs = get_regions_from_selection_and_edit_point ();
6787 framepos_t where = get_preferred_edit_position();
6789 begin_reversible_command (_("place transient"));
6791 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6792 (*r)->region()->add_transient(where);
6795 commit_reversible_command ();
6799 Editor::remove_transient(ArdourCanvas::Item* item)
6805 ArdourCanvas::Line* _line = reinterpret_cast<ArdourCanvas::Line*> (item);
6808 AudioRegionView* _arv = reinterpret_cast<AudioRegionView*> (item->get_data ("regionview"));
6809 _arv->remove_transient (*(float*) _line->get_data ("position"));
6813 Editor::snap_regions_to_grid ()
6815 list <boost::shared_ptr<Playlist > > used_playlists;
6817 RegionSelection rs = get_regions_from_selection_and_entered ();
6819 if (!_session || rs.empty()) {
6823 begin_reversible_command (_("snap regions to grid"));
6825 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6827 boost::shared_ptr<Playlist> pl = (*r)->region()->playlist();
6829 if (!pl->frozen()) {
6830 /* we haven't seen this playlist before */
6832 /* remember used playlists so we can thaw them later */
6833 used_playlists.push_back(pl);
6837 framepos_t start_frame = (*r)->region()->first_frame ();
6838 snap_to (start_frame);
6839 (*r)->region()->set_position (start_frame);
6842 while (used_playlists.size() > 0) {
6843 list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
6845 used_playlists.pop_front();
6848 commit_reversible_command ();
6852 Editor::close_region_gaps ()
6854 list <boost::shared_ptr<Playlist > > used_playlists;
6856 RegionSelection rs = get_regions_from_selection_and_entered ();
6858 if (!_session || rs.empty()) {
6862 Dialog dialog (_("Close Region Gaps"));
6865 table.set_spacings (12);
6866 table.set_border_width (12);
6867 Label* l = manage (left_aligned_label (_("Crossfade length")));
6868 table.attach (*l, 0, 1, 0, 1);
6870 SpinButton spin_crossfade (1, 0);
6871 spin_crossfade.set_range (0, 15);
6872 spin_crossfade.set_increments (1, 1);
6873 spin_crossfade.set_value (5);
6874 table.attach (spin_crossfade, 1, 2, 0, 1);
6876 table.attach (*manage (new Label (_("ms"))), 2, 3, 0, 1);
6878 l = manage (left_aligned_label (_("Pull-back length")));
6879 table.attach (*l, 0, 1, 1, 2);
6881 SpinButton spin_pullback (1, 0);
6882 spin_pullback.set_range (0, 100);
6883 spin_pullback.set_increments (1, 1);
6884 spin_pullback.set_value(30);
6885 table.attach (spin_pullback, 1, 2, 1, 2);
6887 table.attach (*manage (new Label (_("ms"))), 2, 3, 1, 2);
6889 dialog.get_vbox()->pack_start (table);
6890 dialog.add_button (Stock::CANCEL, RESPONSE_CANCEL);
6891 dialog.add_button (_("Ok"), RESPONSE_ACCEPT);
6894 if (dialog.run () == RESPONSE_CANCEL) {
6898 framepos_t crossfade_len = spin_crossfade.get_value();
6899 framepos_t pull_back_frames = spin_pullback.get_value();
6901 crossfade_len = lrintf (crossfade_len * _session->frame_rate()/1000);
6902 pull_back_frames = lrintf (pull_back_frames * _session->frame_rate()/1000);
6904 /* Iterate over the region list and make adjacent regions overlap by crossfade_len_ms */
6906 begin_reversible_command (_("close region gaps"));
6909 boost::shared_ptr<Region> last_region;
6911 rs.sort_by_position_and_track();
6913 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6915 boost::shared_ptr<Playlist> pl = (*r)->region()->playlist();
6917 if (!pl->frozen()) {
6918 /* we haven't seen this playlist before */
6920 /* remember used playlists so we can thaw them later */
6921 used_playlists.push_back(pl);
6925 framepos_t position = (*r)->region()->position();
6927 if (idx == 0 || position < last_region->position()){
6928 last_region = (*r)->region();
6933 (*r)->region()->trim_front( (position - pull_back_frames));
6934 last_region->trim_end( (position - pull_back_frames + crossfade_len));
6936 last_region = (*r)->region();
6941 while (used_playlists.size() > 0) {
6942 list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
6944 used_playlists.pop_front();
6947 commit_reversible_command ();
6951 Editor::tab_to_transient (bool forward)
6953 AnalysisFeatureList positions;
6955 RegionSelection rs = get_regions_from_selection_and_entered ();
6961 framepos_t pos = _session->audible_frame ();
6963 if (!selection->tracks.empty()) {
6965 /* don't waste time searching for transients in duplicate playlists.
6968 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
6970 for (TrackViewList::iterator t = ts.begin(); t != ts.end(); ++t) {
6972 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*t);
6975 boost::shared_ptr<Track> tr = rtv->track();
6977 boost::shared_ptr<Playlist> pl = tr->playlist ();
6979 framepos_t result = pl->find_next_transient (pos, forward ? 1 : -1);
6982 positions.push_back (result);
6995 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6996 (*r)->region()->get_transients (positions);
7000 TransientDetector::cleanup_transients (positions, _session->frame_rate(), 3.0);
7003 AnalysisFeatureList::iterator x;
7005 for (x = positions.begin(); x != positions.end(); ++x) {
7011 if (x != positions.end ()) {
7012 _session->request_locate (*x);
7016 AnalysisFeatureList::reverse_iterator x;
7018 for (x = positions.rbegin(); x != positions.rend(); ++x) {
7024 if (x != positions.rend ()) {
7025 _session->request_locate (*x);
7031 Editor::playhead_forward_to_grid ()
7037 framepos_t pos = playhead_cursor->current_frame ();
7038 if (pos < max_framepos - 1) {
7040 snap_to_internal (pos, RoundUpAlways, false);
7041 _session->request_locate (pos);
7047 Editor::playhead_backward_to_grid ()
7053 framepos_t pos = playhead_cursor->current_frame ();
7056 snap_to_internal (pos, RoundDownAlways, false);
7057 _session->request_locate (pos);
7062 Editor::set_track_height (Height h)
7064 TrackSelection& ts (selection->tracks);
7066 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
7067 (*x)->set_height_enum (h);
7072 Editor::toggle_tracks_active ()
7074 TrackSelection& ts (selection->tracks);
7076 bool target = false;
7082 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
7083 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*x);
7087 target = !rtv->_route->active();
7090 rtv->_route->set_active (target, this);
7096 Editor::remove_tracks ()
7098 /* this will delete GUI objects that may be the subject of an event
7099 handler in which this method is called. Defer actual deletion to the
7100 next idle callback, when all event handling is finished.
7102 Glib::signal_idle().connect (sigc::mem_fun (*this, &Editor::idle_remove_tracks));
7106 Editor::idle_remove_tracks ()
7108 Session::StateProtector sp (_session);
7110 return false; /* do not call again */
7114 Editor::_remove_tracks ()
7116 TrackSelection& ts (selection->tracks);
7122 vector<string> choices;
7126 const char* trackstr;
7128 vector<boost::shared_ptr<Route> > routes;
7129 bool special_bus = false;
7131 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
7132 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*x);
7136 if (rtv->is_track()) {
7141 routes.push_back (rtv->_route);
7143 if (rtv->route()->is_master() || rtv->route()->is_monitor()) {
7148 if (special_bus && !Config->get_allow_special_bus_removal()) {
7149 MessageDialog msg (_("That would be bad news ...."),
7153 msg.set_secondary_text (string_compose (_(
7154 "Removing the master or monitor bus is such a bad idea\n\
7155 that %1 is not going to allow it.\n\
7157 If you really want to do this sort of thing\n\
7158 edit your ardour.rc file to set the\n\
7159 \"allow-special-bus-removal\" option to be \"yes\""), PROGRAM_NAME));
7166 if (ntracks + nbusses == 0) {
7170 trackstr = P_("track", "tracks", ntracks);
7171 busstr = P_("bus", "busses", nbusses);
7175 prompt = string_compose (_("Do you really want to remove %1 %2 and %3 %4?\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!"),
7178 ntracks, trackstr, nbusses, busstr);
7180 prompt = string_compose (_("Do you really want to remove %1 %2?\n"
7181 "(You may also lose the playlists associated with the %2)\n\n"
7182 "This action cannot be undone, and the session file will be overwritten!"),
7185 } else if (nbusses) {
7186 prompt = string_compose (_("Do you really want to remove %1 %2?\n\n"
7187 "This action cannot be undone, and the session file will be overwritten"),
7191 choices.push_back (_("No, do nothing."));
7192 if (ntracks + nbusses > 1) {
7193 choices.push_back (_("Yes, remove them."));
7195 choices.push_back (_("Yes, remove it."));
7200 title = string_compose (_("Remove %1"), trackstr);
7202 title = string_compose (_("Remove %1"), busstr);
7205 Choice prompter (title, prompt, choices);
7207 if (prompter.run () != 1) {
7212 DisplaySuspender ds;
7213 boost::shared_ptr<RouteList> rl (new RouteList);
7214 for (vector<boost::shared_ptr<Route> >::iterator x = routes.begin(); x != routes.end(); ++x) {
7217 _session->remove_routes (rl);
7219 /* TrackSelection and RouteList leave scope,
7220 * destructors are called,
7221 * diskstream drops references, save_state is called (again for every track)
7226 Editor::do_insert_time ()
7228 if (selection->tracks.empty()) {
7232 InsertRemoveTimeDialog d (*this);
7233 int response = d.run ();
7235 if (response != RESPONSE_OK) {
7239 if (d.distance() == 0) {
7244 get_preferred_edit_position (EDIT_IGNORE_MOUSE),
7246 d.intersected_region_action (),
7250 d.move_glued_markers(),
7251 d.move_locked_markers(),
7257 Editor::insert_time (
7258 framepos_t pos, framecnt_t frames, InsertTimeOption opt,
7259 bool all_playlists, bool ignore_music_glue, bool markers_too, bool glued_markers_too, bool locked_markers_too, bool tempo_too
7263 if (Config->get_edit_mode() == Lock) {
7266 bool in_command = false;
7268 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
7270 for (TrackViewList::iterator x = ts.begin(); x != ts.end(); ++x) {
7274 /* don't operate on any playlist more than once, which could
7275 * happen if "all playlists" is enabled, but there is more
7276 * than 1 track using playlists "from" a given track.
7279 set<boost::shared_ptr<Playlist> > pl;
7281 if (all_playlists) {
7282 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*x);
7283 if (rtav && rtav->track ()) {
7284 vector<boost::shared_ptr<Playlist> > all = _session->playlists->playlists_for_track (rtav->track ());
7285 for (vector<boost::shared_ptr<Playlist> >::iterator p = all.begin(); p != all.end(); ++p) {
7290 if ((*x)->playlist ()) {
7291 pl.insert ((*x)->playlist ());
7295 for (set<boost::shared_ptr<Playlist> >::iterator i = pl.begin(); i != pl.end(); ++i) {
7297 (*i)->clear_changes ();
7298 (*i)->clear_owned_changes ();
7300 if (opt == SplitIntersected) {
7301 /* non musical split */
7302 (*i)->split (pos, 0);
7305 (*i)->shift (pos, frames, (opt == MoveIntersected), ignore_music_glue);
7308 begin_reversible_command (_("insert time"));
7311 vector<Command*> cmds;
7313 _session->add_commands (cmds);
7315 _session->add_command (new StatefulDiffCommand (*i));
7319 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*x);
7322 begin_reversible_command (_("insert time"));
7325 rtav->route ()->shift (pos, frames);
7332 XMLNode& before (_session->locations()->get_state());
7333 Locations::LocationList copy (_session->locations()->list());
7335 for (Locations::LocationList::iterator i = copy.begin(); i != copy.end(); ++i) {
7337 Locations::LocationList::const_iterator tmp;
7339 if ((*i)->position_lock_style() == AudioTime || glued_markers_too) {
7340 bool const was_locked = (*i)->locked ();
7341 if (locked_markers_too) {
7345 if ((*i)->start() >= pos) {
7346 // move end first, in case we're moving by more than the length of the range
7347 if (!(*i)->is_mark()) {
7348 (*i)->set_end ((*i)->end() + frames);
7350 (*i)->set_start ((*i)->start() + frames);
7362 begin_reversible_command (_("insert time"));
7365 XMLNode& after (_session->locations()->get_state());
7366 _session->add_command (new MementoCommand<Locations>(*_session->locations(), &before, &after));
7372 begin_reversible_command (_("insert time"));
7375 XMLNode& before (_session->tempo_map().get_state());
7376 _session->tempo_map().insert_time (pos, frames);
7377 XMLNode& after (_session->tempo_map().get_state());
7378 _session->add_command (new MementoCommand<TempoMap>(_session->tempo_map(), &before, &after));
7382 commit_reversible_command ();
7387 Editor::do_remove_time ()
7389 if (selection->tracks.empty()) {
7393 framepos_t pos = get_preferred_edit_position (EDIT_IGNORE_MOUSE);
7394 InsertRemoveTimeDialog d (*this, true);
7396 int response = d.run ();
7398 if (response != RESPONSE_OK) {
7402 framecnt_t distance = d.distance();
7404 if (distance == 0) {
7414 d.move_glued_markers(),
7415 d.move_locked_markers(),
7421 Editor::remove_time (framepos_t pos, framecnt_t frames, InsertTimeOption opt,
7422 bool ignore_music_glue, bool markers_too, bool glued_markers_too, bool locked_markers_too, bool tempo_too)
7424 if (Config->get_edit_mode() == Lock) {
7425 error << (_("Cannot insert or delete time when in Lock edit.")) << endmsg;
7428 bool in_command = false;
7430 for (TrackSelection::iterator x = selection->tracks.begin(); x != selection->tracks.end(); ++x) {
7432 boost::shared_ptr<Playlist> pl = (*x)->playlist();
7436 XMLNode &before = pl->get_state();
7438 std::list<AudioRange> rl;
7439 AudioRange ar(pos, pos+frames, 0);
7442 pl->shift (pos, -frames, true, ignore_music_glue);
7445 begin_reversible_command (_("remove time"));
7448 XMLNode &after = pl->get_state();
7450 _session->add_command (new MementoCommand<Playlist> (*pl, &before, &after));
7454 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*x);
7457 begin_reversible_command (_("remove time"));
7460 rtav->route ()->shift (pos, -frames);
7464 std::list<Location*> loc_kill_list;
7469 XMLNode& before (_session->locations()->get_state());
7470 Locations::LocationList copy (_session->locations()->list());
7472 for (Locations::LocationList::iterator i = copy.begin(); i != copy.end(); ++i) {
7473 if ((*i)->position_lock_style() == AudioTime || glued_markers_too) {
7475 bool const was_locked = (*i)->locked ();
7476 if (locked_markers_too) {
7480 if (!(*i)->is_mark()) { // it's a range; have to handle both start and end
7481 if ((*i)->end() >= pos
7482 && (*i)->end() < pos+frames
7483 && (*i)->start() >= pos
7484 && (*i)->end() < pos+frames) { // range is completely enclosed; kill it
7486 loc_kill_list.push_back(*i);
7487 } else { // only start or end is included, try to do the right thing
7488 // move start before moving end, to avoid trying to move the end to before the start
7489 // if we're removing more time than the length of the range
7490 if ((*i)->start() >= pos && (*i)->start() < pos+frames) {
7491 // start is within cut
7492 (*i)->set_start (pos); // bring the start marker to the beginning of the cut
7494 } else if ((*i)->start() >= pos+frames) {
7495 // start (and thus entire range) lies beyond end of cut
7496 (*i)->set_start ((*i)->start() - frames); // slip the start marker back
7499 if ((*i)->end() >= pos && (*i)->end() < pos+frames) {
7500 // end is inside cut
7501 (*i)->set_end (pos); // bring the end to the cut
7503 } else if ((*i)->end() >= pos+frames) {
7504 // end is beyond end of cut
7505 (*i)->set_end ((*i)->end() - frames); // slip the end marker back
7510 } else if ((*i)->start() >= pos && (*i)->start() < pos+frames ) {
7511 loc_kill_list.push_back(*i);
7513 } else if ((*i)->start() >= pos) {
7514 (*i)->set_start ((*i)->start() -frames);
7524 for (list<Location*>::iterator i = loc_kill_list.begin(); i != loc_kill_list.end(); ++i) {
7525 _session->locations()->remove( *i );
7530 begin_reversible_command (_("remove time"));
7533 XMLNode& after (_session->locations()->get_state());
7534 _session->add_command (new MementoCommand<Locations>(*_session->locations(), &before, &after));
7539 XMLNode& before (_session->tempo_map().get_state());
7541 if (_session->tempo_map().remove_time (pos, frames) ) {
7543 begin_reversible_command (_("remove time"));
7546 XMLNode& after (_session->tempo_map().get_state());
7547 _session->add_command (new MementoCommand<TempoMap>(_session->tempo_map(), &before, &after));
7552 commit_reversible_command ();
7557 Editor::fit_selection ()
7559 if (!selection->tracks.empty()) {
7560 fit_tracks (selection->tracks);
7564 /* no selected tracks - use tracks with selected regions */
7566 if (!selection->regions.empty()) {
7567 for (RegionSelection::iterator r = selection->regions.begin(); r != selection->regions.end(); ++r) {
7568 tvl.push_back (&(*r)->get_time_axis_view ());
7574 } else if (internal_editing()) {
7575 /* no selected tracks, or regions, but in internal edit mode, so follow the mouse and use
7578 if (entered_track) {
7579 tvl.push_back (entered_track);
7588 Editor::fit_tracks (TrackViewList & tracks)
7590 if (tracks.empty()) {
7594 uint32_t child_heights = 0;
7595 int visible_tracks = 0;
7597 for (TrackSelection::iterator t = tracks.begin(); t != tracks.end(); ++t) {
7599 if (!(*t)->marked_for_display()) {
7603 child_heights += (*t)->effective_height() - (*t)->current_height();
7607 /* compute the per-track height from:
7609 total canvas visible height -
7610 height that will be taken by visible children of selected
7611 tracks - height of the ruler/hscroll area
7613 uint32_t h = (uint32_t) floor ((trackviews_height() - child_heights) / visible_tracks);
7614 double first_y_pos = DBL_MAX;
7616 if (h < TimeAxisView::preset_height (HeightSmall)) {
7617 MessageDialog msg (_("There are too many tracks to fit in the current window"));
7618 /* too small to be displayed */
7622 undo_visual_stack.push_back (current_visual_state (true));
7623 PBD::Unwinder<bool> nsv (no_save_visual, true);
7625 /* build a list of all tracks, including children */
7628 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
7630 TimeAxisView::Children c = (*i)->get_child_list ();
7631 for (TimeAxisView::Children::iterator j = c.begin(); j != c.end(); ++j) {
7632 all.push_back (j->get());
7637 // find selection range.
7638 // if someone knows how to user TrackViewList::iterator for this
7640 int selected_top = -1;
7641 int selected_bottom = -1;
7643 for (TrackViewList::iterator t = all.begin(); t != all.end(); ++t, ++i) {
7644 if ((*t)->marked_for_display ()) {
7645 if (tracks.contains(*t)) {
7646 if (selected_top == -1) {
7649 selected_bottom = i;
7655 for (TrackViewList::iterator t = all.begin(); t != all.end(); ++t, ++i) {
7656 if ((*t)->marked_for_display ()) {
7657 if (tracks.contains(*t)) {
7658 (*t)->set_height (h);
7659 first_y_pos = std::min ((*t)->y_position (), first_y_pos);
7661 if (i > selected_top && i < selected_bottom) {
7662 hide_track_in_display (*t);
7669 set the controls_layout height now, because waiting for its size
7670 request signal handler will cause the vertical adjustment setting to fail
7673 controls_layout.property_height () = _full_canvas_height;
7674 vertical_adjustment.set_value (first_y_pos);
7676 redo_visual_stack.push_back (current_visual_state (true));
7678 visible_tracks_selector.set_text (_("Sel"));
7682 Editor::save_visual_state (uint32_t n)
7684 while (visual_states.size() <= n) {
7685 visual_states.push_back (0);
7688 if (visual_states[n] != 0) {
7689 delete visual_states[n];
7692 visual_states[n] = current_visual_state (true);
7697 Editor::goto_visual_state (uint32_t n)
7699 if (visual_states.size() <= n) {
7703 if (visual_states[n] == 0) {
7707 use_visual_state (*visual_states[n]);
7711 Editor::start_visual_state_op (uint32_t n)
7713 save_visual_state (n);
7715 PopUp* pup = new PopUp (WIN_POS_MOUSE, 1000, true);
7717 snprintf (buf, sizeof (buf), _("Saved view %u"), n+1);
7718 pup->set_text (buf);
7723 Editor::cancel_visual_state_op (uint32_t n)
7725 goto_visual_state (n);
7729 Editor::toggle_region_mute ()
7731 if (_ignore_region_action) {
7735 RegionSelection rs = get_regions_from_selection_and_entered ();
7741 if (rs.size() > 1) {
7742 begin_reversible_command (_("mute regions"));
7744 begin_reversible_command (_("mute region"));
7747 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
7749 (*i)->region()->playlist()->clear_changes ();
7750 (*i)->region()->set_muted (!(*i)->region()->muted ());
7751 _session->add_command (new StatefulDiffCommand ((*i)->region()));
7755 commit_reversible_command ();
7759 Editor::combine_regions ()
7761 /* foreach track with selected regions, take all selected regions
7762 and join them into a new region containing the subregions (as a
7766 typedef set<RouteTimeAxisView*> RTVS;
7769 if (selection->regions.empty()) {
7773 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
7774 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(&(*i)->get_time_axis_view());
7777 tracks.insert (rtv);
7781 begin_reversible_command (_("combine regions"));
7783 vector<RegionView*> new_selection;
7785 for (RTVS::iterator i = tracks.begin(); i != tracks.end(); ++i) {
7788 if ((rv = (*i)->combine_regions ()) != 0) {
7789 new_selection.push_back (rv);
7793 selection->clear_regions ();
7794 for (vector<RegionView*>::iterator i = new_selection.begin(); i != new_selection.end(); ++i) {
7795 selection->add (*i);
7798 commit_reversible_command ();
7802 Editor::uncombine_regions ()
7804 typedef set<RouteTimeAxisView*> RTVS;
7807 if (selection->regions.empty()) {
7811 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
7812 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(&(*i)->get_time_axis_view());
7815 tracks.insert (rtv);
7819 begin_reversible_command (_("uncombine regions"));
7821 for (RTVS::iterator i = tracks.begin(); i != tracks.end(); ++i) {
7822 (*i)->uncombine_regions ();
7825 commit_reversible_command ();
7829 Editor::toggle_midi_input_active (bool flip_others)
7832 boost::shared_ptr<RouteList> rl (new RouteList);
7834 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
7835 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
7841 boost::shared_ptr<MidiTrack> mt = rtav->midi_track();
7844 rl->push_back (rtav->route());
7845 onoff = !mt->input_active();
7849 _session->set_exclusive_input_active (rl, onoff, flip_others);
7856 lock_dialog = new Gtk::Dialog (string_compose (_("%1: Locked"), PROGRAM_NAME), true);
7858 Gtk::Image* padlock = manage (new Gtk::Image (ARDOUR_UI_UTILS::get_icon ("padlock_closed")));
7859 lock_dialog->get_vbox()->pack_start (*padlock);
7861 ArdourButton* b = manage (new ArdourButton);
7862 b->set_name ("lock button");
7863 b->set_text (_("Click to unlock"));
7864 b->signal_clicked.connect (sigc::mem_fun (*this, &Editor::unlock));
7865 lock_dialog->get_vbox()->pack_start (*b);
7867 lock_dialog->get_vbox()->show_all ();
7868 lock_dialog->set_size_request (200, 200);
7871 delete _main_menu_disabler;
7872 _main_menu_disabler = new MainMenuDisabler;
7874 lock_dialog->present ();
7880 lock_dialog->hide ();
7882 delete _main_menu_disabler;
7883 _main_menu_disabler = 0;
7885 if (UIConfiguration::instance().get_lock_gui_after_seconds()) {
7886 start_lock_event_timing ();
7891 Editor::bring_in_callback (Gtk::Label* label, uint32_t n, uint32_t total, string name)
7893 Gtkmm2ext::UI::instance()->call_slot (invalidator (*this), boost::bind (&Editor::update_bring_in_message, this, label, n, total, name));
7897 Editor::update_bring_in_message (Gtk::Label* label, uint32_t n, uint32_t total, string name)
7899 Timers::TimerSuspender t;
7900 label->set_text (string_compose ("Copying %1, %2 of %3", name, n, total));
7901 Gtkmm2ext::UI::instance()->flush_pending ();
7905 Editor::bring_all_sources_into_session ()
7912 ArdourDialog w (_("Moving embedded files into session folder"));
7913 w.get_vbox()->pack_start (msg);
7916 /* flush all pending GUI events because we're about to start copying
7920 Timers::TimerSuspender t;
7921 Gtkmm2ext::UI::instance()->flush_pending ();
7925 _session->bring_all_sources_into_session (boost::bind (&Editor::bring_in_callback, this, &msg, _1, _2, _3));