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/dB.h"
46 #include "ardour/location.h"
47 #include "ardour/midi_region.h"
48 #include "ardour/midi_track.h"
49 #include "ardour/operations.h"
50 #include "ardour/playlist_factory.h"
51 #include "ardour/profile.h"
52 #include "ardour/quantize.h"
53 #include "ardour/legatize.h"
54 #include "ardour/region_factory.h"
55 #include "ardour/reverse.h"
56 #include "ardour/session.h"
57 #include "ardour/session_playlists.h"
58 #include "ardour/strip_silence.h"
59 #include "ardour/transient_detector.h"
61 #include "canvas/canvas.h"
64 #include "ardour_ui.h"
65 #include "audio_region_view.h"
66 #include "audio_streamview.h"
67 #include "audio_time_axis.h"
68 #include "automation_region_view.h"
69 #include "automation_time_axis.h"
70 #include "control_point.h"
74 #include "editor_cursors.h"
75 #include "editor_drag.h"
76 #include "editor_regions.h"
77 #include "editor_routes.h"
78 #include "gui_thread.h"
79 #include "insert_time_dialog.h"
80 #include "interthread_progress_window.h"
81 #include "item_counts.h"
83 #include "midi_region_view.h"
84 #include "mixer_strip.h"
85 #include "mouse_cursors.h"
86 #include "normalize_dialog.h"
88 #include "paste_context.h"
89 #include "patch_change_dialog.h"
90 #include "quantize_dialog.h"
91 #include "region_gain_line.h"
92 #include "rgb_macros.h"
93 #include "route_time_axis.h"
94 #include "selection.h"
95 #include "selection_templates.h"
96 #include "streamview.h"
97 #include "strip_silence_dialog.h"
98 #include "time_axis_view.h"
99 #include "transpose_dialog.h"
104 using namespace ARDOUR;
107 using namespace Gtkmm2ext;
108 using namespace Editing;
109 using Gtkmm2ext::Keyboard;
111 /***********************************************************************
113 ***********************************************************************/
116 Editor::undo (uint32_t n)
118 if (_drags->active ()) {
128 Editor::redo (uint32_t n)
130 if (_drags->active ()) {
140 Editor::split_regions_at (framepos_t where, RegionSelection& regions)
144 RegionSelection pre_selected_regions = selection->regions;
145 bool working_on_selection = !pre_selected_regions.empty();
147 list<boost::shared_ptr<Playlist> > used_playlists;
148 list<RouteTimeAxisView*> used_trackviews;
150 if (regions.empty()) {
154 begin_reversible_command (_("split"));
156 // if splitting a single region, and snap-to is using
157 // region boundaries, don't pay attention to them
159 if (regions.size() == 1) {
160 switch (_snap_type) {
161 case SnapToRegionStart:
162 case SnapToRegionSync:
163 case SnapToRegionEnd:
172 EditorFreeze(); /* Emit Signal */
175 for (RegionSelection::iterator a = regions.begin(); a != regions.end(); ) {
177 RegionSelection::iterator tmp;
179 /* XXX this test needs to be more complicated, to make sure we really
180 have something to split.
183 if (!(*a)->region()->covers (where)) {
191 boost::shared_ptr<Playlist> pl = (*a)->region()->playlist();
199 /* we haven't seen this playlist before */
201 /* remember used playlists so we can thaw them later */
202 used_playlists.push_back(pl);
204 TimeAxisView& tv = (*a)->get_time_axis_view();
205 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (&tv);
207 used_trackviews.push_back (rtv);
214 pl->clear_changes ();
215 pl->split_region ((*a)->region(), where);
216 _session->add_command (new StatefulDiffCommand (pl));
222 latest_regionviews.clear ();
224 vector<sigc::connection> region_added_connections;
226 for (list<RouteTimeAxisView*>::iterator i = used_trackviews.begin(); i != used_trackviews.end(); ++i) {
227 region_added_connections.push_back ((*i)->view()->RegionViewAdded.connect (sigc::mem_fun(*this, &Editor::collect_new_region_view)));
230 while (used_playlists.size() > 0) {
231 list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
233 used_playlists.pop_front();
236 for (vector<sigc::connection>::iterator c = region_added_connections.begin(); c != region_added_connections.end(); ++c) {
241 EditorThaw(); /* Emit Signal */
244 if (working_on_selection) {
245 // IFF we were working on selected regions, try to reinstate the other region selections that existed before the freeze/thaw.
247 _ignore_follow_edits = true; // a split will change the region selection in mysterious ways; it's not practical or wanted to follow this edit
248 RegionSelectionAfterSplit rsas = Config->get_region_selection_after_split();
249 /* There are three classes of regions that we might want selected after
250 splitting selected regions:
251 - regions selected before the split operation, and unaffected by it
252 - newly-created regions before the split
253 - newly-created regions after the split
256 if (rsas & Existing) {
257 // region selections that existed before the split.
258 selection->add ( pre_selected_regions );
261 for (RegionSelection::iterator ri = latest_regionviews.begin(); ri != latest_regionviews.end(); ri++) {
262 if ((*ri)->region()->position() < where) {
263 // new regions created before the split
264 if (rsas & NewlyCreatedLeft) {
265 selection->add (*ri);
268 // new regions created after the split
269 if (rsas & NewlyCreatedRight) {
270 selection->add (*ri);
274 _ignore_follow_edits = false;
276 _ignore_follow_edits = true;
277 if( working_on_selection ) {
278 selection->add (latest_regionviews); //these are the new regions created after the split
280 _ignore_follow_edits = false;
283 commit_reversible_command ();
286 /** Move one extreme of the current range selection. If more than one range is selected,
287 * the start of the earliest range or the end of the latest range is moved.
289 * @param move_end true to move the end of the current range selection, false to move
291 * @param next true to move the extreme to the next region boundary, false to move to
295 Editor::move_range_selection_start_or_end_to_region_boundary (bool move_end, bool next)
297 if (selection->time.start() == selection->time.end_frame()) {
301 framepos_t start = selection->time.start ();
302 framepos_t end = selection->time.end_frame ();
304 /* the position of the thing we may move */
305 framepos_t pos = move_end ? end : start;
306 int dir = next ? 1 : -1;
308 /* so we don't find the current region again */
309 if (dir > 0 || pos > 0) {
313 framepos_t const target = get_region_boundary (pos, dir, true, false);
328 begin_reversible_command (_("alter selection"));
329 selection->set_preserving_all_ranges (start, end);
330 commit_reversible_command ();
334 Editor::nudge_forward_release (GdkEventButton* ev)
336 if (ev->state & Keyboard::PrimaryModifier) {
337 nudge_forward (false, true);
339 nudge_forward (false, false);
345 Editor::nudge_backward_release (GdkEventButton* ev)
347 if (ev->state & Keyboard::PrimaryModifier) {
348 nudge_backward (false, true);
350 nudge_backward (false, false);
357 Editor::nudge_forward (bool next, bool force_playhead)
360 framepos_t next_distance;
366 RegionSelection rs = get_regions_from_selection_and_entered ();
368 if (!force_playhead && !rs.empty()) {
370 begin_reversible_command (_("nudge regions forward"));
372 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
373 boost::shared_ptr<Region> r ((*i)->region());
375 distance = get_nudge_distance (r->position(), next_distance);
378 distance = next_distance;
382 r->set_position (r->position() + distance);
383 _session->add_command (new StatefulDiffCommand (r));
386 commit_reversible_command ();
389 } else if (!force_playhead && !selection->markers.empty()) {
393 begin_reversible_command (_("nudge location forward"));
395 for (MarkerSelection::iterator i = selection->markers.begin(); i != selection->markers.end(); ++i) {
397 Location* loc = find_location_from_marker ((*i), is_start);
401 XMLNode& before (loc->get_state());
404 distance = get_nudge_distance (loc->start(), next_distance);
406 distance = next_distance;
408 if (max_framepos - distance > loc->start() + loc->length()) {
409 loc->set_start (loc->start() + distance);
411 loc->set_start (max_framepos - loc->length());
414 distance = get_nudge_distance (loc->end(), next_distance);
416 distance = next_distance;
418 if (max_framepos - distance > loc->end()) {
419 loc->set_end (loc->end() + distance);
421 loc->set_end (max_framepos);
424 XMLNode& after (loc->get_state());
425 _session->add_command (new MementoCommand<Location>(*loc, &before, &after));
429 commit_reversible_command ();
432 distance = get_nudge_distance (playhead_cursor->current_frame (), next_distance);
433 _session->request_locate (playhead_cursor->current_frame () + distance);
438 Editor::nudge_backward (bool next, bool force_playhead)
441 framepos_t next_distance;
447 RegionSelection rs = get_regions_from_selection_and_entered ();
449 if (!force_playhead && !rs.empty()) {
451 begin_reversible_command (_("nudge regions backward"));
453 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
454 boost::shared_ptr<Region> r ((*i)->region());
456 distance = get_nudge_distance (r->position(), next_distance);
459 distance = next_distance;
464 if (r->position() > distance) {
465 r->set_position (r->position() - distance);
469 _session->add_command (new StatefulDiffCommand (r));
472 commit_reversible_command ();
474 } else if (!force_playhead && !selection->markers.empty()) {
478 begin_reversible_command (_("nudge location forward"));
480 for (MarkerSelection::iterator i = selection->markers.begin(); i != selection->markers.end(); ++i) {
482 Location* loc = find_location_from_marker ((*i), is_start);
486 XMLNode& before (loc->get_state());
489 distance = get_nudge_distance (loc->start(), next_distance);
491 distance = next_distance;
493 if (distance < loc->start()) {
494 loc->set_start (loc->start() - distance);
499 distance = get_nudge_distance (loc->end(), next_distance);
502 distance = next_distance;
505 if (distance < loc->end() - loc->length()) {
506 loc->set_end (loc->end() - distance);
508 loc->set_end (loc->length());
512 XMLNode& after (loc->get_state());
513 _session->add_command (new MementoCommand<Location>(*loc, &before, &after));
517 commit_reversible_command ();
521 distance = get_nudge_distance (playhead_cursor->current_frame (), next_distance);
523 if (playhead_cursor->current_frame () > distance) {
524 _session->request_locate (playhead_cursor->current_frame () - distance);
526 _session->goto_start();
532 Editor::nudge_forward_capture_offset ()
534 RegionSelection rs = get_regions_from_selection_and_entered ();
536 if (!_session || rs.empty()) {
540 begin_reversible_command (_("nudge forward"));
542 framepos_t const distance = _session->worst_output_latency();
544 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
545 boost::shared_ptr<Region> r ((*i)->region());
548 r->set_position (r->position() + distance);
549 _session->add_command(new StatefulDiffCommand (r));
552 commit_reversible_command ();
556 Editor::nudge_backward_capture_offset ()
558 RegionSelection rs = get_regions_from_selection_and_entered ();
560 if (!_session || rs.empty()) {
564 begin_reversible_command (_("nudge backward"));
566 framepos_t const distance = _session->worst_output_latency();
568 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
569 boost::shared_ptr<Region> r ((*i)->region());
573 if (r->position() > distance) {
574 r->set_position (r->position() - distance);
578 _session->add_command(new StatefulDiffCommand (r));
581 commit_reversible_command ();
584 struct RegionSelectionPositionSorter {
585 bool operator() (RegionView* a, RegionView* b) {
586 return a->region()->position() < b->region()->position();
591 Editor::sequence_regions ()
594 framepos_t r_end_prev;
602 RegionSelection rs = get_regions_from_selection_and_entered ();
603 rs.sort(RegionSelectionPositionSorter());
607 begin_reversible_command (_("sequence regions"));
608 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
609 boost::shared_ptr<Region> r ((*i)->region());
617 if(r->position_locked())
624 r->set_position(r_end_prev);
627 _session->add_command (new StatefulDiffCommand (r));
629 r_end=r->position() + r->length();
633 commit_reversible_command ();
641 Editor::move_to_start ()
643 _session->goto_start ();
647 Editor::move_to_end ()
650 _session->request_locate (_session->current_end_frame());
654 Editor::build_region_boundary_cache ()
657 vector<RegionPoint> interesting_points;
658 boost::shared_ptr<Region> r;
659 TrackViewList tracks;
662 region_boundary_cache.clear ();
668 switch (_snap_type) {
669 case SnapToRegionStart:
670 interesting_points.push_back (Start);
672 case SnapToRegionEnd:
673 interesting_points.push_back (End);
675 case SnapToRegionSync:
676 interesting_points.push_back (SyncPoint);
678 case SnapToRegionBoundary:
679 interesting_points.push_back (Start);
680 interesting_points.push_back (End);
683 fatal << string_compose (_("build_region_boundary_cache called with snap_type = %1"), _snap_type) << endmsg;
684 abort(); /*NOTREACHED*/
688 TimeAxisView *ontrack = 0;
691 if (!selection->tracks.empty()) {
692 tlist = selection->tracks.filter_to_unique_playlists ();
694 tlist = track_views.filter_to_unique_playlists ();
697 while (pos < _session->current_end_frame() && !at_end) {
700 framepos_t lpos = max_framepos;
702 for (vector<RegionPoint>::iterator p = interesting_points.begin(); p != interesting_points.end(); ++p) {
704 if ((r = find_next_region (pos, *p, 1, tlist, &ontrack)) == 0) {
705 if (*p == interesting_points.back()) {
708 /* move to next point type */
714 rpos = r->first_frame();
718 rpos = r->last_frame();
722 rpos = r->sync_position ();
730 RouteTimeAxisView *rtav;
732 if (ontrack != 0 && (rtav = dynamic_cast<RouteTimeAxisView*>(ontrack)) != 0 ) {
733 if (rtav->track() != 0) {
734 speed = rtav->track()->speed();
738 rpos = track_frame_to_session_frame (rpos, speed);
744 /* prevent duplicates, but we don't use set<> because we want to be able
748 vector<framepos_t>::iterator ri;
750 for (ri = region_boundary_cache.begin(); ri != region_boundary_cache.end(); ++ri) {
756 if (ri == region_boundary_cache.end()) {
757 region_boundary_cache.push_back (rpos);
764 /* finally sort to be sure that the order is correct */
766 sort (region_boundary_cache.begin(), region_boundary_cache.end());
769 boost::shared_ptr<Region>
770 Editor::find_next_region (framepos_t frame, RegionPoint point, int32_t dir, TrackViewList& tracks, TimeAxisView **ontrack)
772 TrackViewList::iterator i;
773 framepos_t closest = max_framepos;
774 boost::shared_ptr<Region> ret;
778 framepos_t track_frame;
779 RouteTimeAxisView *rtav;
781 for (i = tracks.begin(); i != tracks.end(); ++i) {
784 boost::shared_ptr<Region> r;
787 if ( (rtav = dynamic_cast<RouteTimeAxisView*>(*i)) != 0 ) {
788 if (rtav->track()!=0)
789 track_speed = rtav->track()->speed();
792 track_frame = session_frame_to_track_frame(frame, track_speed);
794 if ((r = (*i)->find_next_region (track_frame, point, dir)) == 0) {
800 rpos = r->first_frame ();
804 rpos = r->last_frame ();
808 rpos = r->sync_position ();
812 // rpos is a "track frame", converting it to "_session frame"
813 rpos = track_frame_to_session_frame(rpos, track_speed);
816 distance = rpos - frame;
818 distance = frame - rpos;
821 if (distance < closest) {
833 Editor::find_next_region_boundary (framepos_t pos, int32_t dir, const TrackViewList& tracks)
835 framecnt_t distance = max_framepos;
836 framepos_t current_nearest = -1;
838 for (TrackViewList::const_iterator i = tracks.begin(); i != tracks.end(); ++i) {
839 framepos_t contender;
842 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*i);
848 if ((contender = rtv->find_next_region_boundary (pos, dir)) < 0) {
852 d = ::llabs (pos - contender);
855 current_nearest = contender;
860 return current_nearest;
864 Editor::get_region_boundary (framepos_t pos, int32_t dir, bool with_selection, bool only_onscreen)
869 if (with_selection && Config->get_region_boundaries_from_selected_tracks()) {
871 if (!selection->tracks.empty()) {
873 target = find_next_region_boundary (pos, dir, selection->tracks);
877 if (only_onscreen || Config->get_region_boundaries_from_onscreen_tracks()) {
878 get_onscreen_tracks (tvl);
879 target = find_next_region_boundary (pos, dir, tvl);
881 target = find_next_region_boundary (pos, dir, track_views);
887 if (only_onscreen || Config->get_region_boundaries_from_onscreen_tracks()) {
888 get_onscreen_tracks (tvl);
889 target = find_next_region_boundary (pos, dir, tvl);
891 target = find_next_region_boundary (pos, dir, track_views);
899 Editor::cursor_to_region_boundary (bool with_selection, int32_t dir)
901 framepos_t pos = playhead_cursor->current_frame ();
908 // so we don't find the current region again..
909 if (dir > 0 || pos > 0) {
913 if ((target = get_region_boundary (pos, dir, with_selection, false)) < 0) {
917 _session->request_locate (target);
921 Editor::cursor_to_next_region_boundary (bool with_selection)
923 cursor_to_region_boundary (with_selection, 1);
927 Editor::cursor_to_previous_region_boundary (bool with_selection)
929 cursor_to_region_boundary (with_selection, -1);
933 Editor::cursor_to_region_point (EditorCursor* cursor, RegionPoint point, int32_t dir)
935 boost::shared_ptr<Region> r;
936 framepos_t pos = cursor->current_frame ();
942 TimeAxisView *ontrack = 0;
944 // so we don't find the current region again..
948 if (!selection->tracks.empty()) {
950 r = find_next_region (pos, point, dir, selection->tracks, &ontrack);
952 } else if (clicked_axisview) {
955 t.push_back (clicked_axisview);
957 r = find_next_region (pos, point, dir, t, &ontrack);
961 r = find_next_region (pos, point, dir, track_views, &ontrack);
970 pos = r->first_frame ();
974 pos = r->last_frame ();
978 pos = r->sync_position ();
983 RouteTimeAxisView *rtav;
985 if ( ontrack != 0 && (rtav = dynamic_cast<RouteTimeAxisView*>(ontrack)) != 0 ) {
986 if (rtav->track() != 0) {
987 speed = rtav->track()->speed();
991 pos = track_frame_to_session_frame(pos, speed);
993 if (cursor == playhead_cursor) {
994 _session->request_locate (pos);
996 cursor->set_position (pos);
1001 Editor::cursor_to_next_region_point (EditorCursor* cursor, RegionPoint point)
1003 cursor_to_region_point (cursor, point, 1);
1007 Editor::cursor_to_previous_region_point (EditorCursor* cursor, RegionPoint point)
1009 cursor_to_region_point (cursor, point, -1);
1013 Editor::cursor_to_selection_start (EditorCursor *cursor)
1017 switch (mouse_mode) {
1019 if (!selection->regions.empty()) {
1020 pos = selection->regions.start();
1025 if (!selection->time.empty()) {
1026 pos = selection->time.start ();
1034 if (cursor == playhead_cursor) {
1035 _session->request_locate (pos);
1037 cursor->set_position (pos);
1042 Editor::cursor_to_selection_end (EditorCursor *cursor)
1046 switch (mouse_mode) {
1048 if (!selection->regions.empty()) {
1049 pos = selection->regions.end_frame();
1054 if (!selection->time.empty()) {
1055 pos = selection->time.end_frame ();
1063 if (cursor == playhead_cursor) {
1064 _session->request_locate (pos);
1066 cursor->set_position (pos);
1071 Editor::selected_marker_to_region_boundary (bool with_selection, int32_t dir)
1081 if (selection->markers.empty()) {
1085 if (!mouse_frame (mouse, ignored)) {
1089 add_location_mark (mouse);
1092 if ((loc = find_location_from_marker (selection->markers.front(), ignored)) == 0) {
1096 framepos_t pos = loc->start();
1098 // so we don't find the current region again..
1099 if (dir > 0 || pos > 0) {
1103 if ((target = get_region_boundary (pos, dir, with_selection, false)) < 0) {
1107 loc->move_to (target);
1111 Editor::selected_marker_to_next_region_boundary (bool with_selection)
1113 selected_marker_to_region_boundary (with_selection, 1);
1117 Editor::selected_marker_to_previous_region_boundary (bool with_selection)
1119 selected_marker_to_region_boundary (with_selection, -1);
1123 Editor::selected_marker_to_region_point (RegionPoint point, int32_t dir)
1125 boost::shared_ptr<Region> r;
1130 if (!_session || selection->markers.empty()) {
1134 if ((loc = find_location_from_marker (selection->markers.front(), ignored)) == 0) {
1138 TimeAxisView *ontrack = 0;
1142 // so we don't find the current region again..
1146 if (!selection->tracks.empty()) {
1148 r = find_next_region (pos, point, dir, selection->tracks, &ontrack);
1152 r = find_next_region (pos, point, dir, track_views, &ontrack);
1161 pos = r->first_frame ();
1165 pos = r->last_frame ();
1169 pos = r->adjust_to_sync (r->first_frame());
1174 RouteTimeAxisView *rtav;
1176 if (ontrack != 0 && (rtav = dynamic_cast<RouteTimeAxisView*>(ontrack)) != 0) {
1177 if (rtav->track() != 0) {
1178 speed = rtav->track()->speed();
1182 pos = track_frame_to_session_frame(pos, speed);
1188 Editor::selected_marker_to_next_region_point (RegionPoint point)
1190 selected_marker_to_region_point (point, 1);
1194 Editor::selected_marker_to_previous_region_point (RegionPoint point)
1196 selected_marker_to_region_point (point, -1);
1200 Editor::selected_marker_to_selection_start ()
1206 if (!_session || selection->markers.empty()) {
1210 if ((loc = find_location_from_marker (selection->markers.front(), ignored)) == 0) {
1214 switch (mouse_mode) {
1216 if (!selection->regions.empty()) {
1217 pos = selection->regions.start();
1222 if (!selection->time.empty()) {
1223 pos = selection->time.start ();
1235 Editor::selected_marker_to_selection_end ()
1241 if (!_session || selection->markers.empty()) {
1245 if ((loc = find_location_from_marker (selection->markers.front(), ignored)) == 0) {
1249 switch (mouse_mode) {
1251 if (!selection->regions.empty()) {
1252 pos = selection->regions.end_frame();
1257 if (!selection->time.empty()) {
1258 pos = selection->time.end_frame ();
1270 Editor::scroll_playhead (bool forward)
1272 framepos_t pos = playhead_cursor->current_frame ();
1273 framecnt_t delta = (framecnt_t) floor (current_page_samples() / 0.8);
1276 if (pos == max_framepos) {
1280 if (pos < max_framepos - delta) {
1299 _session->request_locate (pos);
1303 Editor::cursor_align (bool playhead_to_edit)
1309 if (playhead_to_edit) {
1311 if (selection->markers.empty()) {
1315 _session->request_locate (selection->markers.front()->position(), _session->transport_rolling());
1318 /* move selected markers to playhead */
1320 for (MarkerSelection::iterator i = selection->markers.begin(); i != selection->markers.end(); ++i) {
1323 Location* loc = find_location_from_marker (*i, ignored);
1325 if (loc->is_mark()) {
1326 loc->set_start (playhead_cursor->current_frame ());
1328 loc->set (playhead_cursor->current_frame (),
1329 playhead_cursor->current_frame () + loc->length());
1336 Editor::scroll_backward (float pages)
1338 framepos_t const one_page = (framepos_t) rint (_visible_canvas_width * samples_per_pixel);
1339 framepos_t const cnt = (framepos_t) floor (pages * one_page);
1342 if (leftmost_frame < cnt) {
1345 frame = leftmost_frame - cnt;
1348 reset_x_origin (frame);
1352 Editor::scroll_forward (float pages)
1354 framepos_t const one_page = (framepos_t) rint (_visible_canvas_width * samples_per_pixel);
1355 framepos_t const cnt = (framepos_t) floor (pages * one_page);
1358 if (max_framepos - cnt < leftmost_frame) {
1359 frame = max_framepos - cnt;
1361 frame = leftmost_frame + cnt;
1364 reset_x_origin (frame);
1368 Editor::scroll_tracks_down ()
1370 double vert_value = vertical_adjustment.get_value() + vertical_adjustment.get_page_size();
1371 if (vert_value > vertical_adjustment.get_upper() - _visible_canvas_height) {
1372 vert_value = vertical_adjustment.get_upper() - _visible_canvas_height;
1375 vertical_adjustment.set_value (vert_value);
1379 Editor::scroll_tracks_up ()
1381 vertical_adjustment.set_value (vertical_adjustment.get_value() - vertical_adjustment.get_page_size());
1385 Editor::scroll_tracks_down_line ()
1387 double vert_value = vertical_adjustment.get_value() + 60;
1389 if (vert_value > vertical_adjustment.get_upper() - _visible_canvas_height) {
1390 vert_value = vertical_adjustment.get_upper() - _visible_canvas_height;
1393 vertical_adjustment.set_value (vert_value);
1397 Editor::scroll_tracks_up_line ()
1399 reset_y_origin (vertical_adjustment.get_value() - 60);
1403 Editor::scroll_down_one_track ()
1405 TrackViewList::reverse_iterator next = track_views.rend();
1406 std::pair<TimeAxisView*,double> res;
1407 const double top_of_trackviews = vertical_adjustment.get_value();
1409 for (TrackViewList::reverse_iterator t = track_views.rbegin(); t != track_views.rend(); ++t) {
1410 if ((*t)->hidden()) {
1415 /* If this is the upper-most visible trackview, we want to display
1416 the one above it (next)
1419 res = (*t)->covers_y_position (top_of_trackviews);
1427 /* move to the track below the first one that covers the */
1429 if (next != track_views.rend()) {
1430 ensure_time_axis_view_is_visible (**next, true);
1438 Editor::scroll_up_one_track ()
1440 TrackViewList::iterator prev = track_views.end();
1441 std::pair<TimeAxisView*,double> res;
1442 double top_of_trackviews = vertical_adjustment.get_value ();
1444 for (TrackViewList::iterator t = track_views.begin(); t != track_views.end(); ++t) {
1446 if ((*t)->hidden()) {
1450 /* find the trackview at the top of the trackview group */
1451 res = (*t)->covers_y_position (top_of_trackviews);
1460 if (prev != track_views.end()) {
1461 ensure_time_axis_view_is_visible (**prev, true);
1471 Editor::tav_zoom_step (bool coarser)
1473 DisplaySuspender ds;
1477 if (selection->tracks.empty()) {
1480 ts = &selection->tracks;
1483 for (TrackViewList::iterator i = ts->begin(); i != ts->end(); ++i) {
1484 TimeAxisView *tv = (static_cast<TimeAxisView*>(*i));
1485 tv->step_height (coarser);
1490 Editor::tav_zoom_smooth (bool coarser, bool force_all)
1492 DisplaySuspender ds;
1496 if (selection->tracks.empty() || force_all) {
1499 ts = &selection->tracks;
1502 for (TrackViewList::iterator i = ts->begin(); i != ts->end(); ++i) {
1503 TimeAxisView *tv = (static_cast<TimeAxisView*>(*i));
1504 uint32_t h = tv->current_height ();
1509 if (h >= TimeAxisView::preset_height (HeightSmall)) {
1514 tv->set_height (h + 5);
1521 Editor::temporal_zoom_step (bool coarser)
1523 ENSURE_GUI_THREAD (*this, &Editor::temporal_zoom_step, coarser)
1525 framecnt_t nspp = samples_per_pixel;
1533 temporal_zoom (nspp);
1537 Editor::temporal_zoom (framecnt_t fpp)
1543 framepos_t current_page = current_page_samples();
1544 framepos_t current_leftmost = leftmost_frame;
1545 framepos_t current_rightmost;
1546 framepos_t current_center;
1547 framepos_t new_page_size;
1548 framepos_t half_page_size;
1549 framepos_t leftmost_after_zoom = 0;
1551 bool in_track_canvas;
1555 if (fpp == samples_per_pixel) {
1559 // Imposing an arbitrary limit to zoom out as too much zoom out produces
1560 // segfaults for lack of memory. If somebody decides this is not high enough I
1561 // believe it can be raisen to higher values but some limit must be in place.
1563 // This constant represents 1 day @ 48kHz on a 1600 pixel wide display
1564 // all of which is used for the editor track displays. The whole day
1565 // would be 4147200000 samples, so 2592000 samples per pixel.
1567 nfpp = min (fpp, (framecnt_t) 2592000);
1568 nfpp = max ((framecnt_t) 1, nfpp);
1570 new_page_size = (framepos_t) floor (_visible_canvas_width * nfpp);
1571 half_page_size = new_page_size / 2;
1573 switch (zoom_focus) {
1575 leftmost_after_zoom = current_leftmost;
1578 case ZoomFocusRight:
1579 current_rightmost = leftmost_frame + current_page;
1580 if (current_rightmost < new_page_size) {
1581 leftmost_after_zoom = 0;
1583 leftmost_after_zoom = current_rightmost - new_page_size;
1587 case ZoomFocusCenter:
1588 current_center = current_leftmost + (current_page/2);
1589 if (current_center < half_page_size) {
1590 leftmost_after_zoom = 0;
1592 leftmost_after_zoom = current_center - half_page_size;
1596 case ZoomFocusPlayhead:
1597 /* centre playhead */
1598 l = playhead_cursor->current_frame () - (new_page_size * 0.5);
1601 leftmost_after_zoom = 0;
1602 } else if (l > max_framepos) {
1603 leftmost_after_zoom = max_framepos - new_page_size;
1605 leftmost_after_zoom = (framepos_t) l;
1609 case ZoomFocusMouse:
1610 /* try to keep the mouse over the same point in the display */
1612 if (!mouse_frame (where, in_track_canvas)) {
1613 /* use playhead instead */
1614 where = playhead_cursor->current_frame ();
1616 if (where < half_page_size) {
1617 leftmost_after_zoom = 0;
1619 leftmost_after_zoom = where - half_page_size;
1624 l = - ((new_page_size * ((where - current_leftmost)/(double)current_page)) - where);
1627 leftmost_after_zoom = 0;
1628 } else if (l > max_framepos) {
1629 leftmost_after_zoom = max_framepos - new_page_size;
1631 leftmost_after_zoom = (framepos_t) l;
1638 /* try to keep the edit point in the same place */
1639 where = get_preferred_edit_position ();
1643 double l = - ((new_page_size * ((where - current_leftmost)/(double)current_page)) - where);
1646 leftmost_after_zoom = 0;
1647 } else if (l > max_framepos) {
1648 leftmost_after_zoom = max_framepos - new_page_size;
1650 leftmost_after_zoom = (framepos_t) l;
1654 /* edit point not defined */
1661 // leftmost_after_zoom = min (leftmost_after_zoom, _session->current_end_frame());
1663 reposition_and_zoom (leftmost_after_zoom, nfpp);
1667 Editor::calc_extra_zoom_edges(framepos_t &start, framepos_t &end)
1669 /* this func helps make sure we leave a little space
1670 at each end of the editor so that the zoom doesn't fit the region
1671 precisely to the screen.
1674 GdkScreen* screen = gdk_screen_get_default ();
1675 const gint pixwidth = gdk_screen_get_width (screen);
1676 const gint mmwidth = gdk_screen_get_width_mm (screen);
1677 const double pix_per_mm = (double) pixwidth/ (double) mmwidth;
1678 const double one_centimeter_in_pixels = pix_per_mm * 10.0;
1680 const framepos_t range = end - start;
1681 const framecnt_t new_fpp = (framecnt_t) ceil ((double) range / (double) _visible_canvas_width);
1682 const framepos_t extra_samples = (framepos_t) floor (one_centimeter_in_pixels * new_fpp);
1684 if (start > extra_samples) {
1685 start -= extra_samples;
1690 if (max_framepos - extra_samples > end) {
1691 end += extra_samples;
1698 Editor::temporal_zoom_region (bool both_axes)
1700 framepos_t start = max_framepos;
1702 set<TimeAxisView*> tracks;
1704 RegionSelection rs = get_regions_from_selection_and_entered ();
1710 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
1712 if ((*i)->region()->position() < start) {
1713 start = (*i)->region()->position();
1716 if ((*i)->region()->last_frame() + 1 > end) {
1717 end = (*i)->region()->last_frame() + 1;
1720 tracks.insert (&((*i)->get_time_axis_view()));
1723 if ((start == 0 && end == 0) || end < start) {
1727 calc_extra_zoom_edges (start, end);
1729 /* if we're zooming on both axes we need to save track heights etc.
1732 undo_visual_stack.push_back (current_visual_state (both_axes));
1734 PBD::Unwinder<bool> nsv (no_save_visual, true);
1736 temporal_zoom_by_frame (start, end);
1739 uint32_t per_track_height = (uint32_t) floor ((_visible_canvas_height - 10.0) / tracks.size());
1741 /* set visible track heights appropriately */
1743 for (set<TimeAxisView*>::iterator t = tracks.begin(); t != tracks.end(); ++t) {
1744 (*t)->set_height (per_track_height);
1747 /* hide irrelevant tracks */
1749 DisplaySuspender ds;
1751 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1752 if (find (tracks.begin(), tracks.end(), (*i)) == tracks.end()) {
1753 hide_track_in_display (*i);
1757 vertical_adjustment.set_value (0.0);
1760 redo_visual_stack.push_back (current_visual_state (both_axes));
1765 Editor::temporal_zoom_selection (bool both_axes)
1767 if (!selection) return;
1769 //ToDo: if notes are selected, zoom to that
1771 //ToDo: if control points are selected, zoom to that
1773 //if region(s) are selected, zoom to that
1774 if ( !selection->regions.empty() )
1775 temporal_zoom_region (both_axes);
1777 //if a range is selected, zoom to that
1778 if (!selection->time.empty()) {
1780 framepos_t start = selection->time.start();
1781 framepos_t end = selection->time.end_frame();
1783 calc_extra_zoom_edges(start, end);
1785 temporal_zoom_by_frame (start, end);
1788 fit_selected_tracks();
1795 Editor::temporal_zoom_session ()
1797 ENSURE_GUI_THREAD (*this, &Editor::temporal_zoom_session)
1800 framecnt_t start = _session->current_start_frame();
1801 framecnt_t end = _session->current_end_frame();
1803 if (_session->actively_recording () ) {
1804 framepos_t cur = playhead_cursor->current_frame ();
1806 /* recording beyond the end marker; zoom out
1807 * by 5 seconds more so that if 'follow
1808 * playhead' is active we don't immediately
1811 end = cur + _session->frame_rate() * 5;
1815 if ((start == 0 && end == 0) || end < start) {
1819 calc_extra_zoom_edges(start, end);
1821 temporal_zoom_by_frame (start, end);
1826 Editor::temporal_zoom_by_frame (framepos_t start, framepos_t end)
1828 if (!_session) return;
1830 if ((start == 0 && end == 0) || end < start) {
1834 framepos_t range = end - start;
1836 const framecnt_t new_fpp = (framecnt_t) ceil ((double) range / (double) _visible_canvas_width);
1838 framepos_t new_page = range;
1839 framepos_t middle = (framepos_t) floor ((double) start + ((double) range / 2.0f));
1840 framepos_t new_leftmost = (framepos_t) floor ((double) middle - ((double) new_page / 2.0f));
1842 if (new_leftmost > middle) {
1846 if (new_leftmost < 0) {
1850 reposition_and_zoom (new_leftmost, new_fpp);
1854 Editor::temporal_zoom_to_frame (bool coarser, framepos_t frame)
1860 framecnt_t range_before = frame - leftmost_frame;
1864 if (samples_per_pixel <= 1) {
1867 new_spp = samples_per_pixel + (samples_per_pixel/2);
1869 range_before += range_before/2;
1871 if (samples_per_pixel >= 1) {
1872 new_spp = samples_per_pixel - (samples_per_pixel/2);
1874 /* could bail out here since we cannot zoom any finer,
1875 but leave that to the equality test below
1877 new_spp = samples_per_pixel;
1880 range_before -= range_before/2;
1883 if (new_spp == samples_per_pixel) {
1887 /* zoom focus is automatically taken as @param frame when this
1891 framepos_t new_leftmost = frame - (framepos_t)range_before;
1893 if (new_leftmost > frame) {
1897 if (new_leftmost < 0) {
1901 reposition_and_zoom (new_leftmost, new_spp);
1906 Editor::choose_new_marker_name(string &name) {
1908 if (!ARDOUR_UI::config()->get_name_new_markers()) {
1909 /* don't prompt user for a new name */
1913 ArdourPrompter dialog (true);
1915 dialog.set_prompt (_("New Name:"));
1917 dialog.set_title (_("New Location Marker"));
1919 dialog.set_name ("MarkNameWindow");
1920 dialog.set_size_request (250, -1);
1921 dialog.set_position (Gtk::WIN_POS_MOUSE);
1923 dialog.add_button (Stock::OK, RESPONSE_ACCEPT);
1924 dialog.set_initial_text (name);
1928 switch (dialog.run ()) {
1929 case RESPONSE_ACCEPT:
1935 dialog.get_result(name);
1942 Editor::add_location_from_selection ()
1946 if (selection->time.empty()) {
1950 if (_session == 0 || clicked_axisview == 0) {
1954 framepos_t start = selection->time[clicked_selection].start;
1955 framepos_t end = selection->time[clicked_selection].end;
1957 _session->locations()->next_available_name(rangename,"selection");
1958 Location *location = new Location (*_session, start, end, rangename, Location::IsRangeMarker);
1960 begin_reversible_command (_("add marker"));
1962 XMLNode &before = _session->locations()->get_state();
1963 _session->locations()->add (location, true);
1964 XMLNode &after = _session->locations()->get_state();
1965 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
1967 commit_reversible_command ();
1971 Editor::add_location_mark (framepos_t where)
1975 select_new_marker = true;
1977 _session->locations()->next_available_name(markername,"mark");
1978 if (!choose_new_marker_name(markername)) {
1981 Location *location = new Location (*_session, where, where, markername, Location::IsMark);
1982 begin_reversible_command (_("add marker"));
1984 XMLNode &before = _session->locations()->get_state();
1985 _session->locations()->add (location, true);
1986 XMLNode &after = _session->locations()->get_state();
1987 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
1989 commit_reversible_command ();
1993 Editor::add_location_from_playhead_cursor ()
1995 add_location_mark (_session->audible_frame());
1999 Editor::remove_location_at_playhead_cursor ()
2004 begin_reversible_command (_("remove marker"));
2006 XMLNode &before = _session->locations()->get_state();
2007 bool removed = false;
2009 //find location(s) at this time
2010 Locations::LocationList locs;
2011 _session->locations()->find_all_between (_session->audible_frame(), _session->audible_frame()+1, locs, Location::Flags(0));
2012 for (Locations::LocationList::iterator i = locs.begin(); i != locs.end(); ++i) {
2013 if ((*i)->is_mark()) {
2014 _session->locations()->remove (*i);
2021 XMLNode &after = _session->locations()->get_state();
2022 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2024 commit_reversible_command ();
2029 /** Add a range marker around each selected region */
2031 Editor::add_locations_from_region ()
2033 RegionSelection rs = get_regions_from_selection_and_entered ();
2039 begin_reversible_command (selection->regions.size () > 1 ? _("add markers") : _("add marker"));
2041 XMLNode &before = _session->locations()->get_state();
2043 for (RegionSelection::iterator i = rs.begin (); i != rs.end (); ++i) {
2045 boost::shared_ptr<Region> region = (*i)->region ();
2047 Location *location = new Location (*_session, region->position(), region->last_frame(), region->name(), Location::IsRangeMarker);
2049 _session->locations()->add (location, true);
2052 XMLNode &after = _session->locations()->get_state();
2053 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2055 commit_reversible_command ();
2058 /** Add a single range marker around all selected regions */
2060 Editor::add_location_from_region ()
2062 RegionSelection rs = get_regions_from_selection_and_entered ();
2068 begin_reversible_command (_("add marker"));
2070 XMLNode &before = _session->locations()->get_state();
2074 if (rs.size() > 1) {
2075 _session->locations()->next_available_name(markername, "regions");
2077 RegionView* rv = *(rs.begin());
2078 boost::shared_ptr<Region> region = rv->region();
2079 markername = region->name();
2082 if (!choose_new_marker_name(markername)) {
2086 // single range spanning all selected
2087 Location *location = new Location (*_session, selection->regions.start(), selection->regions.end_frame(), markername, Location::IsRangeMarker);
2088 _session->locations()->add (location, true);
2090 XMLNode &after = _session->locations()->get_state();
2091 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2093 commit_reversible_command ();
2099 Editor::jump_forward_to_mark ()
2105 framepos_t pos = _session->locations()->first_mark_after (playhead_cursor->current_frame());
2111 _session->request_locate (pos, _session->transport_rolling());
2115 Editor::jump_backward_to_mark ()
2121 framepos_t pos = _session->locations()->first_mark_before (playhead_cursor->current_frame());
2127 _session->request_locate (pos, _session->transport_rolling());
2133 framepos_t const pos = _session->audible_frame ();
2136 _session->locations()->next_available_name (markername, "mark");
2138 if (!choose_new_marker_name (markername)) {
2142 _session->locations()->add (new Location (*_session, pos, 0, markername, Location::IsMark), true);
2146 Editor::clear_markers ()
2149 begin_reversible_command (_("clear markers"));
2151 XMLNode &before = _session->locations()->get_state();
2152 _session->locations()->clear_markers ();
2153 XMLNode &after = _session->locations()->get_state();
2154 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2156 commit_reversible_command ();
2161 Editor::clear_ranges ()
2164 begin_reversible_command (_("clear ranges"));
2166 XMLNode &before = _session->locations()->get_state();
2168 _session->locations()->clear_ranges ();
2170 XMLNode &after = _session->locations()->get_state();
2171 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2173 commit_reversible_command ();
2178 Editor::clear_locations ()
2180 begin_reversible_command (_("clear locations"));
2182 XMLNode &before = _session->locations()->get_state();
2183 _session->locations()->clear ();
2184 XMLNode &after = _session->locations()->get_state();
2185 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2187 commit_reversible_command ();
2191 Editor::unhide_markers ()
2193 for (LocationMarkerMap::iterator i = location_markers.begin(); i != location_markers.end(); ++i) {
2194 Location *l = (*i).first;
2195 if (l->is_hidden() && l->is_mark()) {
2196 l->set_hidden(false, this);
2202 Editor::unhide_ranges ()
2204 for (LocationMarkerMap::iterator i = location_markers.begin(); i != location_markers.end(); ++i) {
2205 Location *l = (*i).first;
2206 if (l->is_hidden() && l->is_range_marker()) {
2207 l->set_hidden(false, this);
2212 /* INSERT/REPLACE */
2215 Editor::insert_region_list_selection (float times)
2217 RouteTimeAxisView *tv = 0;
2218 boost::shared_ptr<Playlist> playlist;
2220 if (clicked_routeview != 0) {
2221 tv = clicked_routeview;
2222 } else if (!selection->tracks.empty()) {
2223 if ((tv = dynamic_cast<RouteTimeAxisView*>(selection->tracks.front())) == 0) {
2226 } else if (entered_track != 0) {
2227 if ((tv = dynamic_cast<RouteTimeAxisView*>(entered_track)) == 0) {
2234 if ((playlist = tv->playlist()) == 0) {
2238 boost::shared_ptr<Region> region = _regions->get_single_selection ();
2243 begin_reversible_command (_("insert region"));
2244 playlist->clear_changes ();
2245 playlist->add_region ((RegionFactory::create (region, true)), get_preferred_edit_position(), times);
2246 if (Config->get_edit_mode() == Ripple)
2247 playlist->ripple (get_preferred_edit_position(), region->length() * times, boost::shared_ptr<Region>());
2249 _session->add_command(new StatefulDiffCommand (playlist));
2250 commit_reversible_command ();
2253 /* BUILT-IN EFFECTS */
2256 Editor::reverse_selection ()
2261 /* GAIN ENVELOPE EDITING */
2264 Editor::edit_envelope ()
2271 Editor::transition_to_rolling (bool fwd)
2277 if (_session->config.get_external_sync()) {
2278 switch (Config->get_sync_source()) {
2282 /* transport controlled by the master */
2287 if (_session->is_auditioning()) {
2288 _session->cancel_audition ();
2292 _session->request_transport_speed (fwd ? 1.0f : -1.0f);
2296 Editor::play_from_start ()
2298 _session->request_locate (_session->current_start_frame(), true);
2302 Editor::play_from_edit_point ()
2304 _session->request_locate (get_preferred_edit_position(), true);
2308 Editor::play_from_edit_point_and_return ()
2310 framepos_t start_frame;
2311 framepos_t return_frame;
2313 start_frame = get_preferred_edit_position (true);
2315 if (_session->transport_rolling()) {
2316 _session->request_locate (start_frame, false);
2320 /* don't reset the return frame if its already set */
2322 if ((return_frame = _session->requested_return_frame()) < 0) {
2323 return_frame = _session->audible_frame();
2326 if (start_frame >= 0) {
2327 _session->request_roll_at_and_return (start_frame, return_frame);
2332 Editor::play_selection ()
2334 if (selection->time.empty()) {
2338 _session->request_play_range (&selection->time, true);
2342 Editor::get_preroll ()
2344 return 1.0 /*Config->get_edit_preroll_seconds()*/ * _session->frame_rate();
2349 Editor::maybe_locate_with_edit_preroll ( framepos_t location )
2351 if ( _session->transport_rolling() || !ARDOUR_UI::config()->get_follow_edits() || _ignore_follow_edits )
2354 location -= get_preroll();
2356 //don't try to locate before the beginning of time
2360 //if follow_playhead is on, keep the playhead on the screen
2361 if ( _follow_playhead )
2362 if ( location < leftmost_frame )
2363 location = leftmost_frame;
2365 _session->request_locate( location );
2369 Editor::play_with_preroll ()
2371 if (selection->time.empty()) {
2374 framepos_t preroll = get_preroll();
2376 framepos_t start = 0;
2377 if (selection->time[clicked_selection].start > preroll)
2378 start = selection->time[clicked_selection].start - preroll;
2380 framepos_t end = selection->time[clicked_selection].end + preroll;
2382 AudioRange ar (start, end, 0);
2383 list<AudioRange> lar;
2386 _session->request_play_range (&lar, true);
2391 Editor::play_location (Location& location)
2393 if (location.start() <= location.end()) {
2397 _session->request_bounded_roll (location.start(), location.end());
2401 Editor::loop_location (Location& location)
2403 if (location.start() <= location.end()) {
2409 if ((tll = transport_loop_location()) != 0) {
2410 tll->set (location.start(), location.end());
2412 // enable looping, reposition and start rolling
2413 _session->request_locate (tll->start(), true);
2414 _session->request_play_loop (true);
2419 Editor::do_layer_operation (LayerOperation op)
2421 if (selection->regions.empty ()) {
2425 bool const multiple = selection->regions.size() > 1;
2429 begin_reversible_command (_("raise regions"));
2431 begin_reversible_command (_("raise region"));
2437 begin_reversible_command (_("raise regions to top"));
2439 begin_reversible_command (_("raise region to top"));
2445 begin_reversible_command (_("lower regions"));
2447 begin_reversible_command (_("lower region"));
2453 begin_reversible_command (_("lower regions to bottom"));
2455 begin_reversible_command (_("lower region"));
2460 set<boost::shared_ptr<Playlist> > playlists = selection->regions.playlists ();
2461 for (set<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
2462 (*i)->clear_owned_changes ();
2465 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
2466 boost::shared_ptr<Region> r = (*i)->region ();
2478 r->lower_to_bottom ();
2482 for (set<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
2483 vector<Command*> cmds;
2485 _session->add_commands (cmds);
2488 commit_reversible_command ();
2492 Editor::raise_region ()
2494 do_layer_operation (Raise);
2498 Editor::raise_region_to_top ()
2500 do_layer_operation (RaiseToTop);
2504 Editor::lower_region ()
2506 do_layer_operation (Lower);
2510 Editor::lower_region_to_bottom ()
2512 do_layer_operation (LowerToBottom);
2515 /** Show the region editor for the selected regions */
2517 Editor::show_region_properties ()
2519 selection->foreach_regionview (&RegionView::show_region_editor);
2522 /** Show the midi list editor for the selected MIDI regions */
2524 Editor::show_midi_list_editor ()
2526 selection->foreach_midi_regionview (&MidiRegionView::show_list_editor);
2530 Editor::rename_region ()
2532 RegionSelection rs = get_regions_from_selection_and_entered ();
2538 ArdourDialog d (*this, _("Rename Region"), true, false);
2540 Label label (_("New name:"));
2543 hbox.set_spacing (6);
2544 hbox.pack_start (label, false, false);
2545 hbox.pack_start (entry, true, true);
2547 d.get_vbox()->set_border_width (12);
2548 d.get_vbox()->pack_start (hbox, false, false);
2550 d.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
2551 d.add_button(Gtk::Stock::OK, Gtk::RESPONSE_OK);
2553 d.set_size_request (300, -1);
2555 entry.set_text (rs.front()->region()->name());
2556 entry.select_region (0, -1);
2558 entry.signal_activate().connect (sigc::bind (sigc::mem_fun (d, &Dialog::response), RESPONSE_OK));
2564 int const ret = d.run();
2568 if (ret != RESPONSE_OK) {
2572 std::string str = entry.get_text();
2573 strip_whitespace_edges (str);
2575 rs.front()->region()->set_name (str);
2576 _regions->redisplay ();
2581 Editor::audition_playlist_region_via_route (boost::shared_ptr<Region> region, Route& route)
2583 if (_session->is_auditioning()) {
2584 _session->cancel_audition ();
2587 // note: some potential for creativity here, because region doesn't
2588 // have to belong to the playlist that Route is handling
2590 // bool was_soloed = route.soloed();
2592 route.set_solo (true, this);
2594 _session->request_bounded_roll (region->position(), region->position() + region->length());
2596 /* XXX how to unset the solo state ? */
2599 /** Start an audition of the first selected region */
2601 Editor::play_edit_range ()
2603 framepos_t start, end;
2605 if (get_edit_op_range (start, end)) {
2606 _session->request_bounded_roll (start, end);
2611 Editor::play_selected_region ()
2613 framepos_t start = max_framepos;
2616 RegionSelection rs = get_regions_from_selection_and_entered ();
2622 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
2623 if ((*i)->region()->position() < start) {
2624 start = (*i)->region()->position();
2626 if ((*i)->region()->last_frame() + 1 > end) {
2627 end = (*i)->region()->last_frame() + 1;
2631 _session->request_bounded_roll (start, end);
2635 Editor::audition_playlist_region_standalone (boost::shared_ptr<Region> region)
2637 _session->audition_region (region);
2641 Editor::region_from_selection ()
2643 if (clicked_axisview == 0) {
2647 if (selection->time.empty()) {
2651 framepos_t start = selection->time[clicked_selection].start;
2652 framepos_t end = selection->time[clicked_selection].end;
2654 TrackViewList tracks = get_tracks_for_range_action ();
2656 framepos_t selection_cnt = end - start + 1;
2658 for (TrackSelection::iterator i = tracks.begin(); i != tracks.end(); ++i) {
2659 boost::shared_ptr<Region> current;
2660 boost::shared_ptr<Playlist> pl;
2661 framepos_t internal_start;
2664 if ((pl = (*i)->playlist()) == 0) {
2668 if ((current = pl->top_region_at (start)) == 0) {
2672 internal_start = start - current->position();
2673 RegionFactory::region_name (new_name, current->name(), true);
2677 plist.add (ARDOUR::Properties::start, current->start() + internal_start);
2678 plist.add (ARDOUR::Properties::length, selection_cnt);
2679 plist.add (ARDOUR::Properties::name, new_name);
2680 plist.add (ARDOUR::Properties::layer, 0);
2682 boost::shared_ptr<Region> region (RegionFactory::create (current, plist));
2687 Editor::create_region_from_selection (vector<boost::shared_ptr<Region> >& new_regions)
2689 if (selection->time.empty() || selection->tracks.empty()) {
2693 framepos_t start = selection->time[clicked_selection].start;
2694 framepos_t end = selection->time[clicked_selection].end;
2696 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
2697 sort_track_selection (ts);
2699 for (TrackSelection::iterator i = ts.begin(); i != ts.end(); ++i) {
2700 boost::shared_ptr<Region> current;
2701 boost::shared_ptr<Playlist> playlist;
2702 framepos_t internal_start;
2705 if ((playlist = (*i)->playlist()) == 0) {
2709 if ((current = playlist->top_region_at(start)) == 0) {
2713 internal_start = start - current->position();
2714 RegionFactory::region_name (new_name, current->name(), true);
2718 plist.add (ARDOUR::Properties::start, current->start() + internal_start);
2719 plist.add (ARDOUR::Properties::length, end - start + 1);
2720 plist.add (ARDOUR::Properties::name, new_name);
2722 new_regions.push_back (RegionFactory::create (current, plist));
2727 Editor::split_multichannel_region ()
2729 RegionSelection rs = get_regions_from_selection_and_entered ();
2735 vector< boost::shared_ptr<Region> > v;
2737 for (list<RegionView*>::iterator x = rs.begin(); x != rs.end(); ++x) {
2738 (*x)->region()->separate_by_channel (*_session, v);
2743 Editor::new_region_from_selection ()
2745 region_from_selection ();
2746 cancel_selection ();
2750 add_if_covered (RegionView* rv, const AudioRange* ar, RegionSelection* rs)
2752 switch (rv->region()->coverage (ar->start, ar->end - 1)) {
2753 // n.b. -1 because AudioRange::end is one past the end, but coverage expects inclusive ranges
2754 case Evoral::OverlapNone:
2762 * - selected tracks, or if there are none...
2763 * - tracks containing selected regions, or if there are none...
2768 Editor::get_tracks_for_range_action () const
2772 if (selection->tracks.empty()) {
2774 /* use tracks with selected regions */
2776 RegionSelection rs = selection->regions;
2778 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
2779 TimeAxisView* tv = &(*i)->get_time_axis_view();
2781 if (!t.contains (tv)) {
2787 /* no regions and no tracks: use all tracks */
2793 t = selection->tracks;
2796 return t.filter_to_unique_playlists();
2800 Editor::separate_regions_between (const TimeSelection& ts)
2802 bool in_command = false;
2803 boost::shared_ptr<Playlist> playlist;
2804 RegionSelection new_selection;
2806 TrackViewList tmptracks = get_tracks_for_range_action ();
2807 sort_track_selection (tmptracks);
2809 for (TrackSelection::iterator i = tmptracks.begin(); i != tmptracks.end(); ++i) {
2811 RouteTimeAxisView* rtv;
2813 if ((rtv = dynamic_cast<RouteTimeAxisView*> ((*i))) != 0) {
2815 if (rtv->is_track()) {
2817 /* no edits to destructive tracks */
2819 if (rtv->track()->destructive()) {
2823 if ((playlist = rtv->playlist()) != 0) {
2825 playlist->clear_changes ();
2827 /* XXX need to consider musical time selections here at some point */
2829 double speed = rtv->track()->speed();
2832 for (list<AudioRange>::const_iterator t = ts.begin(); t != ts.end(); ++t) {
2834 sigc::connection c = rtv->view()->RegionViewAdded.connect (
2835 sigc::mem_fun(*this, &Editor::collect_new_region_view));
2837 latest_regionviews.clear ();
2839 playlist->partition ((framepos_t)((*t).start * speed),
2840 (framepos_t)((*t).end * speed), false);
2844 if (!latest_regionviews.empty()) {
2846 rtv->view()->foreach_regionview (sigc::bind (
2847 sigc::ptr_fun (add_if_covered),
2848 &(*t), &new_selection));
2851 begin_reversible_command (_("separate"));
2855 /* pick up changes to existing regions */
2857 vector<Command*> cmds;
2858 playlist->rdiff (cmds);
2859 _session->add_commands (cmds);
2861 /* pick up changes to the playlist itself (adds/removes)
2864 _session->add_command(new StatefulDiffCommand (playlist));
2873 // selection->set (new_selection);
2875 commit_reversible_command ();
2879 struct PlaylistState {
2880 boost::shared_ptr<Playlist> playlist;
2884 /** Take tracks from get_tracks_for_range_action and cut any regions
2885 * on those tracks so that the tracks are empty over the time
2889 Editor::separate_region_from_selection ()
2891 /* preferentially use *all* ranges in the time selection if we're in range mode
2892 to allow discontiguous operation, since get_edit_op_range() currently
2893 returns a single range.
2896 if (!selection->time.empty()) {
2898 separate_regions_between (selection->time);
2905 if (get_edit_op_range (start, end)) {
2907 AudioRange ar (start, end, 1);
2911 separate_regions_between (ts);
2917 Editor::separate_region_from_punch ()
2919 Location* loc = _session->locations()->auto_punch_location();
2921 separate_regions_using_location (*loc);
2926 Editor::separate_region_from_loop ()
2928 Location* loc = _session->locations()->auto_loop_location();
2930 separate_regions_using_location (*loc);
2935 Editor::separate_regions_using_location (Location& loc)
2937 if (loc.is_mark()) {
2941 AudioRange ar (loc.start(), loc.end(), 1);
2946 separate_regions_between (ts);
2949 /** Separate regions under the selected region */
2951 Editor::separate_under_selected_regions ()
2953 vector<PlaylistState> playlists;
2957 rs = get_regions_from_selection_and_entered();
2959 if (!_session || rs.empty()) {
2963 begin_reversible_command (_("separate region under"));
2965 list<boost::shared_ptr<Region> > regions_to_remove;
2967 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
2968 // we can't just remove the region(s) in this loop because
2969 // this removes them from the RegionSelection, and they thus
2970 // disappear from underneath the iterator, and the ++i above
2971 // SEGVs in a puzzling fashion.
2973 // so, first iterate over the regions to be removed from rs and
2974 // add them to the regions_to_remove list, and then
2975 // iterate over the list to actually remove them.
2977 regions_to_remove.push_back ((*i)->region());
2980 for (list<boost::shared_ptr<Region> >::iterator rl = regions_to_remove.begin(); rl != regions_to_remove.end(); ++rl) {
2982 boost::shared_ptr<Playlist> playlist = (*rl)->playlist();
2985 // is this check necessary?
2989 vector<PlaylistState>::iterator i;
2991 //only take state if this is a new playlist.
2992 for (i = playlists.begin(); i != playlists.end(); ++i) {
2993 if ((*i).playlist == playlist) {
2998 if (i == playlists.end()) {
3000 PlaylistState before;
3001 before.playlist = playlist;
3002 before.before = &playlist->get_state();
3004 playlist->freeze ();
3005 playlists.push_back(before);
3008 //Partition on the region bounds
3009 playlist->partition ((*rl)->first_frame() - 1, (*rl)->last_frame() + 1, true);
3011 //Re-add region that was just removed due to the partition operation
3012 playlist->add_region( (*rl), (*rl)->first_frame() );
3015 vector<PlaylistState>::iterator pl;
3017 for (pl = playlists.begin(); pl != playlists.end(); ++pl) {
3018 (*pl).playlist->thaw ();
3019 _session->add_command(new MementoCommand<Playlist>(*(*pl).playlist, (*pl).before, &(*pl).playlist->get_state()));
3022 commit_reversible_command ();
3026 Editor::crop_region_to_selection ()
3028 if (!selection->time.empty()) {
3030 crop_region_to (selection->time.start(), selection->time.end_frame());
3037 if (get_edit_op_range (start, end)) {
3038 crop_region_to (start, end);
3045 Editor::crop_region_to (framepos_t start, framepos_t end)
3047 vector<boost::shared_ptr<Playlist> > playlists;
3048 boost::shared_ptr<Playlist> playlist;
3051 if (selection->tracks.empty()) {
3052 ts = track_views.filter_to_unique_playlists();
3054 ts = selection->tracks.filter_to_unique_playlists ();
3057 sort_track_selection (ts);
3059 for (TrackSelection::iterator i = ts.begin(); i != ts.end(); ++i) {
3061 RouteTimeAxisView* rtv;
3063 if ((rtv = dynamic_cast<RouteTimeAxisView*> ((*i))) != 0) {
3065 boost::shared_ptr<Track> t = rtv->track();
3067 if (t != 0 && ! t->destructive()) {
3069 if ((playlist = rtv->playlist()) != 0) {
3070 playlists.push_back (playlist);
3076 if (playlists.empty()) {
3080 framepos_t the_start;
3084 begin_reversible_command (_("trim to selection"));
3086 for (vector<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
3088 boost::shared_ptr<Region> region;
3092 if ((region = (*i)->top_region_at(the_start)) == 0) {
3096 /* now adjust lengths to that we do the right thing
3097 if the selection extends beyond the region
3100 the_start = max (the_start, (framepos_t) region->position());
3101 if (max_framepos - the_start < region->length()) {
3102 the_end = the_start + region->length() - 1;
3104 the_end = max_framepos;
3106 the_end = min (end, the_end);
3107 cnt = the_end - the_start + 1;
3109 region->clear_changes ();
3110 region->trim_to (the_start, cnt);
3111 _session->add_command (new StatefulDiffCommand (region));
3114 commit_reversible_command ();
3118 Editor::region_fill_track ()
3120 RegionSelection rs = get_regions_from_selection_and_entered ();
3122 if (!_session || rs.empty()) {
3126 framepos_t const end = _session->current_end_frame ();
3128 begin_reversible_command (Operations::region_fill);
3130 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3132 boost::shared_ptr<Region> region ((*i)->region());
3134 boost::shared_ptr<Playlist> pl = region->playlist();
3136 if (end <= region->last_frame()) {
3140 double times = (double) (end - region->last_frame()) / (double) region->length();
3146 pl->clear_changes ();
3147 pl->add_region (RegionFactory::create (region, true), region->last_frame(), times);
3148 _session->add_command (new StatefulDiffCommand (pl));
3151 commit_reversible_command ();
3155 Editor::region_fill_selection ()
3157 if (clicked_routeview == 0 || !clicked_routeview->is_audio_track()) {
3161 if (selection->time.empty()) {
3165 boost::shared_ptr<Region> region = _regions->get_single_selection ();
3170 framepos_t start = selection->time[clicked_selection].start;
3171 framepos_t end = selection->time[clicked_selection].end;
3173 boost::shared_ptr<Playlist> playlist;
3175 if (selection->tracks.empty()) {
3179 framepos_t selection_length = end - start;
3180 float times = (float)selection_length / region->length();
3182 begin_reversible_command (Operations::fill_selection);
3184 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
3186 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
3188 if ((playlist = (*i)->playlist()) == 0) {
3192 playlist->clear_changes ();
3193 playlist->add_region (RegionFactory::create (region, true), start, times);
3194 _session->add_command (new StatefulDiffCommand (playlist));
3197 commit_reversible_command ();
3201 Editor::set_region_sync_position ()
3203 set_sync_point (get_preferred_edit_position (), get_regions_from_selection_and_edit_point ());
3207 Editor::set_sync_point (framepos_t where, const RegionSelection& rs)
3209 bool in_command = false;
3211 for (RegionSelection::const_iterator r = rs.begin(); r != rs.end(); ++r) {
3213 if (!(*r)->region()->covers (where)) {
3217 boost::shared_ptr<Region> region ((*r)->region());
3220 begin_reversible_command (_("set sync point"));
3224 region->clear_changes ();
3225 region->set_sync_position (where);
3226 _session->add_command(new StatefulDiffCommand (region));
3230 commit_reversible_command ();
3234 /** Remove the sync positions of the selection */
3236 Editor::remove_region_sync ()
3238 RegionSelection rs = get_regions_from_selection_and_entered ();
3244 begin_reversible_command (_("remove region sync"));
3246 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3248 (*i)->region()->clear_changes ();
3249 (*i)->region()->clear_sync_position ();
3250 _session->add_command(new StatefulDiffCommand ((*i)->region()));
3253 commit_reversible_command ();
3257 Editor::naturalize_region ()
3259 RegionSelection rs = get_regions_from_selection_and_entered ();
3265 if (rs.size() > 1) {
3266 begin_reversible_command (_("move regions to original position"));
3268 begin_reversible_command (_("move region to original position"));
3271 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3272 (*i)->region()->clear_changes ();
3273 (*i)->region()->move_to_natural_position ();
3274 _session->add_command (new StatefulDiffCommand ((*i)->region()));
3277 commit_reversible_command ();
3281 Editor::align_regions (RegionPoint what)
3283 RegionSelection const rs = get_regions_from_selection_and_edit_point ();
3289 begin_reversible_command (_("align selection"));
3291 framepos_t const position = get_preferred_edit_position ();
3293 for (RegionSelection::const_iterator i = rs.begin(); i != rs.end(); ++i) {
3294 align_region_internal ((*i)->region(), what, position);
3297 commit_reversible_command ();
3300 struct RegionSortByTime {
3301 bool operator() (const RegionView* a, const RegionView* b) {
3302 return a->region()->position() < b->region()->position();
3307 Editor::align_regions_relative (RegionPoint point)
3309 RegionSelection const rs = get_regions_from_selection_and_edit_point ();
3315 framepos_t const position = get_preferred_edit_position ();
3317 framepos_t distance = 0;
3321 list<RegionView*> sorted;
3322 rs.by_position (sorted);
3324 boost::shared_ptr<Region> r ((*sorted.begin())->region());
3329 if (position > r->position()) {
3330 distance = position - r->position();
3332 distance = r->position() - position;
3338 if (position > r->last_frame()) {
3339 distance = position - r->last_frame();
3340 pos = r->position() + distance;
3342 distance = r->last_frame() - position;
3343 pos = r->position() - distance;
3349 pos = r->adjust_to_sync (position);
3350 if (pos > r->position()) {
3351 distance = pos - r->position();
3353 distance = r->position() - pos;
3359 if (pos == r->position()) {
3363 begin_reversible_command (_("align selection (relative)"));
3365 /* move first one specially */
3367 r->clear_changes ();
3368 r->set_position (pos);
3369 _session->add_command(new StatefulDiffCommand (r));
3371 /* move rest by the same amount */
3375 for (list<RegionView*>::iterator i = sorted.begin(); i != sorted.end(); ++i) {
3377 boost::shared_ptr<Region> region ((*i)->region());
3379 region->clear_changes ();
3382 region->set_position (region->position() + distance);
3384 region->set_position (region->position() - distance);
3387 _session->add_command(new StatefulDiffCommand (region));
3391 commit_reversible_command ();
3395 Editor::align_region (boost::shared_ptr<Region> region, RegionPoint point, framepos_t position)
3397 begin_reversible_command (_("align region"));
3398 align_region_internal (region, point, position);
3399 commit_reversible_command ();
3403 Editor::align_region_internal (boost::shared_ptr<Region> region, RegionPoint point, framepos_t position)
3405 region->clear_changes ();
3409 region->set_position (region->adjust_to_sync (position));
3413 if (position > region->length()) {
3414 region->set_position (position - region->length());
3419 region->set_position (position);
3423 _session->add_command(new StatefulDiffCommand (region));
3427 Editor::trim_region_front ()
3433 Editor::trim_region_back ()
3435 trim_region (false);
3439 Editor::trim_region (bool front)
3441 framepos_t where = get_preferred_edit_position();
3442 RegionSelection rs = get_regions_from_selection_and_edit_point ();
3448 begin_reversible_command (front ? _("trim front") : _("trim back"));
3450 for (list<RegionView*>::const_iterator i = rs.by_layer().begin(); i != rs.by_layer().end(); ++i) {
3451 if (!(*i)->region()->locked()) {
3453 (*i)->region()->clear_changes ();
3456 (*i)->region()->trim_front (where);
3457 maybe_locate_with_edit_preroll ( where );
3459 (*i)->region()->trim_end (where);
3460 maybe_locate_with_edit_preroll ( where );
3463 _session->add_command (new StatefulDiffCommand ((*i)->region()));
3467 commit_reversible_command ();
3470 /** Trim the end of the selected regions to the position of the edit cursor */
3472 Editor::trim_region_to_loop ()
3474 Location* loc = _session->locations()->auto_loop_location();
3478 trim_region_to_location (*loc, _("trim to loop"));
3482 Editor::trim_region_to_punch ()
3484 Location* loc = _session->locations()->auto_punch_location();
3488 trim_region_to_location (*loc, _("trim to punch"));
3492 Editor::trim_region_to_location (const Location& loc, const char* str)
3494 RegionSelection rs = get_regions_from_selection_and_entered ();
3496 begin_reversible_command (str);
3498 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
3499 RegionView* rv = (*x);
3501 /* require region to span proposed trim */
3502 switch (rv->region()->coverage (loc.start(), loc.end())) {
3503 case Evoral::OverlapInternal:
3509 RouteTimeAxisView* tav = dynamic_cast<RouteTimeAxisView*> (&rv->get_time_axis_view());
3518 if (tav->track() != 0) {
3519 speed = tav->track()->speed();
3522 start = session_frame_to_track_frame (loc.start(), speed);
3523 end = session_frame_to_track_frame (loc.end(), speed);
3525 rv->region()->clear_changes ();
3526 rv->region()->trim_to (start, (end - start));
3527 _session->add_command(new StatefulDiffCommand (rv->region()));
3530 commit_reversible_command ();
3534 Editor::trim_region_to_previous_region_end ()
3536 return trim_to_region(false);
3540 Editor::trim_region_to_next_region_start ()
3542 return trim_to_region(true);
3546 Editor::trim_to_region(bool forward)
3548 RegionSelection rs = get_regions_from_selection_and_entered ();
3550 begin_reversible_command (_("trim to region"));
3552 boost::shared_ptr<Region> next_region;
3554 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
3556 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*x);
3562 AudioTimeAxisView* atav = dynamic_cast<AudioTimeAxisView*> (&arv->get_time_axis_view());
3570 if (atav->track() != 0) {
3571 speed = atav->track()->speed();
3575 boost::shared_ptr<Region> region = arv->region();
3576 boost::shared_ptr<Playlist> playlist (region->playlist());
3578 region->clear_changes ();
3582 next_region = playlist->find_next_region (region->first_frame(), Start, 1);
3588 region->trim_end((framepos_t) ( (next_region->first_frame() - 1) * speed));
3589 arv->region_changed (PropertyChange (ARDOUR::Properties::length));
3593 next_region = playlist->find_next_region (region->first_frame(), Start, 0);
3599 region->trim_front((framepos_t) ((next_region->last_frame() + 1) * speed));
3601 arv->region_changed (ARDOUR::bounds_change);
3604 _session->add_command(new StatefulDiffCommand (region));
3607 commit_reversible_command ();
3611 Editor::unfreeze_route ()
3613 if (clicked_routeview == 0 || !clicked_routeview->is_track()) {
3617 clicked_routeview->track()->unfreeze ();
3621 Editor::_freeze_thread (void* arg)
3623 return static_cast<Editor*>(arg)->freeze_thread ();
3627 Editor::freeze_thread ()
3629 /* create event pool because we may need to talk to the session */
3630 SessionEvent::create_per_thread_pool ("freeze events", 64);
3631 /* create per-thread buffers for process() tree to use */
3632 clicked_routeview->audio_track()->freeze_me (*current_interthread_info);
3633 current_interthread_info->done = true;
3638 Editor::freeze_route ()
3644 /* stop transport before we start. this is important */
3646 _session->request_transport_speed (0.0);
3648 /* wait for just a little while, because the above call is asynchronous */
3650 Glib::usleep (250000);
3652 if (clicked_routeview == 0 || !clicked_routeview->is_audio_track()) {
3656 if (!clicked_routeview->track()->bounceable (clicked_routeview->track()->main_outs(), true)) {
3658 _("This track/bus cannot be frozen because the signal adds or loses channels before reaching the outputs.\n"
3659 "This is typically caused by plugins that generate stereo output from mono input or vice versa.")
3661 d.set_title (_("Cannot freeze"));
3666 if (clicked_routeview->track()->has_external_redirects()) {
3667 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"
3668 "Freezing will only process the signal as far as the first send/insert/return."),
3669 clicked_routeview->track()->name()), true, MESSAGE_INFO, BUTTONS_NONE, true);
3671 d.add_button (_("Freeze anyway"), Gtk::RESPONSE_OK);
3672 d.add_button (_("Don't freeze"), Gtk::RESPONSE_CANCEL);
3673 d.set_title (_("Freeze Limits"));
3675 int response = d.run ();
3678 case Gtk::RESPONSE_CANCEL:
3685 InterThreadInfo itt;
3686 current_interthread_info = &itt;
3688 InterthreadProgressWindow ipw (current_interthread_info, _("Freeze"), _("Cancel Freeze"));
3690 pthread_create_and_store (X_("freezer"), &itt.thread, _freeze_thread, this);
3692 CursorContext::Handle cursor_ctx = CursorContext::create(*this, _cursors->wait);
3694 while (!itt.done && !itt.cancel) {
3695 gtk_main_iteration ();
3698 current_interthread_info = 0;
3702 Editor::bounce_range_selection (bool replace, bool enable_processing)
3704 if (selection->time.empty()) {
3708 TrackSelection views = selection->tracks;
3710 for (TrackViewList::iterator i = views.begin(); i != views.end(); ++i) {
3712 if (enable_processing) {
3714 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*i);
3716 if (rtv && rtv->track() && replace && enable_processing && !rtv->track()->bounceable (rtv->track()->main_outs(), false)) {
3718 _("You can't perform this operation because the processing of the signal "
3719 "will cause one or more of the tracks to end up with a region with more channels than this track has inputs.\n\n"
3720 "You can do this without processing, which is a different operation.")
3722 d.set_title (_("Cannot bounce"));
3729 framepos_t start = selection->time[clicked_selection].start;
3730 framepos_t end = selection->time[clicked_selection].end;
3731 framepos_t cnt = end - start + 1;
3733 begin_reversible_command (_("bounce range"));
3735 for (TrackViewList::iterator i = views.begin(); i != views.end(); ++i) {
3737 RouteTimeAxisView* rtv;
3739 if ((rtv = dynamic_cast<RouteTimeAxisView*> (*i)) == 0) {
3743 boost::shared_ptr<Playlist> playlist;
3745 if ((playlist = rtv->playlist()) == 0) {
3749 InterThreadInfo itt;
3751 playlist->clear_changes ();
3752 playlist->clear_owned_changes ();
3754 boost::shared_ptr<Region> r;
3756 if (enable_processing) {
3757 r = rtv->track()->bounce_range (start, start+cnt, itt, rtv->track()->main_outs(), false);
3759 r = rtv->track()->bounce_range (start, start+cnt, itt, boost::shared_ptr<Processor>(), false);
3767 list<AudioRange> ranges;
3768 ranges.push_back (AudioRange (start, start+cnt, 0));
3769 playlist->cut (ranges); // discard result
3770 playlist->add_region (r, start);
3773 vector<Command*> cmds;
3774 playlist->rdiff (cmds);
3775 _session->add_commands (cmds);
3777 _session->add_command (new StatefulDiffCommand (playlist));
3780 commit_reversible_command ();
3783 /** Delete selected regions, automation points or a time range */
3787 //special case: if the user is pointing in the editor/mixer strip, they may be trying to delete a plugin.
3788 //we need this because the editor-mixer strip is in the editor window, so it doesn't get the bindings from the mix window
3789 bool deleted = false;
3790 if ( current_mixer_strip && current_mixer_strip == MixerStrip::entered_mixer_strip() )
3791 deleted = current_mixer_strip->delete_processors ();
3797 /** Cut selected regions, automation points or a time range */
3804 /** Copy selected regions, automation points or a time range */
3812 /** @return true if a Cut, Copy or Clear is possible */
3814 Editor::can_cut_copy () const
3816 if (!selection->time.empty() || !selection->regions.empty() || !selection->points.empty())
3823 /** Cut, copy or clear selected regions, automation points or a time range.
3824 * @param op Operation (Delete, Cut, Copy or Clear)
3827 Editor::cut_copy (CutCopyOp op)
3829 /* only cancel selection if cut/copy is successful.*/
3835 opname = _("delete");
3844 opname = _("clear");
3848 /* if we're deleting something, and the mouse is still pressed,
3849 the thing we started a drag for will be gone when we release
3850 the mouse button(s). avoid this. see part 2 at the end of
3854 if (op == Delete || op == Cut || op == Clear) {
3855 if (_drags->active ()) {
3860 if ( op != Delete ) //"Delete" doesn't change copy/paste buf
3861 cut_buffer->clear ();
3863 if (entered_marker) {
3865 /* cut/delete op while pointing at a marker */
3868 Location* loc = find_location_from_marker (entered_marker, ignored);
3870 if (_session && loc) {
3871 Glib::signal_idle().connect (sigc::bind (sigc::mem_fun(*this, &Editor::really_remove_marker), loc));
3878 switch (mouse_mode) {
3881 begin_reversible_command (opname + ' ' + X_("MIDI"));
3883 commit_reversible_command ();
3889 bool did_edit = false;
3891 if (!selection->regions.empty() || !selection->points.empty()) {
3892 begin_reversible_command (opname + ' ' + _("objects"));
3895 if (!selection->regions.empty()) {
3896 cut_copy_regions (op, selection->regions);
3898 if (op == Cut || op == Delete) {
3899 selection->clear_regions ();
3903 if (!selection->points.empty()) {
3904 cut_copy_points (op);
3906 if (op == Cut || op == Delete) {
3907 selection->clear_points ();
3910 } else if (selection->time.empty()) {
3911 framepos_t start, end;
3912 /* no time selection, see if we can get an edit range
3915 if (get_edit_op_range (start, end)) {
3916 selection->set (start, end);
3918 } else if (!selection->time.empty()) {
3919 begin_reversible_command (opname + ' ' + _("range"));
3922 cut_copy_ranges (op);
3924 if (op == Cut || op == Delete) {
3925 selection->clear_time ();
3930 /* reset repeated paste state */
3933 commit_reversible_command ();
3936 if (op == Delete || op == Cut || op == Clear) {
3941 struct AutomationRecord {
3942 AutomationRecord () : state (0) , line(NULL) {}
3943 AutomationRecord (XMLNode* s, const AutomationLine* l) : state (s) , line (l) {}
3945 XMLNode* state; ///< state before any operation
3946 const AutomationLine* line; ///< line this came from
3947 boost::shared_ptr<Evoral::ControlList> copy; ///< copied events for the cut buffer
3950 /** Cut, copy or clear selected automation points.
3951 * @param op Operation (Cut, Copy or Clear)
3954 Editor::cut_copy_points (Editing::CutCopyOp op, Evoral::MusicalTime earliest, bool midi)
3956 if (selection->points.empty ()) {
3960 /* XXX: not ideal, as there may be more than one track involved in the point selection */
3961 _last_cut_copy_source_track = &selection->points.front()->line().trackview;
3963 /* Keep a record of the AutomationLists that we end up using in this operation */
3964 typedef std::map<boost::shared_ptr<AutomationList>, AutomationRecord> Lists;
3967 /* Go through all selected points, making an AutomationRecord for each distinct AutomationList */
3968 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
3969 const AutomationLine& line = (*i)->line();
3970 const boost::shared_ptr<AutomationList> al = line.the_list();
3971 if (lists.find (al) == lists.end ()) {
3972 /* We haven't seen this list yet, so make a record for it. This includes
3973 taking a copy of its current state, in case this is needed for undo later.
3975 lists[al] = AutomationRecord (&al->get_state (), &line);
3979 if (op == Cut || op == Copy) {
3980 /* This operation will involve putting things in the cut buffer, so create an empty
3981 ControlList for each of our source lists to put the cut buffer data in.
3983 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
3984 i->second.copy = i->first->create (i->first->parameter (), i->first->descriptor());
3987 /* Add all selected points to the relevant copy ControlLists */
3988 framepos_t start = std::numeric_limits<framepos_t>::max();
3989 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
3990 boost::shared_ptr<AutomationList> al = (*i)->line().the_list();
3991 AutomationList::const_iterator j = (*i)->model();
3993 lists[al].copy->fast_simple_add ((*j)->when, (*j)->value);
3995 /* Update earliest MIDI start time in beats */
3996 earliest = std::min(earliest, Evoral::MusicalTime((*j)->when));
3998 /* Update earliest session start time in frames */
3999 start = std::min(start, (*i)->line().session_position(j));
4003 /* Snap start time backwards, so copy/paste is snap aligned. */
4005 if (earliest == Evoral::MusicalTime::max()) {
4006 earliest = Evoral::MusicalTime(); // Weird... don't offset
4008 earliest.round_down_to_beat();
4010 if (start == std::numeric_limits<double>::max()) {
4011 start = 0; // Weird... don't offset
4013 snap_to(start, RoundDownMaybe);
4016 const double line_offset = midi ? earliest.to_double() : start;
4017 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
4018 /* Correct this copy list so that it is relative to the earliest
4019 start time, so relative ordering between points is preserved
4020 when copying from several lists and the paste starts at the
4021 earliest copied piece of data. */
4022 for (AutomationList::iterator j = i->second.copy->begin(); j != i->second.copy->end(); ++j) {
4023 (*j)->when -= line_offset;
4026 /* And add it to the cut buffer */
4027 cut_buffer->add (i->second.copy);
4031 if (op == Delete || op == Cut) {
4032 /* This operation needs to remove things from the main AutomationList, so do that now */
4034 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
4035 i->first->freeze ();
4038 /* Remove each selected point from its AutomationList */
4039 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
4040 boost::shared_ptr<AutomationList> al = (*i)->line().the_list();
4041 al->erase ((*i)->model ());
4044 /* Thaw the lists and add undo records for them */
4045 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
4046 boost::shared_ptr<AutomationList> al = i->first;
4048 _session->add_command (new MementoCommand<AutomationList> (*al.get(), i->second.state, &(al->get_state ())));
4053 /** Cut, copy or clear selected automation points.
4054 * @param op Operation (Cut, Copy or Clear)
4057 Editor::cut_copy_midi (CutCopyOp op)
4059 Evoral::MusicalTime earliest = Evoral::MusicalTime::max();
4060 for (MidiRegionSelection::iterator i = selection->midi_regions.begin(); i != selection->midi_regions.end(); ++i) {
4061 MidiRegionView* mrv = dynamic_cast<MidiRegionView*>(*i);
4063 if (!mrv->selection().empty()) {
4064 earliest = std::min(earliest, (*mrv->selection().begin())->note()->time());
4066 mrv->cut_copy_clear (op);
4068 /* XXX: not ideal, as there may be more than one track involved in the selection */
4069 _last_cut_copy_source_track = &mrv->get_time_axis_view();
4073 if (!selection->points.empty()) {
4074 cut_copy_points (op, earliest, true);
4075 if (op == Cut || op == Delete) {
4076 selection->clear_points ();
4081 struct lt_playlist {
4082 bool operator () (const PlaylistState& a, const PlaylistState& b) {
4083 return a.playlist < b.playlist;
4087 struct PlaylistMapping {
4089 boost::shared_ptr<Playlist> pl;
4091 PlaylistMapping (TimeAxisView* tvp) : tv (tvp) {}
4094 /** Remove `clicked_regionview' */
4096 Editor::remove_clicked_region ()
4098 if (clicked_routeview == 0 || clicked_regionview == 0) {
4102 begin_reversible_command (_("remove region"));
4104 boost::shared_ptr<Playlist> playlist = clicked_routeview->playlist();
4106 playlist->clear_changes ();
4107 playlist->clear_owned_changes ();
4108 playlist->remove_region (clicked_regionview->region());
4109 if (Config->get_edit_mode() == Ripple)
4110 playlist->ripple (clicked_regionview->region()->position(), -clicked_regionview->region()->length(), boost::shared_ptr<Region>());
4112 /* We might have removed regions, which alters other regions' layering_index,
4113 so we need to do a recursive diff here.
4115 vector<Command*> cmds;
4116 playlist->rdiff (cmds);
4117 _session->add_commands (cmds);
4119 _session->add_command(new StatefulDiffCommand (playlist));
4120 commit_reversible_command ();
4124 /** Remove the selected regions */
4126 Editor::remove_selected_regions ()
4128 RegionSelection rs = get_regions_from_selection_and_entered ();
4130 if (!_session || rs.empty()) {
4134 begin_reversible_command (_("remove region"));
4136 list<boost::shared_ptr<Region> > regions_to_remove;
4138 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
4139 // we can't just remove the region(s) in this loop because
4140 // this removes them from the RegionSelection, and they thus
4141 // disappear from underneath the iterator, and the ++i above
4142 // SEGVs in a puzzling fashion.
4144 // so, first iterate over the regions to be removed from rs and
4145 // add them to the regions_to_remove list, and then
4146 // iterate over the list to actually remove them.
4148 regions_to_remove.push_back ((*i)->region());
4151 vector<boost::shared_ptr<Playlist> > playlists;
4153 for (list<boost::shared_ptr<Region> >::iterator rl = regions_to_remove.begin(); rl != regions_to_remove.end(); ++rl) {
4155 boost::shared_ptr<Playlist> playlist = (*rl)->playlist();
4158 // is this check necessary?
4162 /* get_regions_from_selection_and_entered() guarantees that
4163 the playlists involved are unique, so there is no need
4167 playlists.push_back (playlist);
4169 playlist->clear_changes ();
4170 playlist->clear_owned_changes ();
4171 playlist->freeze ();
4172 playlist->remove_region (*rl);
4173 if (Config->get_edit_mode() == Ripple)
4174 playlist->ripple ((*rl)->position(), -(*rl)->length(), boost::shared_ptr<Region>());
4178 vector<boost::shared_ptr<Playlist> >::iterator pl;
4180 for (pl = playlists.begin(); pl != playlists.end(); ++pl) {
4183 /* We might have removed regions, which alters other regions' layering_index,
4184 so we need to do a recursive diff here.
4186 vector<Command*> cmds;
4187 (*pl)->rdiff (cmds);
4188 _session->add_commands (cmds);
4190 _session->add_command(new StatefulDiffCommand (*pl));
4193 commit_reversible_command ();
4196 /** Cut, copy or clear selected regions.
4197 * @param op Operation (Cut, Copy or Clear)
4200 Editor::cut_copy_regions (CutCopyOp op, RegionSelection& rs)
4202 /* we can't use a std::map here because the ordering is important, and we can't trivially sort
4203 a map when we want ordered access to both elements. i think.
4206 vector<PlaylistMapping> pmap;
4208 framepos_t first_position = max_framepos;
4210 typedef set<boost::shared_ptr<Playlist> > FreezeList;
4211 FreezeList freezelist;
4213 /* get ordering correct before we cut/copy */
4215 rs.sort_by_position_and_track ();
4217 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
4219 first_position = min ((framepos_t) (*x)->region()->position(), first_position);
4221 if (op == Cut || op == Clear || op == Delete) {
4222 boost::shared_ptr<Playlist> pl = (*x)->region()->playlist();
4225 FreezeList::iterator fl;
4227 // only take state if this is a new playlist.
4228 for (fl = freezelist.begin(); fl != freezelist.end(); ++fl) {
4234 if (fl == freezelist.end()) {
4235 pl->clear_changes();
4236 pl->clear_owned_changes ();
4238 freezelist.insert (pl);
4243 TimeAxisView* tv = &(*x)->get_time_axis_view();
4244 vector<PlaylistMapping>::iterator z;
4246 for (z = pmap.begin(); z != pmap.end(); ++z) {
4247 if ((*z).tv == tv) {
4252 if (z == pmap.end()) {
4253 pmap.push_back (PlaylistMapping (tv));
4257 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ) {
4259 boost::shared_ptr<Playlist> pl = (*x)->region()->playlist();
4262 /* region not yet associated with a playlist (e.g. unfinished
4269 TimeAxisView& tv = (*x)->get_time_axis_view();
4270 boost::shared_ptr<Playlist> npl;
4271 RegionSelection::iterator tmp;
4278 vector<PlaylistMapping>::iterator z;
4280 for (z = pmap.begin(); z != pmap.end(); ++z) {
4281 if ((*z).tv == &tv) {
4286 assert (z != pmap.end());
4289 npl = PlaylistFactory::create (pl->data_type(), *_session, "cutlist", true);
4297 boost::shared_ptr<Region> r = (*x)->region();
4298 boost::shared_ptr<Region> _xx;
4304 pl->remove_region (r);
4305 if (Config->get_edit_mode() == Ripple)
4306 pl->ripple (r->position(), -r->length(), boost::shared_ptr<Region>());
4310 _xx = RegionFactory::create (r);
4311 npl->add_region (_xx, r->position() - first_position);
4312 pl->remove_region (r);
4313 if (Config->get_edit_mode() == Ripple)
4314 pl->ripple (r->position(), -r->length(), boost::shared_ptr<Region>());
4318 /* copy region before adding, so we're not putting same object into two different playlists */
4319 npl->add_region (RegionFactory::create (r), r->position() - first_position);
4323 pl->remove_region (r);
4324 if (Config->get_edit_mode() == Ripple)
4325 pl->ripple (r->position(), -r->length(), boost::shared_ptr<Region>());
4334 list<boost::shared_ptr<Playlist> > foo;
4336 /* the pmap is in the same order as the tracks in which selected regions occured */
4338 for (vector<PlaylistMapping>::iterator i = pmap.begin(); i != pmap.end(); ++i) {
4341 foo.push_back ((*i).pl);
4346 cut_buffer->set (foo);
4350 _last_cut_copy_source_track = 0;
4352 _last_cut_copy_source_track = pmap.front().tv;
4356 for (FreezeList::iterator pl = freezelist.begin(); pl != freezelist.end(); ++pl) {
4359 /* We might have removed regions, which alters other regions' layering_index,
4360 so we need to do a recursive diff here.
4362 vector<Command*> cmds;
4363 (*pl)->rdiff (cmds);
4364 _session->add_commands (cmds);
4366 _session->add_command (new StatefulDiffCommand (*pl));
4371 Editor::cut_copy_ranges (CutCopyOp op)
4373 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4375 /* Sort the track selection now, so that it if is used, the playlists
4376 selected by the calls below to cut_copy_clear are in the order that
4377 their tracks appear in the editor. This makes things like paste
4378 of ranges work properly.
4381 sort_track_selection (ts);
4384 if (!entered_track) {
4387 ts.push_back (entered_track);
4390 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4391 (*i)->cut_copy_clear (*selection, op);
4396 Editor::paste (float times, bool from_context)
4398 DEBUG_TRACE (DEBUG::CutNPaste, "paste to preferred edit pos\n");
4400 paste_internal (get_preferred_edit_position (false, from_context), times);
4404 Editor::mouse_paste ()
4409 if (!mouse_frame (where, ignored)) {
4414 paste_internal (where, 1);
4418 Editor::paste_internal (framepos_t position, float times)
4420 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("apparent paste position is %1\n", position));
4422 if (cut_buffer->empty(internal_editing())) {
4426 if (position == max_framepos) {
4427 position = get_preferred_edit_position();
4428 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("preferred edit position is %1\n", position));
4431 if (position == last_paste_pos) {
4432 /* repeated paste in the same position */
4435 /* paste in new location, reset repeated paste state */
4437 last_paste_pos = position;
4440 /* get everything in the correct order */
4443 if (!selection->tracks.empty()) {
4444 /* If there is a track selection, paste into exactly those tracks and
4445 only those tracks. This allows the user to be explicit and override
4446 the below "do the reasonable thing" logic. */
4447 ts = selection->tracks.filter_to_unique_playlists ();
4448 sort_track_selection (ts);
4450 /* Figure out which track to base the paste at. */
4451 TimeAxisView* base_track = NULL;
4452 if (_edit_point == Editing::EditAtMouse && entered_track) {
4453 /* With the mouse edit point, paste onto the track under the mouse. */
4454 base_track = entered_track;
4455 } else if (_edit_point == Editing::EditAtMouse && entered_regionview) {
4456 /* With the mouse edit point, paste onto the track of the region under the mouse. */
4457 base_track = &entered_regionview->get_time_axis_view();
4458 } else if (_last_cut_copy_source_track) {
4459 /* Paste to the track that the cut/copy came from (see mantis #333). */
4460 base_track = _last_cut_copy_source_track;
4462 /* This is "impossible" since we've copied... well, do nothing. */
4466 /* Walk up to parent if necessary, so base track is a route. */
4467 while (base_track->get_parent()) {
4468 base_track = base_track->get_parent();
4471 /* Add base track and all tracks below it. The paste logic will select
4472 the appropriate object types from the cut buffer in relative order. */
4473 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4474 if ((*i)->order() >= base_track->order()) {
4479 /* Sort tracks so the nth track of type T will pick the nth object of type T. */
4480 sort_track_selection (ts);
4482 /* Add automation children of each track in order, for pasting several lines. */
4483 for (TrackViewList::iterator i = ts.begin(); i != ts.end();) {
4484 /* Add any automation children for pasting several lines */
4485 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*i++);
4490 typedef RouteTimeAxisView::AutomationTracks ATracks;
4491 const ATracks& atracks = rtv->automation_tracks();
4492 for (ATracks::const_iterator a = atracks.begin(); a != atracks.end(); ++a) {
4493 i = ts.insert(i, a->second.get());
4498 /* We now have a list of trackviews starting at base_track, including
4499 automation children, in the order shown in the editor, e.g. R1,
4500 R1.A1, R1.A2, R2, R2.A1, ... */
4503 begin_reversible_command (Operations::paste);
4505 if (ts.size() == 1 && cut_buffer->lines.size() == 1 &&
4506 dynamic_cast<AutomationTimeAxisView*>(ts.front())) {
4507 /* Only one line copied, and one automation track selected. Do a
4508 "greedy" paste from one automation type to another. */
4510 PasteContext ctx(paste_count, times, ItemCounts(), true);
4511 ts.front()->paste (position, *cut_buffer, ctx);
4515 /* Paste into tracks */
4517 PasteContext ctx(paste_count, times, ItemCounts(), false);
4518 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4519 (*i)->paste (position, *cut_buffer, ctx);
4523 commit_reversible_command ();
4527 Editor::duplicate_some_regions (RegionSelection& regions, float times)
4529 boost::shared_ptr<Playlist> playlist;
4530 RegionSelection sel = regions; // clear (below) may clear the argument list if its the current region selection
4531 RegionSelection foo;
4533 framepos_t const start_frame = regions.start ();
4534 framepos_t const end_frame = regions.end_frame ();
4536 begin_reversible_command (Operations::duplicate_region);
4538 selection->clear_regions ();
4540 for (RegionSelection::iterator i = sel.begin(); i != sel.end(); ++i) {
4542 boost::shared_ptr<Region> r ((*i)->region());
4544 TimeAxisView& tv = (*i)->get_time_axis_view();
4545 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (&tv);
4546 latest_regionviews.clear ();
4547 sigc::connection c = rtv->view()->RegionViewAdded.connect (sigc::mem_fun(*this, &Editor::collect_new_region_view));
4549 playlist = (*i)->region()->playlist();
4550 playlist->clear_changes ();
4551 playlist->duplicate (r, end_frame + (r->first_frame() - start_frame), times);
4552 _session->add_command(new StatefulDiffCommand (playlist));
4556 foo.insert (foo.end(), latest_regionviews.begin(), latest_regionviews.end());
4560 selection->set (foo);
4563 commit_reversible_command ();
4567 Editor::duplicate_selection (float times)
4569 if (selection->time.empty() || selection->tracks.empty()) {
4573 boost::shared_ptr<Playlist> playlist;
4574 vector<boost::shared_ptr<Region> > new_regions;
4575 vector<boost::shared_ptr<Region> >::iterator ri;
4577 create_region_from_selection (new_regions);
4579 if (new_regions.empty()) {
4583 begin_reversible_command (_("duplicate selection"));
4585 ri = new_regions.begin();
4587 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4589 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4590 if ((playlist = (*i)->playlist()) == 0) {
4593 playlist->clear_changes ();
4594 playlist->duplicate (*ri, selection->time[clicked_selection].end, times);
4595 _session->add_command (new StatefulDiffCommand (playlist));
4598 if (ri == new_regions.end()) {
4603 commit_reversible_command ();
4606 /** Reset all selected points to the relevant default value */
4608 Editor::reset_point_selection ()
4610 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
4611 ARDOUR::AutomationList::iterator j = (*i)->model ();
4612 (*j)->value = (*i)->line().the_list()->default_value ();
4617 Editor::center_playhead ()
4619 float const page = _visible_canvas_width * samples_per_pixel;
4620 center_screen_internal (playhead_cursor->current_frame (), page);
4624 Editor::center_edit_point ()
4626 float const page = _visible_canvas_width * samples_per_pixel;
4627 center_screen_internal (get_preferred_edit_position(), page);
4630 /** Caller must begin and commit a reversible command */
4632 Editor::clear_playlist (boost::shared_ptr<Playlist> playlist)
4634 playlist->clear_changes ();
4636 _session->add_command (new StatefulDiffCommand (playlist));
4640 Editor::nudge_track (bool use_edit, bool forwards)
4642 boost::shared_ptr<Playlist> playlist;
4643 framepos_t distance;
4644 framepos_t next_distance;
4648 start = get_preferred_edit_position();
4653 if ((distance = get_nudge_distance (start, next_distance)) == 0) {
4657 if (selection->tracks.empty()) {
4661 begin_reversible_command (_("nudge track"));
4663 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4665 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4667 if ((playlist = (*i)->playlist()) == 0) {
4671 playlist->clear_changes ();
4672 playlist->clear_owned_changes ();
4674 playlist->nudge_after (start, distance, forwards);
4676 vector<Command*> cmds;
4678 playlist->rdiff (cmds);
4679 _session->add_commands (cmds);
4681 _session->add_command (new StatefulDiffCommand (playlist));
4684 commit_reversible_command ();
4688 Editor::remove_last_capture ()
4690 vector<string> choices;
4697 if (Config->get_verify_remove_last_capture()) {
4698 prompt = _("Do you really want to destroy the last capture?"
4699 "\n(This is destructive and cannot be undone)");
4701 choices.push_back (_("No, do nothing."));
4702 choices.push_back (_("Yes, destroy it."));
4704 Gtkmm2ext::Choice prompter (_("Destroy last capture"), prompt, choices);
4706 if (prompter.run () == 1) {
4707 _session->remove_last_capture ();
4708 _regions->redisplay ();
4712 _session->remove_last_capture();
4713 _regions->redisplay ();
4718 Editor::normalize_region ()
4724 RegionSelection rs = get_regions_from_selection_and_entered ();
4730 NormalizeDialog dialog (rs.size() > 1);
4732 if (dialog.run () == RESPONSE_CANCEL) {
4736 CursorContext::Handle cursor_ctx = CursorContext::create(*this, _cursors->wait);
4739 /* XXX: should really only count audio regions here */
4740 int const regions = rs.size ();
4742 /* Make a list of the selected audio regions' maximum amplitudes, and also
4743 obtain the maximum amplitude of them all.
4745 list<double> max_amps;
4747 for (RegionSelection::const_iterator i = rs.begin(); i != rs.end(); ++i) {
4748 AudioRegionView const * arv = dynamic_cast<AudioRegionView const *> (*i);
4750 dialog.descend (1.0 / regions);
4751 double const a = arv->audio_region()->maximum_amplitude (&dialog);
4754 /* the user cancelled the operation */
4758 max_amps.push_back (a);
4759 max_amp = max (max_amp, a);
4764 begin_reversible_command (_("normalize"));
4766 list<double>::const_iterator a = max_amps.begin ();
4768 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
4769 AudioRegionView* const arv = dynamic_cast<AudioRegionView*> (*r);
4774 arv->region()->clear_changes ();
4776 double const amp = dialog.normalize_individually() ? *a : max_amp;
4778 arv->audio_region()->normalize (amp, dialog.target ());
4779 _session->add_command (new StatefulDiffCommand (arv->region()));
4784 commit_reversible_command ();
4789 Editor::reset_region_scale_amplitude ()
4795 RegionSelection rs = get_regions_from_selection_and_entered ();
4801 begin_reversible_command ("reset gain");
4803 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
4804 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
4807 arv->region()->clear_changes ();
4808 arv->audio_region()->set_scale_amplitude (1.0f);
4809 _session->add_command (new StatefulDiffCommand (arv->region()));
4812 commit_reversible_command ();
4816 Editor::adjust_region_gain (bool up)
4818 RegionSelection rs = get_regions_from_selection_and_entered ();
4820 if (!_session || rs.empty()) {
4824 begin_reversible_command ("adjust region gain");
4826 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
4827 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
4832 arv->region()->clear_changes ();
4834 double dB = accurate_coefficient_to_dB (arv->audio_region()->scale_amplitude ());
4842 arv->audio_region()->set_scale_amplitude (dB_to_coefficient (dB));
4843 _session->add_command (new StatefulDiffCommand (arv->region()));
4846 commit_reversible_command ();
4851 Editor::reverse_region ()
4857 Reverse rev (*_session);
4858 apply_filter (rev, _("reverse regions"));
4862 Editor::strip_region_silence ()
4868 RegionSelection rs = get_regions_from_selection_and_entered ();
4874 std::list<RegionView*> audio_only;
4876 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
4877 AudioRegionView* const arv = dynamic_cast<AudioRegionView*> (*i);
4879 audio_only.push_back (arv);
4883 StripSilenceDialog d (_session, audio_only);
4884 int const r = d.run ();
4888 if (r == Gtk::RESPONSE_OK) {
4889 ARDOUR::AudioIntervalMap silences;
4890 d.silences (silences);
4891 StripSilence s (*_session, silences, d.fade_length());
4892 apply_filter (s, _("strip silence"), &d);
4897 Editor::apply_midi_note_edit_op_to_region (MidiOperator& op, MidiRegionView& mrv)
4899 Evoral::Sequence<Evoral::MusicalTime>::Notes selected;
4900 mrv.selection_as_notelist (selected, true);
4902 vector<Evoral::Sequence<Evoral::MusicalTime>::Notes> v;
4903 v.push_back (selected);
4905 framepos_t pos_frames = mrv.midi_region()->position() - mrv.midi_region()->start();
4906 Evoral::MusicalTime pos_beats = _session->tempo_map().framewalk_to_beats(0, pos_frames);
4908 return op (mrv.midi_region()->model(), pos_beats, v);
4912 Editor::apply_midi_note_edit_op (MidiOperator& op, const RegionSelection& rs)
4918 begin_reversible_command (op.name ());
4920 for (RegionSelection::const_iterator r = rs.begin(); r != rs.end(); ) {
4921 RegionSelection::const_iterator tmp = r;
4924 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*r);
4927 Command* cmd = apply_midi_note_edit_op_to_region (op, *mrv);
4930 _session->add_command (cmd);
4937 commit_reversible_command ();
4941 Editor::fork_region ()
4943 RegionSelection rs = get_regions_from_selection_and_entered ();
4949 begin_reversible_command (_("Fork Region(s)"));
4951 CursorContext::Handle cursor_ctx = CursorContext::create(*this, _cursors->wait);
4954 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
4955 RegionSelection::iterator tmp = r;
4958 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*>(*r);
4962 boost::shared_ptr<Playlist> playlist = mrv->region()->playlist();
4963 boost::shared_ptr<MidiSource> new_source = _session->create_midi_source_by_stealing_name (mrv->midi_view()->track());
4964 boost::shared_ptr<MidiRegion> newregion = mrv->midi_region()->clone (new_source);
4966 playlist->clear_changes ();
4967 playlist->replace_region (mrv->region(), newregion, mrv->region()->position());
4968 _session->add_command(new StatefulDiffCommand (playlist));
4970 error << string_compose (_("Could not unlink %1"), mrv->region()->name()) << endmsg;
4977 commit_reversible_command ();
4981 Editor::quantize_region ()
4984 quantize_regions(get_regions_from_selection_and_entered ());
4989 Editor::quantize_regions (const RegionSelection& rs)
4991 if (rs.n_midi_regions() == 0) {
4995 QuantizeDialog* qd = new QuantizeDialog (*this);
4998 const int r = qd->run ();
5001 if (r == Gtk::RESPONSE_OK) {
5002 Quantize quant (qd->snap_start(), qd->snap_end(),
5003 qd->start_grid_size(), qd->end_grid_size(),
5004 qd->strength(), qd->swing(), qd->threshold());
5006 apply_midi_note_edit_op (quant, rs);
5011 Editor::legatize_region (bool shrink_only)
5014 legatize_regions(get_regions_from_selection_and_entered (), shrink_only);
5019 Editor::legatize_regions (const RegionSelection& rs, bool shrink_only)
5021 if (rs.n_midi_regions() == 0) {
5025 Legatize legatize(shrink_only);
5026 apply_midi_note_edit_op (legatize, rs);
5030 Editor::insert_patch_change (bool from_context)
5032 RegionSelection rs = get_regions_from_selection_and_entered ();
5038 const framepos_t p = get_preferred_edit_position (false, from_context);
5040 /* XXX: bit of a hack; use the MIDNAM from the first selected region;
5041 there may be more than one, but the PatchChangeDialog can only offer
5042 one set of patch menus.
5044 MidiRegionView* first = dynamic_cast<MidiRegionView*> (rs.front ());
5046 Evoral::PatchChange<Evoral::MusicalTime> empty (Evoral::MusicalTime(), 0, 0, 0);
5047 PatchChangeDialog d (0, _session, empty, first->instrument_info(), Gtk::Stock::ADD);
5049 if (d.run() == RESPONSE_CANCEL) {
5053 for (RegionSelection::iterator i = rs.begin (); i != rs.end(); ++i) {
5054 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*i);
5056 if (p >= mrv->region()->first_frame() && p <= mrv->region()->last_frame()) {
5057 mrv->add_patch_change (p - mrv->region()->position(), d.patch ());
5064 Editor::apply_filter (Filter& filter, string command, ProgressReporter* progress)
5066 RegionSelection rs = get_regions_from_selection_and_entered ();
5072 begin_reversible_command (command);
5074 CursorContext::Handle cursor_ctx = CursorContext::create(*this, _cursors->wait);
5078 int const N = rs.size ();
5080 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
5081 RegionSelection::iterator tmp = r;
5084 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
5086 boost::shared_ptr<Playlist> playlist = arv->region()->playlist();
5089 progress->descend (1.0 / N);
5092 if (arv->audio_region()->apply (filter, progress) == 0) {
5094 playlist->clear_changes ();
5095 playlist->clear_owned_changes ();
5097 if (filter.results.empty ()) {
5099 /* no regions returned; remove the old one */
5100 playlist->remove_region (arv->region ());
5104 std::vector<boost::shared_ptr<Region> >::iterator res = filter.results.begin ();
5106 /* first region replaces the old one */
5107 playlist->replace_region (arv->region(), *res, (*res)->position());
5111 while (res != filter.results.end()) {
5112 playlist->add_region (*res, (*res)->position());
5118 /* We might have removed regions, which alters other regions' layering_index,
5119 so we need to do a recursive diff here.
5121 vector<Command*> cmds;
5122 playlist->rdiff (cmds);
5123 _session->add_commands (cmds);
5125 _session->add_command(new StatefulDiffCommand (playlist));
5131 progress->ascend ();
5139 commit_reversible_command ();
5143 Editor::external_edit_region ()
5149 Editor::reset_region_gain_envelopes ()
5151 RegionSelection rs = get_regions_from_selection_and_entered ();
5153 if (!_session || rs.empty()) {
5157 begin_reversible_command (_("reset region gain"));
5159 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5160 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
5162 boost::shared_ptr<AutomationList> alist (arv->audio_region()->envelope());
5163 XMLNode& before (alist->get_state());
5165 arv->audio_region()->set_default_envelope ();
5166 _session->add_command (new MementoCommand<AutomationList>(*arv->audio_region()->envelope().get(), &before, &alist->get_state()));
5170 commit_reversible_command ();
5174 Editor::set_region_gain_visibility (RegionView* rv)
5176 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (rv);
5178 arv->update_envelope_visibility();
5183 Editor::set_gain_envelope_visibility ()
5189 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5190 AudioTimeAxisView* v = dynamic_cast<AudioTimeAxisView*>(*i);
5192 v->audio_view()->foreach_regionview (sigc::mem_fun (this, &Editor::set_region_gain_visibility));
5198 Editor::toggle_gain_envelope_active ()
5200 if (_ignore_region_action) {
5204 RegionSelection rs = get_regions_from_selection_and_entered ();
5206 if (!_session || rs.empty()) {
5210 begin_reversible_command (_("region gain envelope active"));
5212 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5213 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
5215 arv->region()->clear_changes ();
5216 arv->audio_region()->set_envelope_active (!arv->audio_region()->envelope_active());
5217 _session->add_command (new StatefulDiffCommand (arv->region()));
5221 commit_reversible_command ();
5225 Editor::toggle_region_lock ()
5227 if (_ignore_region_action) {
5231 RegionSelection rs = get_regions_from_selection_and_entered ();
5233 if (!_session || rs.empty()) {
5237 begin_reversible_command (_("toggle region lock"));
5239 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5240 (*i)->region()->clear_changes ();
5241 (*i)->region()->set_locked (!(*i)->region()->locked());
5242 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5245 commit_reversible_command ();
5249 Editor::toggle_region_video_lock ()
5251 if (_ignore_region_action) {
5255 RegionSelection rs = get_regions_from_selection_and_entered ();
5257 if (!_session || rs.empty()) {
5261 begin_reversible_command (_("Toggle Video Lock"));
5263 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5264 (*i)->region()->clear_changes ();
5265 (*i)->region()->set_video_locked (!(*i)->region()->video_locked());
5266 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5269 commit_reversible_command ();
5273 Editor::toggle_region_lock_style ()
5275 if (_ignore_region_action) {
5279 RegionSelection rs = get_regions_from_selection_and_entered ();
5281 if (!_session || rs.empty()) {
5285 begin_reversible_command (_("region lock style"));
5287 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5288 (*i)->region()->clear_changes ();
5289 PositionLockStyle const ns = (*i)->region()->position_lock_style() == AudioTime ? MusicTime : AudioTime;
5290 (*i)->region()->set_position_lock_style (ns);
5291 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5294 commit_reversible_command ();
5298 Editor::toggle_opaque_region ()
5300 if (_ignore_region_action) {
5304 RegionSelection rs = get_regions_from_selection_and_entered ();
5306 if (!_session || rs.empty()) {
5310 begin_reversible_command (_("change region opacity"));
5312 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5313 (*i)->region()->clear_changes ();
5314 (*i)->region()->set_opaque (!(*i)->region()->opaque());
5315 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5318 commit_reversible_command ();
5322 Editor::toggle_record_enable ()
5324 bool new_state = false;
5326 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5327 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5330 if (!rtav->is_track())
5334 new_state = !rtav->track()->record_enabled();
5338 rtav->track()->set_record_enabled (new_state, this);
5343 Editor::toggle_solo ()
5345 bool new_state = false;
5347 boost::shared_ptr<RouteList> rl (new RouteList);
5349 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5350 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5357 new_state = !rtav->route()->soloed ();
5361 rl->push_back (rtav->route());
5364 _session->set_solo (rl, new_state, Session::rt_cleanup, true);
5368 Editor::toggle_mute ()
5370 bool new_state = false;
5372 boost::shared_ptr<RouteList> rl (new RouteList);
5374 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5375 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5382 new_state = !rtav->route()->muted();
5386 rl->push_back (rtav->route());
5389 _session->set_mute (rl, new_state, Session::rt_cleanup, true);
5393 Editor::toggle_solo_isolate ()
5399 Editor::fade_range ()
5401 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
5403 begin_reversible_command (_("fade range"));
5405 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
5406 (*i)->fade_range (selection->time);
5409 commit_reversible_command ();
5414 Editor::set_fade_length (bool in)
5416 RegionSelection rs = get_regions_from_selection_and_entered ();
5422 /* we need a region to measure the offset from the start */
5424 RegionView* rv = rs.front ();
5426 framepos_t pos = get_preferred_edit_position();
5430 if (pos > rv->region()->last_frame() || pos < rv->region()->first_frame()) {
5431 /* edit point is outside the relevant region */
5436 if (pos <= rv->region()->position()) {
5440 len = pos - rv->region()->position();
5441 cmd = _("set fade in length");
5443 if (pos >= rv->region()->last_frame()) {
5447 len = rv->region()->last_frame() - pos;
5448 cmd = _("set fade out length");
5451 begin_reversible_command (cmd);
5453 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5454 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5460 boost::shared_ptr<AutomationList> alist;
5462 alist = tmp->audio_region()->fade_in();
5464 alist = tmp->audio_region()->fade_out();
5467 XMLNode &before = alist->get_state();
5470 tmp->audio_region()->set_fade_in_length (len);
5471 tmp->audio_region()->set_fade_in_active (true);
5473 tmp->audio_region()->set_fade_out_length (len);
5474 tmp->audio_region()->set_fade_out_active (true);
5477 XMLNode &after = alist->get_state();
5478 _session->add_command(new MementoCommand<AutomationList>(*alist, &before, &after));
5481 commit_reversible_command ();
5485 Editor::set_fade_in_shape (FadeShape shape)
5487 RegionSelection rs = get_regions_from_selection_and_entered ();
5493 begin_reversible_command (_("set fade in shape"));
5495 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5496 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5502 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_in();
5503 XMLNode &before = alist->get_state();
5505 tmp->audio_region()->set_fade_in_shape (shape);
5507 XMLNode &after = alist->get_state();
5508 _session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
5511 commit_reversible_command ();
5516 Editor::set_fade_out_shape (FadeShape shape)
5518 RegionSelection rs = get_regions_from_selection_and_entered ();
5524 begin_reversible_command (_("set fade out shape"));
5526 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5527 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5533 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_out();
5534 XMLNode &before = alist->get_state();
5536 tmp->audio_region()->set_fade_out_shape (shape);
5538 XMLNode &after = alist->get_state();
5539 _session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
5542 commit_reversible_command ();
5546 Editor::set_fade_in_active (bool yn)
5548 RegionSelection rs = get_regions_from_selection_and_entered ();
5554 begin_reversible_command (_("set fade in active"));
5556 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5557 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5564 boost::shared_ptr<AudioRegion> ar (tmp->audio_region());
5566 ar->clear_changes ();
5567 ar->set_fade_in_active (yn);
5568 _session->add_command (new StatefulDiffCommand (ar));
5571 commit_reversible_command ();
5575 Editor::set_fade_out_active (bool yn)
5577 RegionSelection rs = get_regions_from_selection_and_entered ();
5583 begin_reversible_command (_("set fade out active"));
5585 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5586 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5592 boost::shared_ptr<AudioRegion> ar (tmp->audio_region());
5594 ar->clear_changes ();
5595 ar->set_fade_out_active (yn);
5596 _session->add_command(new StatefulDiffCommand (ar));
5599 commit_reversible_command ();
5603 Editor::toggle_region_fades (int dir)
5605 if (_ignore_region_action) {
5609 boost::shared_ptr<AudioRegion> ar;
5612 RegionSelection rs = get_regions_from_selection_and_entered ();
5618 RegionSelection::iterator i;
5619 for (i = rs.begin(); i != rs.end(); ++i) {
5620 if ((ar = boost::dynamic_pointer_cast<AudioRegion>((*i)->region())) != 0) {
5622 yn = ar->fade_out_active ();
5624 yn = ar->fade_in_active ();
5630 if (i == rs.end()) {
5634 /* XXX should this undo-able? */
5636 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5637 if ((ar = boost::dynamic_pointer_cast<AudioRegion>((*i)->region())) == 0) {
5640 if (dir == 1 || dir == 0) {
5641 ar->set_fade_in_active (!yn);
5644 if (dir == -1 || dir == 0) {
5645 ar->set_fade_out_active (!yn);
5651 /** Update region fade visibility after its configuration has been changed */
5653 Editor::update_region_fade_visibility ()
5655 bool _fade_visibility = _session->config.get_show_region_fades ();
5657 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5658 AudioTimeAxisView* v = dynamic_cast<AudioTimeAxisView*>(*i);
5660 if (_fade_visibility) {
5661 v->audio_view()->show_all_fades ();
5663 v->audio_view()->hide_all_fades ();
5670 Editor::set_edit_point ()
5675 if (!mouse_frame (where, ignored)) {
5681 if (selection->markers.empty()) {
5683 mouse_add_new_marker (where);
5688 Location* loc = find_location_from_marker (selection->markers.front(), ignored);
5691 loc->move_to (where);
5697 Editor::set_playhead_cursor ()
5699 if (entered_marker) {
5700 _session->request_locate (entered_marker->position(), _session->transport_rolling());
5705 if (!mouse_frame (where, ignored)) {
5712 _session->request_locate (where, _session->transport_rolling());
5716 if (ARDOUR_UI::config()->get_follow_edits()) {
5717 cancel_time_selection();
5722 Editor::split_region ()
5724 if ( !selection->time.empty()) {
5725 separate_regions_between (selection->time);
5729 RegionSelection rs = get_regions_from_selection_and_edit_point ();
5731 framepos_t where = get_preferred_edit_position ();
5737 split_regions_at (where, rs);
5740 struct EditorOrderRouteSorter {
5741 bool operator() (boost::shared_ptr<Route> a, boost::shared_ptr<Route> b) {
5742 return a->order_key () < b->order_key ();
5747 Editor::select_next_route()
5749 if (selection->tracks.empty()) {
5750 selection->set (track_views.front());
5754 TimeAxisView* current = selection->tracks.front();
5758 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5759 if (*i == current) {
5761 if (i != track_views.end()) {
5764 current = (*(track_views.begin()));
5765 //selection->set (*(track_views.begin()));
5770 rui = dynamic_cast<RouteUI *>(current);
5771 } while ( current->hidden() || (rui != NULL && !rui->route()->active()));
5773 selection->set(current);
5775 ensure_time_axis_view_is_visible (*current, false);
5779 Editor::select_prev_route()
5781 if (selection->tracks.empty()) {
5782 selection->set (track_views.front());
5786 TimeAxisView* current = selection->tracks.front();
5790 for (TrackViewList::reverse_iterator i = track_views.rbegin(); i != track_views.rend(); ++i) {
5791 if (*i == current) {
5793 if (i != track_views.rend()) {
5796 current = *(track_views.rbegin());
5801 rui = dynamic_cast<RouteUI *>(current);
5802 } while ( current->hidden() || (rui != NULL && !rui->route()->active()));
5804 selection->set (current);
5806 ensure_time_axis_view_is_visible (*current, false);
5810 Editor::set_loop_from_selection (bool play)
5812 if (_session == 0 || selection->time.empty()) {
5816 framepos_t start = selection->time[clicked_selection].start;
5817 framepos_t end = selection->time[clicked_selection].end;
5819 set_loop_range (start, end, _("set loop range from selection"));
5822 _session->request_locate (start, true);
5823 _session->request_play_loop (true);
5828 Editor::set_loop_from_edit_range (bool play)
5830 if (_session == 0) {
5837 if (!get_edit_op_range (start, end)) {
5841 set_loop_range (start, end, _("set loop range from edit range"));
5844 _session->request_locate (start, true);
5845 _session->request_play_loop (true);
5850 Editor::set_loop_from_region (bool play)
5852 framepos_t start = max_framepos;
5855 RegionSelection rs = get_regions_from_selection_and_entered ();
5861 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5862 if ((*i)->region()->position() < start) {
5863 start = (*i)->region()->position();
5865 if ((*i)->region()->last_frame() + 1 > end) {
5866 end = (*i)->region()->last_frame() + 1;
5870 set_loop_range (start, end, _("set loop range from region"));
5873 _session->request_locate (start, true);
5874 _session->request_play_loop (true);
5879 Editor::set_punch_from_selection ()
5881 if (_session == 0 || selection->time.empty()) {
5885 framepos_t start = selection->time[clicked_selection].start;
5886 framepos_t end = selection->time[clicked_selection].end;
5888 set_punch_range (start, end, _("set punch range from selection"));
5892 Editor::set_session_extents_from_selection ()
5894 if (_session == 0 || selection->time.empty()) {
5898 begin_reversible_command (_("set session start/stop from selection"));
5900 framepos_t start = selection->time[clicked_selection].start;
5901 framepos_t end = selection->time[clicked_selection].end;
5904 if ((loc = _session->locations()->session_range_location()) == 0) {
5905 _session->set_session_extents ( start, end ); // this will create a new session range; no need for UNDO
5907 XMLNode &before = loc->get_state();
5909 _session->set_session_extents ( start, end );
5911 XMLNode &after = loc->get_state();
5913 _session->add_command (new MementoCommand<Location>(*loc, &before, &after));
5915 commit_reversible_command ();
5920 Editor::set_punch_from_edit_range ()
5922 if (_session == 0) {
5929 if (!get_edit_op_range (start, end)) {
5933 set_punch_range (start, end, _("set punch range from edit range"));
5937 Editor::set_punch_from_region ()
5939 framepos_t start = max_framepos;
5942 RegionSelection rs = get_regions_from_selection_and_entered ();
5948 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5949 if ((*i)->region()->position() < start) {
5950 start = (*i)->region()->position();
5952 if ((*i)->region()->last_frame() + 1 > end) {
5953 end = (*i)->region()->last_frame() + 1;
5957 set_punch_range (start, end, _("set punch range from region"));
5961 Editor::pitch_shift_region ()
5963 RegionSelection rs = get_regions_from_selection_and_entered ();
5965 RegionSelection audio_rs;
5966 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5967 if (dynamic_cast<AudioRegionView*> (*i)) {
5968 audio_rs.push_back (*i);
5972 if (audio_rs.empty()) {
5976 pitch_shift (audio_rs, 1.2);
5980 Editor::transpose_region ()
5982 RegionSelection rs = get_regions_from_selection_and_entered ();
5984 list<MidiRegionView*> midi_region_views;
5985 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5986 MidiRegionView* mrv = dynamic_cast<MidiRegionView*> (*i);
5988 midi_region_views.push_back (mrv);
5993 int const r = d.run ();
5994 if (r != RESPONSE_ACCEPT) {
5998 for (list<MidiRegionView*>::iterator i = midi_region_views.begin(); i != midi_region_views.end(); ++i) {
5999 (*i)->midi_region()->transpose (d.semitones ());
6004 Editor::set_tempo_from_region ()
6006 RegionSelection rs = get_regions_from_selection_and_entered ();
6008 if (!_session || rs.empty()) {
6012 RegionView* rv = rs.front();
6014 define_one_bar (rv->region()->position(), rv->region()->last_frame() + 1);
6018 Editor::use_range_as_bar ()
6020 framepos_t start, end;
6021 if (get_edit_op_range (start, end)) {
6022 define_one_bar (start, end);
6027 Editor::define_one_bar (framepos_t start, framepos_t end)
6029 framepos_t length = end - start;
6031 const Meter& m (_session->tempo_map().meter_at (start));
6033 /* length = 1 bar */
6035 /* now we want frames per beat.
6036 we have frames per bar, and beats per bar, so ...
6039 /* XXXX METER MATH */
6041 double frames_per_beat = length / m.divisions_per_bar();
6043 /* beats per minute = */
6045 double beats_per_minute = (_session->frame_rate() * 60.0) / frames_per_beat;
6047 /* now decide whether to:
6049 (a) set global tempo
6050 (b) add a new tempo marker
6054 const TempoSection& t (_session->tempo_map().tempo_section_at (start));
6056 bool do_global = false;
6058 if ((_session->tempo_map().n_tempos() == 1) && (_session->tempo_map().n_meters() == 1)) {
6060 /* only 1 tempo & 1 meter: ask if the user wants to set the tempo
6061 at the start, or create a new marker
6064 vector<string> options;
6065 options.push_back (_("Cancel"));
6066 options.push_back (_("Add new marker"));
6067 options.push_back (_("Set global tempo"));
6070 _("Define one bar"),
6071 _("Do you want to set the global tempo or add a new tempo marker?"),
6075 c.set_default_response (2);
6091 /* more than 1 tempo and/or meter section already, go ahead do the "usual":
6092 if the marker is at the region starter, change it, otherwise add
6097 begin_reversible_command (_("set tempo from region"));
6098 XMLNode& before (_session->tempo_map().get_state());
6101 _session->tempo_map().change_initial_tempo (beats_per_minute, t.note_type());
6102 } else if (t.frame() == start) {
6103 _session->tempo_map().change_existing_tempo_at (start, beats_per_minute, t.note_type());
6105 Timecode::BBT_Time bbt;
6106 _session->tempo_map().bbt_time (start, bbt);
6107 _session->tempo_map().add_tempo (Tempo (beats_per_minute, t.note_type()), bbt);
6110 XMLNode& after (_session->tempo_map().get_state());
6112 _session->add_command (new MementoCommand<TempoMap>(_session->tempo_map(), &before, &after));
6113 commit_reversible_command ();
6117 Editor::split_region_at_transients ()
6119 AnalysisFeatureList positions;
6121 RegionSelection rs = get_regions_from_selection_and_entered ();
6123 if (!_session || rs.empty()) {
6127 begin_reversible_command (_("split regions"));
6129 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ) {
6131 RegionSelection::iterator tmp;
6136 boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion> ((*i)->region());
6138 if (ar && (ar->get_transients (positions) == 0)) {
6139 split_region_at_points ((*i)->region(), positions, true);
6146 commit_reversible_command ();
6151 Editor::split_region_at_points (boost::shared_ptr<Region> r, AnalysisFeatureList& positions, bool can_ferret, bool select_new)
6153 bool use_rhythmic_rodent = false;
6155 boost::shared_ptr<Playlist> pl = r->playlist();
6157 list<boost::shared_ptr<Region> > new_regions;
6163 if (positions.empty()) {
6168 if (positions.size() > 20 && can_ferret) {
6169 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);
6170 MessageDialog msg (msgstr,
6173 Gtk::BUTTONS_OK_CANCEL);
6176 msg.add_button (_("Call for the Ferret!"), RESPONSE_APPLY);
6177 msg.set_secondary_text (_("Press OK to continue with this split operation\nor ask the Ferret dialog to tune the analysis"));
6179 msg.set_secondary_text (_("Press OK to continue with this split operation"));
6182 msg.set_title (_("Excessive split?"));
6185 int response = msg.run();
6191 case RESPONSE_APPLY:
6192 use_rhythmic_rodent = true;
6199 if (use_rhythmic_rodent) {
6200 show_rhythm_ferret ();
6204 AnalysisFeatureList::const_iterator x;
6206 pl->clear_changes ();
6207 pl->clear_owned_changes ();
6209 x = positions.begin();
6211 if (x == positions.end()) {
6216 pl->remove_region (r);
6220 while (x != positions.end()) {
6222 /* deal with positons that are out of scope of present region bounds */
6223 if (*x <= 0 || *x > r->length()) {
6228 /* file start = original start + how far we from the initial position ?
6231 framepos_t file_start = r->start() + pos;
6233 /* length = next position - current position
6236 framepos_t len = (*x) - pos;
6238 /* XXX we do we really want to allow even single-sample regions?
6239 shouldn't we have some kind of lower limit on region size?
6248 if (RegionFactory::region_name (new_name, r->name())) {
6252 /* do NOT announce new regions 1 by one, just wait till they are all done */
6256 plist.add (ARDOUR::Properties::start, file_start);
6257 plist.add (ARDOUR::Properties::length, len);
6258 plist.add (ARDOUR::Properties::name, new_name);
6259 plist.add (ARDOUR::Properties::layer, 0);
6261 boost::shared_ptr<Region> nr = RegionFactory::create (r->sources(), plist, false);
6262 /* because we set annouce to false, manually add the new region to the
6265 RegionFactory::map_add (nr);
6267 pl->add_region (nr, r->position() + pos);
6270 new_regions.push_front(nr);
6279 RegionFactory::region_name (new_name, r->name());
6281 /* Add the final region */
6284 plist.add (ARDOUR::Properties::start, r->start() + pos);
6285 plist.add (ARDOUR::Properties::length, r->last_frame() - (r->position() + pos) + 1);
6286 plist.add (ARDOUR::Properties::name, new_name);
6287 plist.add (ARDOUR::Properties::layer, 0);
6289 boost::shared_ptr<Region> nr = RegionFactory::create (r->sources(), plist, false);
6290 /* because we set annouce to false, manually add the new region to the
6293 RegionFactory::map_add (nr);
6294 pl->add_region (nr, r->position() + pos);
6297 new_regions.push_front(nr);
6302 /* We might have removed regions, which alters other regions' layering_index,
6303 so we need to do a recursive diff here.
6305 vector<Command*> cmds;
6307 _session->add_commands (cmds);
6309 _session->add_command (new StatefulDiffCommand (pl));
6313 for (list<boost::shared_ptr<Region> >::iterator i = new_regions.begin(); i != new_regions.end(); ++i){
6314 set_selected_regionview_from_region_list ((*i), Selection::Add);
6320 Editor::place_transient()
6326 RegionSelection rs = get_regions_from_selection_and_edit_point ();
6332 framepos_t where = get_preferred_edit_position();
6334 begin_reversible_command (_("place transient"));
6336 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6337 framepos_t position = (*r)->region()->position();
6338 (*r)->region()->add_transient(where - position);
6341 commit_reversible_command ();
6345 Editor::remove_transient(ArdourCanvas::Item* item)
6351 ArdourCanvas::Line* _line = reinterpret_cast<ArdourCanvas::Line*> (item);
6354 AudioRegionView* _arv = reinterpret_cast<AudioRegionView*> (item->get_data ("regionview"));
6355 _arv->remove_transient (*(float*) _line->get_data ("position"));
6359 Editor::snap_regions_to_grid ()
6361 list <boost::shared_ptr<Playlist > > used_playlists;
6363 RegionSelection rs = get_regions_from_selection_and_entered ();
6365 if (!_session || rs.empty()) {
6369 begin_reversible_command (_("snap regions to grid"));
6371 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6373 boost::shared_ptr<Playlist> pl = (*r)->region()->playlist();
6375 if (!pl->frozen()) {
6376 /* we haven't seen this playlist before */
6378 /* remember used playlists so we can thaw them later */
6379 used_playlists.push_back(pl);
6383 framepos_t start_frame = (*r)->region()->first_frame ();
6384 snap_to (start_frame);
6385 (*r)->region()->set_position (start_frame);
6388 while (used_playlists.size() > 0) {
6389 list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
6391 used_playlists.pop_front();
6394 commit_reversible_command ();
6398 Editor::close_region_gaps ()
6400 list <boost::shared_ptr<Playlist > > used_playlists;
6402 RegionSelection rs = get_regions_from_selection_and_entered ();
6404 if (!_session || rs.empty()) {
6408 Dialog dialog (_("Close Region Gaps"));
6411 table.set_spacings (12);
6412 table.set_border_width (12);
6413 Label* l = manage (left_aligned_label (_("Crossfade length")));
6414 table.attach (*l, 0, 1, 0, 1);
6416 SpinButton spin_crossfade (1, 0);
6417 spin_crossfade.set_range (0, 15);
6418 spin_crossfade.set_increments (1, 1);
6419 spin_crossfade.set_value (5);
6420 table.attach (spin_crossfade, 1, 2, 0, 1);
6422 table.attach (*manage (new Label (_("ms"))), 2, 3, 0, 1);
6424 l = manage (left_aligned_label (_("Pull-back length")));
6425 table.attach (*l, 0, 1, 1, 2);
6427 SpinButton spin_pullback (1, 0);
6428 spin_pullback.set_range (0, 100);
6429 spin_pullback.set_increments (1, 1);
6430 spin_pullback.set_value(30);
6431 table.attach (spin_pullback, 1, 2, 1, 2);
6433 table.attach (*manage (new Label (_("ms"))), 2, 3, 1, 2);
6435 dialog.get_vbox()->pack_start (table);
6436 dialog.add_button (Stock::CANCEL, RESPONSE_CANCEL);
6437 dialog.add_button (_("Ok"), RESPONSE_ACCEPT);
6440 if (dialog.run () == RESPONSE_CANCEL) {
6444 framepos_t crossfade_len = spin_crossfade.get_value();
6445 framepos_t pull_back_frames = spin_pullback.get_value();
6447 crossfade_len = lrintf (crossfade_len * _session->frame_rate()/1000);
6448 pull_back_frames = lrintf (pull_back_frames * _session->frame_rate()/1000);
6450 /* Iterate over the region list and make adjacent regions overlap by crossfade_len_ms */
6452 begin_reversible_command (_("close region gaps"));
6455 boost::shared_ptr<Region> last_region;
6457 rs.sort_by_position_and_track();
6459 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6461 boost::shared_ptr<Playlist> pl = (*r)->region()->playlist();
6463 if (!pl->frozen()) {
6464 /* we haven't seen this playlist before */
6466 /* remember used playlists so we can thaw them later */
6467 used_playlists.push_back(pl);
6471 framepos_t position = (*r)->region()->position();
6473 if (idx == 0 || position < last_region->position()){
6474 last_region = (*r)->region();
6479 (*r)->region()->trim_front( (position - pull_back_frames));
6480 last_region->trim_end( (position - pull_back_frames + crossfade_len));
6482 last_region = (*r)->region();
6487 while (used_playlists.size() > 0) {
6488 list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
6490 used_playlists.pop_front();
6493 commit_reversible_command ();
6497 Editor::tab_to_transient (bool forward)
6499 AnalysisFeatureList positions;
6501 RegionSelection rs = get_regions_from_selection_and_entered ();
6507 framepos_t pos = _session->audible_frame ();
6509 if (!selection->tracks.empty()) {
6511 /* don't waste time searching for transients in duplicate playlists.
6514 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
6516 for (TrackViewList::iterator t = ts.begin(); t != ts.end(); ++t) {
6518 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*t);
6521 boost::shared_ptr<Track> tr = rtv->track();
6523 boost::shared_ptr<Playlist> pl = tr->playlist ();
6525 framepos_t result = pl->find_next_transient (pos, forward ? 1 : -1);
6528 positions.push_back (result);
6541 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6542 (*r)->region()->get_transients (positions);
6546 TransientDetector::cleanup_transients (positions, _session->frame_rate(), 3.0);
6549 AnalysisFeatureList::iterator x;
6551 for (x = positions.begin(); x != positions.end(); ++x) {
6557 if (x != positions.end ()) {
6558 _session->request_locate (*x);
6562 AnalysisFeatureList::reverse_iterator x;
6564 for (x = positions.rbegin(); x != positions.rend(); ++x) {
6570 if (x != positions.rend ()) {
6571 _session->request_locate (*x);
6577 Editor::playhead_forward_to_grid ()
6583 framepos_t pos = playhead_cursor->current_frame ();
6584 if (pos < max_framepos - 1) {
6586 snap_to_internal (pos, RoundUpAlways, false);
6587 _session->request_locate (pos);
6593 Editor::playhead_backward_to_grid ()
6599 framepos_t pos = playhead_cursor->current_frame ();
6602 snap_to_internal (pos, RoundDownAlways, false);
6603 _session->request_locate (pos);
6608 Editor::set_track_height (Height h)
6610 TrackSelection& ts (selection->tracks);
6612 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
6613 (*x)->set_height_enum (h);
6618 Editor::toggle_tracks_active ()
6620 TrackSelection& ts (selection->tracks);
6622 bool target = false;
6628 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
6629 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*x);
6633 target = !rtv->_route->active();
6636 rtv->_route->set_active (target, this);
6642 Editor::remove_tracks ()
6644 TrackSelection& ts (selection->tracks);
6650 vector<string> choices;
6654 const char* trackstr;
6656 vector<boost::shared_ptr<Route> > routes;
6657 bool special_bus = false;
6659 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
6660 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*x);
6664 if (rtv->is_track()) {
6669 routes.push_back (rtv->_route);
6671 if (rtv->route()->is_master() || rtv->route()->is_monitor()) {
6676 if (special_bus && !Config->get_allow_special_bus_removal()) {
6677 MessageDialog msg (_("That would be bad news ...."),
6681 msg.set_secondary_text (string_compose (_(
6682 "Removing the master or monitor bus is such a bad idea\n\
6683 that %1 is not going to allow it.\n\
6685 If you really want to do this sort of thing\n\
6686 edit your ardour.rc file to set the\n\
6687 \"allow-special-bus-removal\" option to be \"yes\""), PROGRAM_NAME));
6694 if (ntracks + nbusses == 0) {
6698 // XXX should be using gettext plural forms, maybe?
6700 trackstr = _("tracks");
6702 trackstr = _("track");
6706 busstr = _("busses");
6713 prompt = string_compose (_("Do you really want to remove %1 %2 and %3 %4?\n"
6714 "(You may also lose the playlists associated with the %2)\n\n"
6715 "This action cannot be undone, and the session file will be overwritten!"),
6716 ntracks, trackstr, nbusses, busstr);
6718 prompt = string_compose (_("Do you really want to remove %1 %2?\n"
6719 "(You may also lose the playlists associated with the %2)\n\n"
6720 "This action cannot be undone, and the session file will be overwritten!"),
6723 } else if (nbusses) {
6724 prompt = string_compose (_("Do you really want to remove %1 %2?\n\n"
6725 "This action cannot be undone, and the session file will be overwritten"),
6729 choices.push_back (_("No, do nothing."));
6730 if (ntracks + nbusses > 1) {
6731 choices.push_back (_("Yes, remove them."));
6733 choices.push_back (_("Yes, remove it."));
6738 title = string_compose (_("Remove %1"), trackstr);
6740 title = string_compose (_("Remove %1"), busstr);
6743 Choice prompter (title, prompt, choices);
6745 if (prompter.run () != 1) {
6750 Session::StateProtector sp (_session);
6751 DisplaySuspender ds;
6752 for (vector<boost::shared_ptr<Route> >::iterator x = routes.begin(); x != routes.end(); ++x) {
6753 _session->remove_route (*x);
6759 Editor::do_insert_time ()
6761 if (selection->tracks.empty()) {
6765 InsertTimeDialog d (*this);
6766 int response = d.run ();
6768 if (response != RESPONSE_OK) {
6772 if (d.distance() == 0) {
6776 InsertTimeOption opt = d.intersected_region_action ();
6779 get_preferred_edit_position(),
6785 d.move_glued_markers(),
6786 d.move_locked_markers(),
6792 Editor::insert_time (
6793 framepos_t pos, framecnt_t frames, InsertTimeOption opt,
6794 bool all_playlists, bool ignore_music_glue, bool markers_too, bool glued_markers_too, bool locked_markers_too, bool tempo_too
6797 bool commit = false;
6799 if (Config->get_edit_mode() == Lock) {
6803 begin_reversible_command (_("insert time"));
6805 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
6807 for (TrackViewList::iterator x = ts.begin(); x != ts.end(); ++x) {
6811 /* don't operate on any playlist more than once, which could
6812 * happen if "all playlists" is enabled, but there is more
6813 * than 1 track using playlists "from" a given track.
6816 set<boost::shared_ptr<Playlist> > pl;
6818 if (all_playlists) {
6819 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*x);
6821 vector<boost::shared_ptr<Playlist> > all = _session->playlists->playlists_for_track (rtav->track ());
6822 for (vector<boost::shared_ptr<Playlist> >::iterator p = all.begin(); p != all.end(); ++p) {
6827 if ((*x)->playlist ()) {
6828 pl.insert ((*x)->playlist ());
6832 for (set<boost::shared_ptr<Playlist> >::iterator i = pl.begin(); i != pl.end(); ++i) {
6834 (*i)->clear_changes ();
6835 (*i)->clear_owned_changes ();
6837 if (opt == SplitIntersected) {
6841 (*i)->shift (pos, frames, (opt == MoveIntersected), ignore_music_glue);
6843 vector<Command*> cmds;
6845 _session->add_commands (cmds);
6847 _session->add_command (new StatefulDiffCommand (*i));
6852 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*x);
6854 rtav->route ()->shift (pos, frames);
6862 XMLNode& before (_session->locations()->get_state());
6863 Locations::LocationList copy (_session->locations()->list());
6865 for (Locations::LocationList::iterator i = copy.begin(); i != copy.end(); ++i) {
6867 Locations::LocationList::const_iterator tmp;
6869 bool const was_locked = (*i)->locked ();
6870 if (locked_markers_too) {
6874 if ((*i)->position_lock_style() == AudioTime || glued_markers_too) {
6876 if ((*i)->start() >= pos) {
6877 (*i)->set_start ((*i)->start() + frames);
6878 if (!(*i)->is_mark()) {
6879 (*i)->set_end ((*i)->end() + frames);
6892 XMLNode& after (_session->locations()->get_state());
6893 _session->add_command (new MementoCommand<Locations>(*_session->locations(), &before, &after));
6898 _session->tempo_map().insert_time (pos, frames);
6902 commit_reversible_command ();
6907 Editor::fit_selected_tracks ()
6909 if (!selection->tracks.empty()) {
6910 fit_tracks (selection->tracks);
6914 /* no selected tracks - use tracks with selected regions */
6916 if (!selection->regions.empty()) {
6917 for (RegionSelection::iterator r = selection->regions.begin(); r != selection->regions.end(); ++r) {
6918 tvl.push_back (&(*r)->get_time_axis_view ());
6924 } else if (internal_editing()) {
6925 /* no selected tracks, or regions, but in internal edit mode, so follow the mouse and use
6928 if (entered_track) {
6929 tvl.push_back (entered_track);
6938 Editor::fit_tracks (TrackViewList & tracks)
6940 if (tracks.empty()) {
6944 uint32_t child_heights = 0;
6945 int visible_tracks = 0;
6947 for (TrackSelection::iterator t = tracks.begin(); t != tracks.end(); ++t) {
6949 if (!(*t)->marked_for_display()) {
6953 child_heights += (*t)->effective_height() - (*t)->current_height();
6957 /* compute the per-track height from:
6959 total canvas visible height -
6960 height that will be taken by visible children of selected
6961 tracks - height of the ruler/hscroll area
6963 uint32_t h = (uint32_t) floor ((trackviews_height() - child_heights) / visible_tracks);
6964 double first_y_pos = DBL_MAX;
6966 if (h < TimeAxisView::preset_height (HeightSmall)) {
6967 MessageDialog msg (*this, _("There are too many tracks to fit in the current window"));
6968 /* too small to be displayed */
6972 undo_visual_stack.push_back (current_visual_state (true));
6973 no_save_visual = true;
6975 /* build a list of all tracks, including children */
6978 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
6980 TimeAxisView::Children c = (*i)->get_child_list ();
6981 for (TimeAxisView::Children::iterator j = c.begin(); j != c.end(); ++j) {
6982 all.push_back (j->get());
6986 bool prev_was_selected = false;
6987 bool is_selected = tracks.contains (all.front());
6988 bool next_is_selected;
6990 for (TrackViewList::iterator t = all.begin(); t != all.end(); ++t) {
6992 TrackViewList::iterator next;
6997 if (next != all.end()) {
6998 next_is_selected = tracks.contains (*next);
7000 next_is_selected = false;
7003 if ((*t)->marked_for_display ()) {
7005 (*t)->set_height (h);
7006 first_y_pos = std::min ((*t)->y_position (), first_y_pos);
7008 if (prev_was_selected && next_is_selected) {
7009 hide_track_in_display (*t);
7014 prev_was_selected = is_selected;
7015 is_selected = next_is_selected;
7019 set the controls_layout height now, because waiting for its size
7020 request signal handler will cause the vertical adjustment setting to fail
7023 controls_layout.property_height () = _full_canvas_height;
7024 vertical_adjustment.set_value (first_y_pos);
7026 redo_visual_stack.push_back (current_visual_state (true));
7028 visible_tracks_selector.set_text (_("Sel"));
7032 Editor::save_visual_state (uint32_t n)
7034 while (visual_states.size() <= n) {
7035 visual_states.push_back (0);
7038 if (visual_states[n] != 0) {
7039 delete visual_states[n];
7042 visual_states[n] = current_visual_state (true);
7047 Editor::goto_visual_state (uint32_t n)
7049 if (visual_states.size() <= n) {
7053 if (visual_states[n] == 0) {
7057 use_visual_state (*visual_states[n]);
7061 Editor::start_visual_state_op (uint32_t n)
7063 save_visual_state (n);
7065 PopUp* pup = new PopUp (WIN_POS_MOUSE, 1000, true);
7067 snprintf (buf, sizeof (buf), _("Saved view %u"), n+1);
7068 pup->set_text (buf);
7073 Editor::cancel_visual_state_op (uint32_t n)
7075 goto_visual_state (n);
7079 Editor::toggle_region_mute ()
7081 if (_ignore_region_action) {
7085 RegionSelection rs = get_regions_from_selection_and_entered ();
7091 if (rs.size() > 1) {
7092 begin_reversible_command (_("mute regions"));
7094 begin_reversible_command (_("mute region"));
7097 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
7099 (*i)->region()->playlist()->clear_changes ();
7100 (*i)->region()->set_muted (!(*i)->region()->muted ());
7101 _session->add_command (new StatefulDiffCommand ((*i)->region()));
7105 commit_reversible_command ();
7109 Editor::combine_regions ()
7111 /* foreach track with selected regions, take all selected regions
7112 and join them into a new region containing the subregions (as a
7116 typedef set<RouteTimeAxisView*> RTVS;
7119 if (selection->regions.empty()) {
7123 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
7124 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(&(*i)->get_time_axis_view());
7127 tracks.insert (rtv);
7131 begin_reversible_command (_("combine regions"));
7133 vector<RegionView*> new_selection;
7135 for (RTVS::iterator i = tracks.begin(); i != tracks.end(); ++i) {
7138 if ((rv = (*i)->combine_regions ()) != 0) {
7139 new_selection.push_back (rv);
7143 selection->clear_regions ();
7144 for (vector<RegionView*>::iterator i = new_selection.begin(); i != new_selection.end(); ++i) {
7145 selection->add (*i);
7148 commit_reversible_command ();
7152 Editor::uncombine_regions ()
7154 typedef set<RouteTimeAxisView*> RTVS;
7157 if (selection->regions.empty()) {
7161 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
7162 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(&(*i)->get_time_axis_view());
7165 tracks.insert (rtv);
7169 begin_reversible_command (_("uncombine regions"));
7171 for (RTVS::iterator i = tracks.begin(); i != tracks.end(); ++i) {
7172 (*i)->uncombine_regions ();
7175 commit_reversible_command ();
7179 Editor::toggle_midi_input_active (bool flip_others)
7182 boost::shared_ptr<RouteList> rl (new RouteList);
7184 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
7185 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
7191 boost::shared_ptr<MidiTrack> mt = rtav->midi_track();
7194 rl->push_back (rtav->route());
7195 onoff = !mt->input_active();
7199 _session->set_exclusive_input_active (rl, onoff, flip_others);
7206 lock_dialog = new Gtk::Dialog (string_compose (_("%1: Locked"), PROGRAM_NAME), true);
7208 Gtk::Image* padlock = manage (new Gtk::Image (ARDOUR_UI_UTILS::get_icon ("padlock_closed")));
7209 lock_dialog->get_vbox()->pack_start (*padlock);
7211 ArdourButton* b = manage (new ArdourButton);
7212 b->set_name ("lock button");
7213 b->set_text (_("Click to unlock"));
7214 b->signal_clicked.connect (sigc::mem_fun (*this, &Editor::unlock));
7215 lock_dialog->get_vbox()->pack_start (*b);
7217 lock_dialog->get_vbox()->show_all ();
7218 lock_dialog->set_size_request (200, 200);
7222 /* The global menu bar continues to be accessible to applications
7223 with modal dialogs, which means that we need to desensitize
7224 all items in the menu bar. Since those items are really just
7225 proxies for actions, that means disabling all actions.
7227 ActionManager::disable_all_actions ();
7229 lock_dialog->present ();
7235 lock_dialog->hide ();
7238 ActionManager::pop_action_state ();
7241 if (ARDOUR_UI::config()->get_lock_gui_after_seconds()) {
7242 start_lock_event_timing ();
7247 Editor::bring_in_callback (Gtk::Label* label, uint32_t n, uint32_t total, string name)
7249 Gtkmm2ext::UI::instance()->call_slot (invalidator (*this), boost::bind (&Editor::update_bring_in_message, this, label, n, total, name));
7253 Editor::update_bring_in_message (Gtk::Label* label, uint32_t n, uint32_t total, string name)
7255 label->set_text (string_compose ("Copying %1, %2 of %3", name, n, total));
7256 Gtkmm2ext::UI::instance()->flush_pending ();
7260 Editor::bring_all_sources_into_session ()
7267 ArdourDialog w (_("Moving embedded files into session folder"));
7268 w.get_vbox()->pack_start (msg);
7271 /* flush all pending GUI events because we're about to start copying
7275 Gtkmm2ext::UI::instance()->flush_pending ();
7279 _session->bring_all_sources_into_session (boost::bind (&Editor::bring_in_callback, this, &msg, _1, _2, _3));