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)
4916 RegionSelection rs = get_regions_from_selection_and_entered ();
4922 begin_reversible_command (op.name ());
4924 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
4925 RegionSelection::iterator tmp = r;
4928 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*r);
4931 cmd = apply_midi_note_edit_op_to_region (op, *mrv);
4934 _session->add_command (cmd);
4941 commit_reversible_command ();
4945 Editor::fork_region ()
4947 RegionSelection rs = get_regions_from_selection_and_entered ();
4953 begin_reversible_command (_("Fork Region(s)"));
4955 CursorContext::Handle cursor_ctx = CursorContext::create(*this, _cursors->wait);
4958 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
4959 RegionSelection::iterator tmp = r;
4962 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*>(*r);
4966 boost::shared_ptr<Playlist> playlist = mrv->region()->playlist();
4967 boost::shared_ptr<MidiSource> new_source = _session->create_midi_source_by_stealing_name (mrv->midi_view()->track());
4968 boost::shared_ptr<MidiRegion> newregion = mrv->midi_region()->clone (new_source);
4970 playlist->clear_changes ();
4971 playlist->replace_region (mrv->region(), newregion, mrv->region()->position());
4972 _session->add_command(new StatefulDiffCommand (playlist));
4974 error << string_compose (_("Could not unlink %1"), mrv->region()->name()) << endmsg;
4981 commit_reversible_command ();
4985 Editor::quantize_region ()
4987 int selected_midi_region_cnt = 0;
4993 RegionSelection rs = get_regions_from_selection_and_entered ();
4999 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
5000 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*r);
5002 selected_midi_region_cnt++;
5006 if (selected_midi_region_cnt == 0) {
5010 QuantizeDialog* qd = new QuantizeDialog (*this);
5013 const int r = qd->run ();
5016 if (r == Gtk::RESPONSE_OK) {
5017 Quantize quant (qd->snap_start(), qd->snap_end(),
5018 qd->start_grid_size(), qd->end_grid_size(),
5019 qd->strength(), qd->swing(), qd->threshold());
5021 apply_midi_note_edit_op (quant);
5026 Editor::legatize_region (bool shrink_only)
5028 int selected_midi_region_cnt = 0;
5034 RegionSelection rs = get_regions_from_selection_and_entered ();
5040 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
5041 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*r);
5043 selected_midi_region_cnt++;
5047 if (selected_midi_region_cnt == 0) {
5051 Legatize legatize(shrink_only);
5052 apply_midi_note_edit_op (legatize);
5056 Editor::insert_patch_change (bool from_context)
5058 RegionSelection rs = get_regions_from_selection_and_entered ();
5064 const framepos_t p = get_preferred_edit_position (false, from_context);
5066 /* XXX: bit of a hack; use the MIDNAM from the first selected region;
5067 there may be more than one, but the PatchChangeDialog can only offer
5068 one set of patch menus.
5070 MidiRegionView* first = dynamic_cast<MidiRegionView*> (rs.front ());
5072 Evoral::PatchChange<Evoral::MusicalTime> empty (Evoral::MusicalTime(), 0, 0, 0);
5073 PatchChangeDialog d (0, _session, empty, first->instrument_info(), Gtk::Stock::ADD);
5075 if (d.run() == RESPONSE_CANCEL) {
5079 for (RegionSelection::iterator i = rs.begin (); i != rs.end(); ++i) {
5080 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*i);
5082 if (p >= mrv->region()->first_frame() && p <= mrv->region()->last_frame()) {
5083 mrv->add_patch_change (p - mrv->region()->position(), d.patch ());
5090 Editor::apply_filter (Filter& filter, string command, ProgressReporter* progress)
5092 RegionSelection rs = get_regions_from_selection_and_entered ();
5098 begin_reversible_command (command);
5100 CursorContext::Handle cursor_ctx = CursorContext::create(*this, _cursors->wait);
5104 int const N = rs.size ();
5106 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
5107 RegionSelection::iterator tmp = r;
5110 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
5112 boost::shared_ptr<Playlist> playlist = arv->region()->playlist();
5115 progress->descend (1.0 / N);
5118 if (arv->audio_region()->apply (filter, progress) == 0) {
5120 playlist->clear_changes ();
5121 playlist->clear_owned_changes ();
5123 if (filter.results.empty ()) {
5125 /* no regions returned; remove the old one */
5126 playlist->remove_region (arv->region ());
5130 std::vector<boost::shared_ptr<Region> >::iterator res = filter.results.begin ();
5132 /* first region replaces the old one */
5133 playlist->replace_region (arv->region(), *res, (*res)->position());
5137 while (res != filter.results.end()) {
5138 playlist->add_region (*res, (*res)->position());
5144 /* We might have removed regions, which alters other regions' layering_index,
5145 so we need to do a recursive diff here.
5147 vector<Command*> cmds;
5148 playlist->rdiff (cmds);
5149 _session->add_commands (cmds);
5151 _session->add_command(new StatefulDiffCommand (playlist));
5157 progress->ascend ();
5165 commit_reversible_command ();
5169 Editor::external_edit_region ()
5175 Editor::reset_region_gain_envelopes ()
5177 RegionSelection rs = get_regions_from_selection_and_entered ();
5179 if (!_session || rs.empty()) {
5183 begin_reversible_command (_("reset region gain"));
5185 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5186 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
5188 boost::shared_ptr<AutomationList> alist (arv->audio_region()->envelope());
5189 XMLNode& before (alist->get_state());
5191 arv->audio_region()->set_default_envelope ();
5192 _session->add_command (new MementoCommand<AutomationList>(*arv->audio_region()->envelope().get(), &before, &alist->get_state()));
5196 commit_reversible_command ();
5200 Editor::set_region_gain_visibility (RegionView* rv)
5202 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (rv);
5204 arv->update_envelope_visibility();
5209 Editor::set_gain_envelope_visibility ()
5215 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5216 AudioTimeAxisView* v = dynamic_cast<AudioTimeAxisView*>(*i);
5218 v->audio_view()->foreach_regionview (sigc::mem_fun (this, &Editor::set_region_gain_visibility));
5224 Editor::toggle_gain_envelope_active ()
5226 if (_ignore_region_action) {
5230 RegionSelection rs = get_regions_from_selection_and_entered ();
5232 if (!_session || rs.empty()) {
5236 begin_reversible_command (_("region gain envelope active"));
5238 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5239 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
5241 arv->region()->clear_changes ();
5242 arv->audio_region()->set_envelope_active (!arv->audio_region()->envelope_active());
5243 _session->add_command (new StatefulDiffCommand (arv->region()));
5247 commit_reversible_command ();
5251 Editor::toggle_region_lock ()
5253 if (_ignore_region_action) {
5257 RegionSelection rs = get_regions_from_selection_and_entered ();
5259 if (!_session || rs.empty()) {
5263 begin_reversible_command (_("toggle region lock"));
5265 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5266 (*i)->region()->clear_changes ();
5267 (*i)->region()->set_locked (!(*i)->region()->locked());
5268 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5271 commit_reversible_command ();
5275 Editor::toggle_region_video_lock ()
5277 if (_ignore_region_action) {
5281 RegionSelection rs = get_regions_from_selection_and_entered ();
5283 if (!_session || rs.empty()) {
5287 begin_reversible_command (_("Toggle Video Lock"));
5289 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5290 (*i)->region()->clear_changes ();
5291 (*i)->region()->set_video_locked (!(*i)->region()->video_locked());
5292 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5295 commit_reversible_command ();
5299 Editor::toggle_region_lock_style ()
5301 if (_ignore_region_action) {
5305 RegionSelection rs = get_regions_from_selection_and_entered ();
5307 if (!_session || rs.empty()) {
5311 begin_reversible_command (_("region lock style"));
5313 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5314 (*i)->region()->clear_changes ();
5315 PositionLockStyle const ns = (*i)->region()->position_lock_style() == AudioTime ? MusicTime : AudioTime;
5316 (*i)->region()->set_position_lock_style (ns);
5317 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5320 commit_reversible_command ();
5324 Editor::toggle_opaque_region ()
5326 if (_ignore_region_action) {
5330 RegionSelection rs = get_regions_from_selection_and_entered ();
5332 if (!_session || rs.empty()) {
5336 begin_reversible_command (_("change region opacity"));
5338 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5339 (*i)->region()->clear_changes ();
5340 (*i)->region()->set_opaque (!(*i)->region()->opaque());
5341 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5344 commit_reversible_command ();
5348 Editor::toggle_record_enable ()
5350 bool new_state = false;
5352 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5353 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5356 if (!rtav->is_track())
5360 new_state = !rtav->track()->record_enabled();
5364 rtav->track()->set_record_enabled (new_state, this);
5369 Editor::toggle_solo ()
5371 bool new_state = false;
5373 boost::shared_ptr<RouteList> rl (new RouteList);
5375 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5376 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5383 new_state = !rtav->route()->soloed ();
5387 rl->push_back (rtav->route());
5390 _session->set_solo (rl, new_state, Session::rt_cleanup, true);
5394 Editor::toggle_mute ()
5396 bool new_state = false;
5398 boost::shared_ptr<RouteList> rl (new RouteList);
5400 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5401 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5408 new_state = !rtav->route()->muted();
5412 rl->push_back (rtav->route());
5415 _session->set_mute (rl, new_state, Session::rt_cleanup, true);
5419 Editor::toggle_solo_isolate ()
5425 Editor::fade_range ()
5427 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
5429 begin_reversible_command (_("fade range"));
5431 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
5432 (*i)->fade_range (selection->time);
5435 commit_reversible_command ();
5440 Editor::set_fade_length (bool in)
5442 RegionSelection rs = get_regions_from_selection_and_entered ();
5448 /* we need a region to measure the offset from the start */
5450 RegionView* rv = rs.front ();
5452 framepos_t pos = get_preferred_edit_position();
5456 if (pos > rv->region()->last_frame() || pos < rv->region()->first_frame()) {
5457 /* edit point is outside the relevant region */
5462 if (pos <= rv->region()->position()) {
5466 len = pos - rv->region()->position();
5467 cmd = _("set fade in length");
5469 if (pos >= rv->region()->last_frame()) {
5473 len = rv->region()->last_frame() - pos;
5474 cmd = _("set fade out length");
5477 begin_reversible_command (cmd);
5479 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5480 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5486 boost::shared_ptr<AutomationList> alist;
5488 alist = tmp->audio_region()->fade_in();
5490 alist = tmp->audio_region()->fade_out();
5493 XMLNode &before = alist->get_state();
5496 tmp->audio_region()->set_fade_in_length (len);
5497 tmp->audio_region()->set_fade_in_active (true);
5499 tmp->audio_region()->set_fade_out_length (len);
5500 tmp->audio_region()->set_fade_out_active (true);
5503 XMLNode &after = alist->get_state();
5504 _session->add_command(new MementoCommand<AutomationList>(*alist, &before, &after));
5507 commit_reversible_command ();
5511 Editor::set_fade_in_shape (FadeShape shape)
5513 RegionSelection rs = get_regions_from_selection_and_entered ();
5519 begin_reversible_command (_("set fade in shape"));
5521 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5522 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5528 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_in();
5529 XMLNode &before = alist->get_state();
5531 tmp->audio_region()->set_fade_in_shape (shape);
5533 XMLNode &after = alist->get_state();
5534 _session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
5537 commit_reversible_command ();
5542 Editor::set_fade_out_shape (FadeShape shape)
5544 RegionSelection rs = get_regions_from_selection_and_entered ();
5550 begin_reversible_command (_("set fade out shape"));
5552 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5553 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5559 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_out();
5560 XMLNode &before = alist->get_state();
5562 tmp->audio_region()->set_fade_out_shape (shape);
5564 XMLNode &after = alist->get_state();
5565 _session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
5568 commit_reversible_command ();
5572 Editor::set_fade_in_active (bool yn)
5574 RegionSelection rs = get_regions_from_selection_and_entered ();
5580 begin_reversible_command (_("set fade in active"));
5582 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5583 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5590 boost::shared_ptr<AudioRegion> ar (tmp->audio_region());
5592 ar->clear_changes ();
5593 ar->set_fade_in_active (yn);
5594 _session->add_command (new StatefulDiffCommand (ar));
5597 commit_reversible_command ();
5601 Editor::set_fade_out_active (bool yn)
5603 RegionSelection rs = get_regions_from_selection_and_entered ();
5609 begin_reversible_command (_("set fade out active"));
5611 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5612 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5618 boost::shared_ptr<AudioRegion> ar (tmp->audio_region());
5620 ar->clear_changes ();
5621 ar->set_fade_out_active (yn);
5622 _session->add_command(new StatefulDiffCommand (ar));
5625 commit_reversible_command ();
5629 Editor::toggle_region_fades (int dir)
5631 if (_ignore_region_action) {
5635 boost::shared_ptr<AudioRegion> ar;
5638 RegionSelection rs = get_regions_from_selection_and_entered ();
5644 RegionSelection::iterator i;
5645 for (i = rs.begin(); i != rs.end(); ++i) {
5646 if ((ar = boost::dynamic_pointer_cast<AudioRegion>((*i)->region())) != 0) {
5648 yn = ar->fade_out_active ();
5650 yn = ar->fade_in_active ();
5656 if (i == rs.end()) {
5660 /* XXX should this undo-able? */
5662 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5663 if ((ar = boost::dynamic_pointer_cast<AudioRegion>((*i)->region())) == 0) {
5666 if (dir == 1 || dir == 0) {
5667 ar->set_fade_in_active (!yn);
5670 if (dir == -1 || dir == 0) {
5671 ar->set_fade_out_active (!yn);
5677 /** Update region fade visibility after its configuration has been changed */
5679 Editor::update_region_fade_visibility ()
5681 bool _fade_visibility = _session->config.get_show_region_fades ();
5683 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5684 AudioTimeAxisView* v = dynamic_cast<AudioTimeAxisView*>(*i);
5686 if (_fade_visibility) {
5687 v->audio_view()->show_all_fades ();
5689 v->audio_view()->hide_all_fades ();
5696 Editor::set_edit_point ()
5701 if (!mouse_frame (where, ignored)) {
5707 if (selection->markers.empty()) {
5709 mouse_add_new_marker (where);
5714 Location* loc = find_location_from_marker (selection->markers.front(), ignored);
5717 loc->move_to (where);
5723 Editor::set_playhead_cursor ()
5725 if (entered_marker) {
5726 _session->request_locate (entered_marker->position(), _session->transport_rolling());
5731 if (!mouse_frame (where, ignored)) {
5738 _session->request_locate (where, _session->transport_rolling());
5742 if (ARDOUR_UI::config()->get_follow_edits()) {
5743 cancel_time_selection();
5748 Editor::split_region ()
5750 if ( !selection->time.empty()) {
5751 separate_regions_between (selection->time);
5755 RegionSelection rs = get_regions_from_selection_and_edit_point ();
5757 framepos_t where = get_preferred_edit_position ();
5763 split_regions_at (where, rs);
5766 struct EditorOrderRouteSorter {
5767 bool operator() (boost::shared_ptr<Route> a, boost::shared_ptr<Route> b) {
5768 return a->order_key () < b->order_key ();
5773 Editor::select_next_route()
5775 if (selection->tracks.empty()) {
5776 selection->set (track_views.front());
5780 TimeAxisView* current = selection->tracks.front();
5784 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5785 if (*i == current) {
5787 if (i != track_views.end()) {
5790 current = (*(track_views.begin()));
5791 //selection->set (*(track_views.begin()));
5796 rui = dynamic_cast<RouteUI *>(current);
5797 } while ( current->hidden() || (rui != NULL && !rui->route()->active()));
5799 selection->set(current);
5801 ensure_time_axis_view_is_visible (*current, false);
5805 Editor::select_prev_route()
5807 if (selection->tracks.empty()) {
5808 selection->set (track_views.front());
5812 TimeAxisView* current = selection->tracks.front();
5816 for (TrackViewList::reverse_iterator i = track_views.rbegin(); i != track_views.rend(); ++i) {
5817 if (*i == current) {
5819 if (i != track_views.rend()) {
5822 current = *(track_views.rbegin());
5827 rui = dynamic_cast<RouteUI *>(current);
5828 } while ( current->hidden() || (rui != NULL && !rui->route()->active()));
5830 selection->set (current);
5832 ensure_time_axis_view_is_visible (*current, false);
5836 Editor::set_loop_from_selection (bool play)
5838 if (_session == 0 || selection->time.empty()) {
5842 framepos_t start = selection->time[clicked_selection].start;
5843 framepos_t end = selection->time[clicked_selection].end;
5845 set_loop_range (start, end, _("set loop range from selection"));
5848 _session->request_locate (start, true);
5849 _session->request_play_loop (true);
5854 Editor::set_loop_from_edit_range (bool play)
5856 if (_session == 0) {
5863 if (!get_edit_op_range (start, end)) {
5867 set_loop_range (start, end, _("set loop range from edit range"));
5870 _session->request_locate (start, true);
5871 _session->request_play_loop (true);
5876 Editor::set_loop_from_region (bool play)
5878 framepos_t start = max_framepos;
5881 RegionSelection rs = get_regions_from_selection_and_entered ();
5887 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5888 if ((*i)->region()->position() < start) {
5889 start = (*i)->region()->position();
5891 if ((*i)->region()->last_frame() + 1 > end) {
5892 end = (*i)->region()->last_frame() + 1;
5896 set_loop_range (start, end, _("set loop range from region"));
5899 _session->request_locate (start, true);
5900 _session->request_play_loop (true);
5905 Editor::set_punch_from_selection ()
5907 if (_session == 0 || selection->time.empty()) {
5911 framepos_t start = selection->time[clicked_selection].start;
5912 framepos_t end = selection->time[clicked_selection].end;
5914 set_punch_range (start, end, _("set punch range from selection"));
5918 Editor::set_session_extents_from_selection ()
5920 if (_session == 0 || selection->time.empty()) {
5924 begin_reversible_command (_("set session start/stop from selection"));
5926 framepos_t start = selection->time[clicked_selection].start;
5927 framepos_t end = selection->time[clicked_selection].end;
5930 if ((loc = _session->locations()->session_range_location()) == 0) {
5931 _session->set_session_extents ( start, end ); // this will create a new session range; no need for UNDO
5933 XMLNode &before = loc->get_state();
5935 _session->set_session_extents ( start, end );
5937 XMLNode &after = loc->get_state();
5939 _session->add_command (new MementoCommand<Location>(*loc, &before, &after));
5941 commit_reversible_command ();
5946 Editor::set_punch_from_edit_range ()
5948 if (_session == 0) {
5955 if (!get_edit_op_range (start, end)) {
5959 set_punch_range (start, end, _("set punch range from edit range"));
5963 Editor::set_punch_from_region ()
5965 framepos_t start = max_framepos;
5968 RegionSelection rs = get_regions_from_selection_and_entered ();
5974 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5975 if ((*i)->region()->position() < start) {
5976 start = (*i)->region()->position();
5978 if ((*i)->region()->last_frame() + 1 > end) {
5979 end = (*i)->region()->last_frame() + 1;
5983 set_punch_range (start, end, _("set punch range from region"));
5987 Editor::pitch_shift_region ()
5989 RegionSelection rs = get_regions_from_selection_and_entered ();
5991 RegionSelection audio_rs;
5992 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5993 if (dynamic_cast<AudioRegionView*> (*i)) {
5994 audio_rs.push_back (*i);
5998 if (audio_rs.empty()) {
6002 pitch_shift (audio_rs, 1.2);
6006 Editor::transpose_region ()
6008 RegionSelection rs = get_regions_from_selection_and_entered ();
6010 list<MidiRegionView*> midi_region_views;
6011 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
6012 MidiRegionView* mrv = dynamic_cast<MidiRegionView*> (*i);
6014 midi_region_views.push_back (mrv);
6019 int const r = d.run ();
6020 if (r != RESPONSE_ACCEPT) {
6024 for (list<MidiRegionView*>::iterator i = midi_region_views.begin(); i != midi_region_views.end(); ++i) {
6025 (*i)->midi_region()->transpose (d.semitones ());
6030 Editor::set_tempo_from_region ()
6032 RegionSelection rs = get_regions_from_selection_and_entered ();
6034 if (!_session || rs.empty()) {
6038 RegionView* rv = rs.front();
6040 define_one_bar (rv->region()->position(), rv->region()->last_frame() + 1);
6044 Editor::use_range_as_bar ()
6046 framepos_t start, end;
6047 if (get_edit_op_range (start, end)) {
6048 define_one_bar (start, end);
6053 Editor::define_one_bar (framepos_t start, framepos_t end)
6055 framepos_t length = end - start;
6057 const Meter& m (_session->tempo_map().meter_at (start));
6059 /* length = 1 bar */
6061 /* now we want frames per beat.
6062 we have frames per bar, and beats per bar, so ...
6065 /* XXXX METER MATH */
6067 double frames_per_beat = length / m.divisions_per_bar();
6069 /* beats per minute = */
6071 double beats_per_minute = (_session->frame_rate() * 60.0) / frames_per_beat;
6073 /* now decide whether to:
6075 (a) set global tempo
6076 (b) add a new tempo marker
6080 const TempoSection& t (_session->tempo_map().tempo_section_at (start));
6082 bool do_global = false;
6084 if ((_session->tempo_map().n_tempos() == 1) && (_session->tempo_map().n_meters() == 1)) {
6086 /* only 1 tempo & 1 meter: ask if the user wants to set the tempo
6087 at the start, or create a new marker
6090 vector<string> options;
6091 options.push_back (_("Cancel"));
6092 options.push_back (_("Add new marker"));
6093 options.push_back (_("Set global tempo"));
6096 _("Define one bar"),
6097 _("Do you want to set the global tempo or add a new tempo marker?"),
6101 c.set_default_response (2);
6117 /* more than 1 tempo and/or meter section already, go ahead do the "usual":
6118 if the marker is at the region starter, change it, otherwise add
6123 begin_reversible_command (_("set tempo from region"));
6124 XMLNode& before (_session->tempo_map().get_state());
6127 _session->tempo_map().change_initial_tempo (beats_per_minute, t.note_type());
6128 } else if (t.frame() == start) {
6129 _session->tempo_map().change_existing_tempo_at (start, beats_per_minute, t.note_type());
6131 Timecode::BBT_Time bbt;
6132 _session->tempo_map().bbt_time (start, bbt);
6133 _session->tempo_map().add_tempo (Tempo (beats_per_minute, t.note_type()), bbt);
6136 XMLNode& after (_session->tempo_map().get_state());
6138 _session->add_command (new MementoCommand<TempoMap>(_session->tempo_map(), &before, &after));
6139 commit_reversible_command ();
6143 Editor::split_region_at_transients ()
6145 AnalysisFeatureList positions;
6147 RegionSelection rs = get_regions_from_selection_and_entered ();
6149 if (!_session || rs.empty()) {
6153 begin_reversible_command (_("split regions"));
6155 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ) {
6157 RegionSelection::iterator tmp;
6162 boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion> ((*i)->region());
6164 if (ar && (ar->get_transients (positions) == 0)) {
6165 split_region_at_points ((*i)->region(), positions, true);
6172 commit_reversible_command ();
6177 Editor::split_region_at_points (boost::shared_ptr<Region> r, AnalysisFeatureList& positions, bool can_ferret, bool select_new)
6179 bool use_rhythmic_rodent = false;
6181 boost::shared_ptr<Playlist> pl = r->playlist();
6183 list<boost::shared_ptr<Region> > new_regions;
6189 if (positions.empty()) {
6194 if (positions.size() > 20 && can_ferret) {
6195 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);
6196 MessageDialog msg (msgstr,
6199 Gtk::BUTTONS_OK_CANCEL);
6202 msg.add_button (_("Call for the Ferret!"), RESPONSE_APPLY);
6203 msg.set_secondary_text (_("Press OK to continue with this split operation\nor ask the Ferret dialog to tune the analysis"));
6205 msg.set_secondary_text (_("Press OK to continue with this split operation"));
6208 msg.set_title (_("Excessive split?"));
6211 int response = msg.run();
6217 case RESPONSE_APPLY:
6218 use_rhythmic_rodent = true;
6225 if (use_rhythmic_rodent) {
6226 show_rhythm_ferret ();
6230 AnalysisFeatureList::const_iterator x;
6232 pl->clear_changes ();
6233 pl->clear_owned_changes ();
6235 x = positions.begin();
6237 if (x == positions.end()) {
6242 pl->remove_region (r);
6246 while (x != positions.end()) {
6248 /* deal with positons that are out of scope of present region bounds */
6249 if (*x <= 0 || *x > r->length()) {
6254 /* file start = original start + how far we from the initial position ?
6257 framepos_t file_start = r->start() + pos;
6259 /* length = next position - current position
6262 framepos_t len = (*x) - pos;
6264 /* XXX we do we really want to allow even single-sample regions?
6265 shouldn't we have some kind of lower limit on region size?
6274 if (RegionFactory::region_name (new_name, r->name())) {
6278 /* do NOT announce new regions 1 by one, just wait till they are all done */
6282 plist.add (ARDOUR::Properties::start, file_start);
6283 plist.add (ARDOUR::Properties::length, len);
6284 plist.add (ARDOUR::Properties::name, new_name);
6285 plist.add (ARDOUR::Properties::layer, 0);
6287 boost::shared_ptr<Region> nr = RegionFactory::create (r->sources(), plist, false);
6288 /* because we set annouce to false, manually add the new region to the
6291 RegionFactory::map_add (nr);
6293 pl->add_region (nr, r->position() + pos);
6296 new_regions.push_front(nr);
6305 RegionFactory::region_name (new_name, r->name());
6307 /* Add the final region */
6310 plist.add (ARDOUR::Properties::start, r->start() + pos);
6311 plist.add (ARDOUR::Properties::length, r->last_frame() - (r->position() + pos) + 1);
6312 plist.add (ARDOUR::Properties::name, new_name);
6313 plist.add (ARDOUR::Properties::layer, 0);
6315 boost::shared_ptr<Region> nr = RegionFactory::create (r->sources(), plist, false);
6316 /* because we set annouce to false, manually add the new region to the
6319 RegionFactory::map_add (nr);
6320 pl->add_region (nr, r->position() + pos);
6323 new_regions.push_front(nr);
6328 /* We might have removed regions, which alters other regions' layering_index,
6329 so we need to do a recursive diff here.
6331 vector<Command*> cmds;
6333 _session->add_commands (cmds);
6335 _session->add_command (new StatefulDiffCommand (pl));
6339 for (list<boost::shared_ptr<Region> >::iterator i = new_regions.begin(); i != new_regions.end(); ++i){
6340 set_selected_regionview_from_region_list ((*i), Selection::Add);
6346 Editor::place_transient()
6352 RegionSelection rs = get_regions_from_selection_and_edit_point ();
6358 framepos_t where = get_preferred_edit_position();
6360 begin_reversible_command (_("place transient"));
6362 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6363 framepos_t position = (*r)->region()->position();
6364 (*r)->region()->add_transient(where - position);
6367 commit_reversible_command ();
6371 Editor::remove_transient(ArdourCanvas::Item* item)
6377 ArdourCanvas::Line* _line = reinterpret_cast<ArdourCanvas::Line*> (item);
6380 AudioRegionView* _arv = reinterpret_cast<AudioRegionView*> (item->get_data ("regionview"));
6381 _arv->remove_transient (*(float*) _line->get_data ("position"));
6385 Editor::snap_regions_to_grid ()
6387 list <boost::shared_ptr<Playlist > > used_playlists;
6389 RegionSelection rs = get_regions_from_selection_and_entered ();
6391 if (!_session || rs.empty()) {
6395 begin_reversible_command (_("snap regions to grid"));
6397 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6399 boost::shared_ptr<Playlist> pl = (*r)->region()->playlist();
6401 if (!pl->frozen()) {
6402 /* we haven't seen this playlist before */
6404 /* remember used playlists so we can thaw them later */
6405 used_playlists.push_back(pl);
6409 framepos_t start_frame = (*r)->region()->first_frame ();
6410 snap_to (start_frame);
6411 (*r)->region()->set_position (start_frame);
6414 while (used_playlists.size() > 0) {
6415 list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
6417 used_playlists.pop_front();
6420 commit_reversible_command ();
6424 Editor::close_region_gaps ()
6426 list <boost::shared_ptr<Playlist > > used_playlists;
6428 RegionSelection rs = get_regions_from_selection_and_entered ();
6430 if (!_session || rs.empty()) {
6434 Dialog dialog (_("Close Region Gaps"));
6437 table.set_spacings (12);
6438 table.set_border_width (12);
6439 Label* l = manage (left_aligned_label (_("Crossfade length")));
6440 table.attach (*l, 0, 1, 0, 1);
6442 SpinButton spin_crossfade (1, 0);
6443 spin_crossfade.set_range (0, 15);
6444 spin_crossfade.set_increments (1, 1);
6445 spin_crossfade.set_value (5);
6446 table.attach (spin_crossfade, 1, 2, 0, 1);
6448 table.attach (*manage (new Label (_("ms"))), 2, 3, 0, 1);
6450 l = manage (left_aligned_label (_("Pull-back length")));
6451 table.attach (*l, 0, 1, 1, 2);
6453 SpinButton spin_pullback (1, 0);
6454 spin_pullback.set_range (0, 100);
6455 spin_pullback.set_increments (1, 1);
6456 spin_pullback.set_value(30);
6457 table.attach (spin_pullback, 1, 2, 1, 2);
6459 table.attach (*manage (new Label (_("ms"))), 2, 3, 1, 2);
6461 dialog.get_vbox()->pack_start (table);
6462 dialog.add_button (Stock::CANCEL, RESPONSE_CANCEL);
6463 dialog.add_button (_("Ok"), RESPONSE_ACCEPT);
6466 if (dialog.run () == RESPONSE_CANCEL) {
6470 framepos_t crossfade_len = spin_crossfade.get_value();
6471 framepos_t pull_back_frames = spin_pullback.get_value();
6473 crossfade_len = lrintf (crossfade_len * _session->frame_rate()/1000);
6474 pull_back_frames = lrintf (pull_back_frames * _session->frame_rate()/1000);
6476 /* Iterate over the region list and make adjacent regions overlap by crossfade_len_ms */
6478 begin_reversible_command (_("close region gaps"));
6481 boost::shared_ptr<Region> last_region;
6483 rs.sort_by_position_and_track();
6485 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6487 boost::shared_ptr<Playlist> pl = (*r)->region()->playlist();
6489 if (!pl->frozen()) {
6490 /* we haven't seen this playlist before */
6492 /* remember used playlists so we can thaw them later */
6493 used_playlists.push_back(pl);
6497 framepos_t position = (*r)->region()->position();
6499 if (idx == 0 || position < last_region->position()){
6500 last_region = (*r)->region();
6505 (*r)->region()->trim_front( (position - pull_back_frames));
6506 last_region->trim_end( (position - pull_back_frames + crossfade_len));
6508 last_region = (*r)->region();
6513 while (used_playlists.size() > 0) {
6514 list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
6516 used_playlists.pop_front();
6519 commit_reversible_command ();
6523 Editor::tab_to_transient (bool forward)
6525 AnalysisFeatureList positions;
6527 RegionSelection rs = get_regions_from_selection_and_entered ();
6533 framepos_t pos = _session->audible_frame ();
6535 if (!selection->tracks.empty()) {
6537 /* don't waste time searching for transients in duplicate playlists.
6540 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
6542 for (TrackViewList::iterator t = ts.begin(); t != ts.end(); ++t) {
6544 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*t);
6547 boost::shared_ptr<Track> tr = rtv->track();
6549 boost::shared_ptr<Playlist> pl = tr->playlist ();
6551 framepos_t result = pl->find_next_transient (pos, forward ? 1 : -1);
6554 positions.push_back (result);
6567 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6568 (*r)->region()->get_transients (positions);
6572 TransientDetector::cleanup_transients (positions, _session->frame_rate(), 3.0);
6575 AnalysisFeatureList::iterator x;
6577 for (x = positions.begin(); x != positions.end(); ++x) {
6583 if (x != positions.end ()) {
6584 _session->request_locate (*x);
6588 AnalysisFeatureList::reverse_iterator x;
6590 for (x = positions.rbegin(); x != positions.rend(); ++x) {
6596 if (x != positions.rend ()) {
6597 _session->request_locate (*x);
6603 Editor::playhead_forward_to_grid ()
6609 framepos_t pos = playhead_cursor->current_frame ();
6610 if (pos < max_framepos - 1) {
6612 snap_to_internal (pos, RoundUpAlways, false);
6613 _session->request_locate (pos);
6619 Editor::playhead_backward_to_grid ()
6625 framepos_t pos = playhead_cursor->current_frame ();
6628 snap_to_internal (pos, RoundDownAlways, false);
6629 _session->request_locate (pos);
6634 Editor::set_track_height (Height h)
6636 TrackSelection& ts (selection->tracks);
6638 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
6639 (*x)->set_height_enum (h);
6644 Editor::toggle_tracks_active ()
6646 TrackSelection& ts (selection->tracks);
6648 bool target = false;
6654 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
6655 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*x);
6659 target = !rtv->_route->active();
6662 rtv->_route->set_active (target, this);
6668 Editor::remove_tracks ()
6670 TrackSelection& ts (selection->tracks);
6676 vector<string> choices;
6680 const char* trackstr;
6682 vector<boost::shared_ptr<Route> > routes;
6683 bool special_bus = false;
6685 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
6686 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*x);
6690 if (rtv->is_track()) {
6695 routes.push_back (rtv->_route);
6697 if (rtv->route()->is_master() || rtv->route()->is_monitor()) {
6702 if (special_bus && !Config->get_allow_special_bus_removal()) {
6703 MessageDialog msg (_("That would be bad news ...."),
6707 msg.set_secondary_text (string_compose (_(
6708 "Removing the master or monitor bus is such a bad idea\n\
6709 that %1 is not going to allow it.\n\
6711 If you really want to do this sort of thing\n\
6712 edit your ardour.rc file to set the\n\
6713 \"allow-special-bus-removal\" option to be \"yes\""), PROGRAM_NAME));
6720 if (ntracks + nbusses == 0) {
6724 // XXX should be using gettext plural forms, maybe?
6726 trackstr = _("tracks");
6728 trackstr = _("track");
6732 busstr = _("busses");
6739 prompt = string_compose (_("Do you really want to remove %1 %2 and %3 %4?\n"
6740 "(You may also lose the playlists associated with the %2)\n\n"
6741 "This action cannot be undone, and the session file will be overwritten!"),
6742 ntracks, trackstr, nbusses, busstr);
6744 prompt = string_compose (_("Do you really want to remove %1 %2?\n"
6745 "(You may also lose the playlists associated with the %2)\n\n"
6746 "This action cannot be undone, and the session file will be overwritten!"),
6749 } else if (nbusses) {
6750 prompt = string_compose (_("Do you really want to remove %1 %2?\n\n"
6751 "This action cannot be undone, and the session file will be overwritten"),
6755 choices.push_back (_("No, do nothing."));
6756 if (ntracks + nbusses > 1) {
6757 choices.push_back (_("Yes, remove them."));
6759 choices.push_back (_("Yes, remove it."));
6764 title = string_compose (_("Remove %1"), trackstr);
6766 title = string_compose (_("Remove %1"), busstr);
6769 Choice prompter (title, prompt, choices);
6771 if (prompter.run () != 1) {
6776 Session::StateProtector sp (_session);
6777 DisplaySuspender ds;
6778 for (vector<boost::shared_ptr<Route> >::iterator x = routes.begin(); x != routes.end(); ++x) {
6779 _session->remove_route (*x);
6785 Editor::do_insert_time ()
6787 if (selection->tracks.empty()) {
6791 InsertTimeDialog d (*this);
6792 int response = d.run ();
6794 if (response != RESPONSE_OK) {
6798 if (d.distance() == 0) {
6802 InsertTimeOption opt = d.intersected_region_action ();
6805 get_preferred_edit_position(),
6811 d.move_glued_markers(),
6812 d.move_locked_markers(),
6818 Editor::insert_time (
6819 framepos_t pos, framecnt_t frames, InsertTimeOption opt,
6820 bool all_playlists, bool ignore_music_glue, bool markers_too, bool glued_markers_too, bool locked_markers_too, bool tempo_too
6823 bool commit = false;
6825 if (Config->get_edit_mode() == Lock) {
6829 begin_reversible_command (_("insert time"));
6831 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
6833 for (TrackViewList::iterator x = ts.begin(); x != ts.end(); ++x) {
6837 /* don't operate on any playlist more than once, which could
6838 * happen if "all playlists" is enabled, but there is more
6839 * than 1 track using playlists "from" a given track.
6842 set<boost::shared_ptr<Playlist> > pl;
6844 if (all_playlists) {
6845 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*x);
6847 vector<boost::shared_ptr<Playlist> > all = _session->playlists->playlists_for_track (rtav->track ());
6848 for (vector<boost::shared_ptr<Playlist> >::iterator p = all.begin(); p != all.end(); ++p) {
6853 if ((*x)->playlist ()) {
6854 pl.insert ((*x)->playlist ());
6858 for (set<boost::shared_ptr<Playlist> >::iterator i = pl.begin(); i != pl.end(); ++i) {
6860 (*i)->clear_changes ();
6861 (*i)->clear_owned_changes ();
6863 if (opt == SplitIntersected) {
6867 (*i)->shift (pos, frames, (opt == MoveIntersected), ignore_music_glue);
6869 vector<Command*> cmds;
6871 _session->add_commands (cmds);
6873 _session->add_command (new StatefulDiffCommand (*i));
6878 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*x);
6880 rtav->route ()->shift (pos, frames);
6888 XMLNode& before (_session->locations()->get_state());
6889 Locations::LocationList copy (_session->locations()->list());
6891 for (Locations::LocationList::iterator i = copy.begin(); i != copy.end(); ++i) {
6893 Locations::LocationList::const_iterator tmp;
6895 bool const was_locked = (*i)->locked ();
6896 if (locked_markers_too) {
6900 if ((*i)->position_lock_style() == AudioTime || glued_markers_too) {
6902 if ((*i)->start() >= pos) {
6903 (*i)->set_start ((*i)->start() + frames);
6904 if (!(*i)->is_mark()) {
6905 (*i)->set_end ((*i)->end() + frames);
6918 XMLNode& after (_session->locations()->get_state());
6919 _session->add_command (new MementoCommand<Locations>(*_session->locations(), &before, &after));
6924 _session->tempo_map().insert_time (pos, frames);
6928 commit_reversible_command ();
6933 Editor::fit_selected_tracks ()
6935 if (!selection->tracks.empty()) {
6936 fit_tracks (selection->tracks);
6940 /* no selected tracks - use tracks with selected regions */
6942 if (!selection->regions.empty()) {
6943 for (RegionSelection::iterator r = selection->regions.begin(); r != selection->regions.end(); ++r) {
6944 tvl.push_back (&(*r)->get_time_axis_view ());
6950 } else if (internal_editing()) {
6951 /* no selected tracks, or regions, but in internal edit mode, so follow the mouse and use
6954 if (entered_track) {
6955 tvl.push_back (entered_track);
6964 Editor::fit_tracks (TrackViewList & tracks)
6966 if (tracks.empty()) {
6970 uint32_t child_heights = 0;
6971 int visible_tracks = 0;
6973 for (TrackSelection::iterator t = tracks.begin(); t != tracks.end(); ++t) {
6975 if (!(*t)->marked_for_display()) {
6979 child_heights += (*t)->effective_height() - (*t)->current_height();
6983 /* compute the per-track height from:
6985 total canvas visible height -
6986 height that will be taken by visible children of selected
6987 tracks - height of the ruler/hscroll area
6989 uint32_t h = (uint32_t) floor ((trackviews_height() - child_heights) / visible_tracks);
6990 double first_y_pos = DBL_MAX;
6992 if (h < TimeAxisView::preset_height (HeightSmall)) {
6993 MessageDialog msg (*this, _("There are too many tracks to fit in the current window"));
6994 /* too small to be displayed */
6998 undo_visual_stack.push_back (current_visual_state (true));
6999 no_save_visual = true;
7001 /* build a list of all tracks, including children */
7004 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
7006 TimeAxisView::Children c = (*i)->get_child_list ();
7007 for (TimeAxisView::Children::iterator j = c.begin(); j != c.end(); ++j) {
7008 all.push_back (j->get());
7012 bool prev_was_selected = false;
7013 bool is_selected = tracks.contains (all.front());
7014 bool next_is_selected;
7016 for (TrackViewList::iterator t = all.begin(); t != all.end(); ++t) {
7018 TrackViewList::iterator next;
7023 if (next != all.end()) {
7024 next_is_selected = tracks.contains (*next);
7026 next_is_selected = false;
7029 if ((*t)->marked_for_display ()) {
7031 (*t)->set_height (h);
7032 first_y_pos = std::min ((*t)->y_position (), first_y_pos);
7034 if (prev_was_selected && next_is_selected) {
7035 hide_track_in_display (*t);
7040 prev_was_selected = is_selected;
7041 is_selected = next_is_selected;
7045 set the controls_layout height now, because waiting for its size
7046 request signal handler will cause the vertical adjustment setting to fail
7049 controls_layout.property_height () = _full_canvas_height;
7050 vertical_adjustment.set_value (first_y_pos);
7052 redo_visual_stack.push_back (current_visual_state (true));
7054 visible_tracks_selector.set_text (_("Sel"));
7058 Editor::save_visual_state (uint32_t n)
7060 while (visual_states.size() <= n) {
7061 visual_states.push_back (0);
7064 if (visual_states[n] != 0) {
7065 delete visual_states[n];
7068 visual_states[n] = current_visual_state (true);
7073 Editor::goto_visual_state (uint32_t n)
7075 if (visual_states.size() <= n) {
7079 if (visual_states[n] == 0) {
7083 use_visual_state (*visual_states[n]);
7087 Editor::start_visual_state_op (uint32_t n)
7089 save_visual_state (n);
7091 PopUp* pup = new PopUp (WIN_POS_MOUSE, 1000, true);
7093 snprintf (buf, sizeof (buf), _("Saved view %u"), n+1);
7094 pup->set_text (buf);
7099 Editor::cancel_visual_state_op (uint32_t n)
7101 goto_visual_state (n);
7105 Editor::toggle_region_mute ()
7107 if (_ignore_region_action) {
7111 RegionSelection rs = get_regions_from_selection_and_entered ();
7117 if (rs.size() > 1) {
7118 begin_reversible_command (_("mute regions"));
7120 begin_reversible_command (_("mute region"));
7123 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
7125 (*i)->region()->playlist()->clear_changes ();
7126 (*i)->region()->set_muted (!(*i)->region()->muted ());
7127 _session->add_command (new StatefulDiffCommand ((*i)->region()));
7131 commit_reversible_command ();
7135 Editor::combine_regions ()
7137 /* foreach track with selected regions, take all selected regions
7138 and join them into a new region containing the subregions (as a
7142 typedef set<RouteTimeAxisView*> RTVS;
7145 if (selection->regions.empty()) {
7149 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
7150 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(&(*i)->get_time_axis_view());
7153 tracks.insert (rtv);
7157 begin_reversible_command (_("combine regions"));
7159 vector<RegionView*> new_selection;
7161 for (RTVS::iterator i = tracks.begin(); i != tracks.end(); ++i) {
7164 if ((rv = (*i)->combine_regions ()) != 0) {
7165 new_selection.push_back (rv);
7169 selection->clear_regions ();
7170 for (vector<RegionView*>::iterator i = new_selection.begin(); i != new_selection.end(); ++i) {
7171 selection->add (*i);
7174 commit_reversible_command ();
7178 Editor::uncombine_regions ()
7180 typedef set<RouteTimeAxisView*> RTVS;
7183 if (selection->regions.empty()) {
7187 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
7188 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(&(*i)->get_time_axis_view());
7191 tracks.insert (rtv);
7195 begin_reversible_command (_("uncombine regions"));
7197 for (RTVS::iterator i = tracks.begin(); i != tracks.end(); ++i) {
7198 (*i)->uncombine_regions ();
7201 commit_reversible_command ();
7205 Editor::toggle_midi_input_active (bool flip_others)
7208 boost::shared_ptr<RouteList> rl (new RouteList);
7210 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
7211 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
7217 boost::shared_ptr<MidiTrack> mt = rtav->midi_track();
7220 rl->push_back (rtav->route());
7221 onoff = !mt->input_active();
7225 _session->set_exclusive_input_active (rl, onoff, flip_others);
7232 lock_dialog = new Gtk::Dialog (string_compose (_("%1: Locked"), PROGRAM_NAME), true);
7234 Gtk::Image* padlock = manage (new Gtk::Image (ARDOUR_UI_UTILS::get_icon ("padlock_closed")));
7235 lock_dialog->get_vbox()->pack_start (*padlock);
7237 ArdourButton* b = manage (new ArdourButton);
7238 b->set_name ("lock button");
7239 b->set_text (_("Click to unlock"));
7240 b->signal_clicked.connect (sigc::mem_fun (*this, &Editor::unlock));
7241 lock_dialog->get_vbox()->pack_start (*b);
7243 lock_dialog->get_vbox()->show_all ();
7244 lock_dialog->set_size_request (200, 200);
7248 /* The global menu bar continues to be accessible to applications
7249 with modal dialogs, which means that we need to desensitize
7250 all items in the menu bar. Since those items are really just
7251 proxies for actions, that means disabling all actions.
7253 ActionManager::disable_all_actions ();
7255 lock_dialog->present ();
7261 lock_dialog->hide ();
7264 ActionManager::pop_action_state ();
7267 if (ARDOUR_UI::config()->get_lock_gui_after_seconds()) {
7268 start_lock_event_timing ();
7273 Editor::bring_in_callback (Gtk::Label* label, uint32_t n, uint32_t total, string name)
7275 Gtkmm2ext::UI::instance()->call_slot (invalidator (*this), boost::bind (&Editor::update_bring_in_message, this, label, n, total, name));
7279 Editor::update_bring_in_message (Gtk::Label* label, uint32_t n, uint32_t total, string name)
7281 label->set_text (string_compose ("Copying %1, %2 of %3", name, n, total));
7282 Gtkmm2ext::UI::instance()->flush_pending ();
7286 Editor::bring_all_sources_into_session ()
7293 ArdourDialog w (_("Moving embedded files into session folder"));
7294 w.get_vbox()->pack_start (msg);
7297 /* flush all pending GUI events because we're about to start copying
7301 Gtkmm2ext::UI::instance()->flush_pending ();
7305 _session->bring_all_sources_into_session (boost::bind (&Editor::bring_in_callback, this, &msg, _1, _2, _3));