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"
100 #include "transform_dialog.h"
105 using namespace ARDOUR;
108 using namespace Gtkmm2ext;
109 using namespace Editing;
110 using Gtkmm2ext::Keyboard;
112 /***********************************************************************
114 ***********************************************************************/
117 Editor::undo (uint32_t n)
119 if (_drags->active ()) {
125 redo_action->set_sensitive(true);
126 begin_selection_op_history ();
131 Editor::redo (uint32_t n)
133 if (_drags->active ()) {
139 cerr << "redo depth is : " << _session->redo_depth() << endl;
140 if (_session->redo_depth() == 0) {
141 redo_action->set_sensitive(false);
143 begin_selection_op_history ();
148 Editor::split_regions_at (framepos_t where, RegionSelection& regions)
152 RegionSelection pre_selected_regions = selection->regions;
153 bool working_on_selection = !pre_selected_regions.empty();
155 list<boost::shared_ptr<Playlist> > used_playlists;
156 list<RouteTimeAxisView*> used_trackviews;
158 if (regions.empty()) {
162 begin_reversible_command (_("split"));
164 // if splitting a single region, and snap-to is using
165 // region boundaries, don't pay attention to them
167 if (regions.size() == 1) {
168 switch (_snap_type) {
169 case SnapToRegionStart:
170 case SnapToRegionSync:
171 case SnapToRegionEnd:
180 EditorFreeze(); /* Emit Signal */
183 for (RegionSelection::iterator a = regions.begin(); a != regions.end(); ) {
185 RegionSelection::iterator tmp;
187 /* XXX this test needs to be more complicated, to make sure we really
188 have something to split.
191 if (!(*a)->region()->covers (where)) {
199 boost::shared_ptr<Playlist> pl = (*a)->region()->playlist();
207 /* we haven't seen this playlist before */
209 /* remember used playlists so we can thaw them later */
210 used_playlists.push_back(pl);
212 TimeAxisView& tv = (*a)->get_time_axis_view();
213 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (&tv);
215 used_trackviews.push_back (rtv);
222 pl->clear_changes ();
223 pl->split_region ((*a)->region(), where);
224 _session->add_command (new StatefulDiffCommand (pl));
230 latest_regionviews.clear ();
232 vector<sigc::connection> region_added_connections;
234 for (list<RouteTimeAxisView*>::iterator i = used_trackviews.begin(); i != used_trackviews.end(); ++i) {
235 region_added_connections.push_back ((*i)->view()->RegionViewAdded.connect (sigc::mem_fun(*this, &Editor::collect_new_region_view)));
238 while (used_playlists.size() > 0) {
239 list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
241 used_playlists.pop_front();
244 for (vector<sigc::connection>::iterator c = region_added_connections.begin(); c != region_added_connections.end(); ++c) {
249 EditorThaw(); /* Emit Signal */
252 if (working_on_selection) {
253 // IFF we were working on selected regions, try to reinstate the other region selections that existed before the freeze/thaw.
255 _ignore_follow_edits = true; // a split will change the region selection in mysterious ways; it's not practical or wanted to follow this edit
256 RegionSelectionAfterSplit rsas = Config->get_region_selection_after_split();
257 /* There are three classes of regions that we might want selected after
258 splitting selected regions:
259 - regions selected before the split operation, and unaffected by it
260 - newly-created regions before the split
261 - newly-created regions after the split
264 if (rsas & Existing) {
265 // region selections that existed before the split.
266 selection->add ( pre_selected_regions );
269 for (RegionSelection::iterator ri = latest_regionviews.begin(); ri != latest_regionviews.end(); ri++) {
270 if ((*ri)->region()->position() < where) {
271 // new regions created before the split
272 if (rsas & NewlyCreatedLeft) {
273 selection->add (*ri);
276 // new regions created after the split
277 if (rsas & NewlyCreatedRight) {
278 selection->add (*ri);
282 _ignore_follow_edits = false;
284 _ignore_follow_edits = true;
285 if( working_on_selection ) {
286 selection->add (latest_regionviews); //these are the new regions created after the split
288 _ignore_follow_edits = false;
291 commit_reversible_command ();
294 /** Move one extreme of the current range selection. If more than one range is selected,
295 * the start of the earliest range or the end of the latest range is moved.
297 * @param move_end true to move the end of the current range selection, false to move
299 * @param next true to move the extreme to the next region boundary, false to move to
303 Editor::move_range_selection_start_or_end_to_region_boundary (bool move_end, bool next)
305 if (selection->time.start() == selection->time.end_frame()) {
309 framepos_t start = selection->time.start ();
310 framepos_t end = selection->time.end_frame ();
312 /* the position of the thing we may move */
313 framepos_t pos = move_end ? end : start;
314 int dir = next ? 1 : -1;
316 /* so we don't find the current region again */
317 if (dir > 0 || pos > 0) {
321 framepos_t const target = get_region_boundary (pos, dir, true, false);
336 begin_reversible_command (_("alter selection"));
337 selection->set_preserving_all_ranges (start, end);
338 commit_reversible_command ();
342 Editor::nudge_forward_release (GdkEventButton* ev)
344 if (ev->state & Keyboard::PrimaryModifier) {
345 nudge_forward (false, true);
347 nudge_forward (false, false);
353 Editor::nudge_backward_release (GdkEventButton* ev)
355 if (ev->state & Keyboard::PrimaryModifier) {
356 nudge_backward (false, true);
358 nudge_backward (false, false);
365 Editor::nudge_forward (bool next, bool force_playhead)
368 framepos_t next_distance;
374 RegionSelection rs = get_regions_from_selection_and_entered ();
376 if (!force_playhead && !rs.empty()) {
378 begin_reversible_command (_("nudge regions forward"));
380 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
381 boost::shared_ptr<Region> r ((*i)->region());
383 distance = get_nudge_distance (r->position(), next_distance);
386 distance = next_distance;
390 r->set_position (r->position() + distance);
391 _session->add_command (new StatefulDiffCommand (r));
394 commit_reversible_command ();
397 } else if (!force_playhead && !selection->markers.empty()) {
401 begin_reversible_command (_("nudge location forward"));
403 for (MarkerSelection::iterator i = selection->markers.begin(); i != selection->markers.end(); ++i) {
405 Location* loc = find_location_from_marker ((*i), is_start);
409 XMLNode& before (loc->get_state());
412 distance = get_nudge_distance (loc->start(), next_distance);
414 distance = next_distance;
416 if (max_framepos - distance > loc->start() + loc->length()) {
417 loc->set_start (loc->start() + distance);
419 loc->set_start (max_framepos - loc->length());
422 distance = get_nudge_distance (loc->end(), next_distance);
424 distance = next_distance;
426 if (max_framepos - distance > loc->end()) {
427 loc->set_end (loc->end() + distance);
429 loc->set_end (max_framepos);
432 XMLNode& after (loc->get_state());
433 _session->add_command (new MementoCommand<Location>(*loc, &before, &after));
437 commit_reversible_command ();
440 distance = get_nudge_distance (playhead_cursor->current_frame (), next_distance);
441 _session->request_locate (playhead_cursor->current_frame () + distance);
446 Editor::nudge_backward (bool next, bool force_playhead)
449 framepos_t next_distance;
455 RegionSelection rs = get_regions_from_selection_and_entered ();
457 if (!force_playhead && !rs.empty()) {
459 begin_reversible_command (_("nudge regions backward"));
461 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
462 boost::shared_ptr<Region> r ((*i)->region());
464 distance = get_nudge_distance (r->position(), next_distance);
467 distance = next_distance;
472 if (r->position() > distance) {
473 r->set_position (r->position() - distance);
477 _session->add_command (new StatefulDiffCommand (r));
480 commit_reversible_command ();
482 } else if (!force_playhead && !selection->markers.empty()) {
486 begin_reversible_command (_("nudge location forward"));
488 for (MarkerSelection::iterator i = selection->markers.begin(); i != selection->markers.end(); ++i) {
490 Location* loc = find_location_from_marker ((*i), is_start);
494 XMLNode& before (loc->get_state());
497 distance = get_nudge_distance (loc->start(), next_distance);
499 distance = next_distance;
501 if (distance < loc->start()) {
502 loc->set_start (loc->start() - distance);
507 distance = get_nudge_distance (loc->end(), next_distance);
510 distance = next_distance;
513 if (distance < loc->end() - loc->length()) {
514 loc->set_end (loc->end() - distance);
516 loc->set_end (loc->length());
520 XMLNode& after (loc->get_state());
521 _session->add_command (new MementoCommand<Location>(*loc, &before, &after));
525 commit_reversible_command ();
529 distance = get_nudge_distance (playhead_cursor->current_frame (), next_distance);
531 if (playhead_cursor->current_frame () > distance) {
532 _session->request_locate (playhead_cursor->current_frame () - distance);
534 _session->goto_start();
540 Editor::nudge_forward_capture_offset ()
542 RegionSelection rs = get_regions_from_selection_and_entered ();
544 if (!_session || rs.empty()) {
548 begin_reversible_command (_("nudge forward"));
550 framepos_t const distance = _session->worst_output_latency();
552 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
553 boost::shared_ptr<Region> r ((*i)->region());
556 r->set_position (r->position() + distance);
557 _session->add_command(new StatefulDiffCommand (r));
560 commit_reversible_command ();
564 Editor::nudge_backward_capture_offset ()
566 RegionSelection rs = get_regions_from_selection_and_entered ();
568 if (!_session || rs.empty()) {
572 begin_reversible_command (_("nudge backward"));
574 framepos_t const distance = _session->worst_output_latency();
576 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
577 boost::shared_ptr<Region> r ((*i)->region());
581 if (r->position() > distance) {
582 r->set_position (r->position() - distance);
586 _session->add_command(new StatefulDiffCommand (r));
589 commit_reversible_command ();
592 struct RegionSelectionPositionSorter {
593 bool operator() (RegionView* a, RegionView* b) {
594 return a->region()->position() < b->region()->position();
599 Editor::sequence_regions ()
602 framepos_t r_end_prev;
610 RegionSelection rs = get_regions_from_selection_and_entered ();
611 rs.sort(RegionSelectionPositionSorter());
615 begin_reversible_command (_("sequence regions"));
616 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
617 boost::shared_ptr<Region> r ((*i)->region());
625 if(r->position_locked())
632 r->set_position(r_end_prev);
635 _session->add_command (new StatefulDiffCommand (r));
637 r_end=r->position() + r->length();
641 commit_reversible_command ();
649 Editor::move_to_start ()
651 _session->goto_start ();
655 Editor::move_to_end ()
658 _session->request_locate (_session->current_end_frame());
662 Editor::build_region_boundary_cache ()
665 vector<RegionPoint> interesting_points;
666 boost::shared_ptr<Region> r;
667 TrackViewList tracks;
670 region_boundary_cache.clear ();
676 switch (_snap_type) {
677 case SnapToRegionStart:
678 interesting_points.push_back (Start);
680 case SnapToRegionEnd:
681 interesting_points.push_back (End);
683 case SnapToRegionSync:
684 interesting_points.push_back (SyncPoint);
686 case SnapToRegionBoundary:
687 interesting_points.push_back (Start);
688 interesting_points.push_back (End);
691 fatal << string_compose (_("build_region_boundary_cache called with snap_type = %1"), _snap_type) << endmsg;
692 abort(); /*NOTREACHED*/
696 TimeAxisView *ontrack = 0;
699 if (!selection->tracks.empty()) {
700 tlist = selection->tracks.filter_to_unique_playlists ();
702 tlist = track_views.filter_to_unique_playlists ();
705 while (pos < _session->current_end_frame() && !at_end) {
708 framepos_t lpos = max_framepos;
710 for (vector<RegionPoint>::iterator p = interesting_points.begin(); p != interesting_points.end(); ++p) {
712 if ((r = find_next_region (pos, *p, 1, tlist, &ontrack)) == 0) {
713 if (*p == interesting_points.back()) {
716 /* move to next point type */
722 rpos = r->first_frame();
726 rpos = r->last_frame();
730 rpos = r->sync_position ();
738 RouteTimeAxisView *rtav;
740 if (ontrack != 0 && (rtav = dynamic_cast<RouteTimeAxisView*>(ontrack)) != 0 ) {
741 if (rtav->track() != 0) {
742 speed = rtav->track()->speed();
746 rpos = track_frame_to_session_frame (rpos, speed);
752 /* prevent duplicates, but we don't use set<> because we want to be able
756 vector<framepos_t>::iterator ri;
758 for (ri = region_boundary_cache.begin(); ri != region_boundary_cache.end(); ++ri) {
764 if (ri == region_boundary_cache.end()) {
765 region_boundary_cache.push_back (rpos);
772 /* finally sort to be sure that the order is correct */
774 sort (region_boundary_cache.begin(), region_boundary_cache.end());
777 boost::shared_ptr<Region>
778 Editor::find_next_region (framepos_t frame, RegionPoint point, int32_t dir, TrackViewList& tracks, TimeAxisView **ontrack)
780 TrackViewList::iterator i;
781 framepos_t closest = max_framepos;
782 boost::shared_ptr<Region> ret;
786 framepos_t track_frame;
787 RouteTimeAxisView *rtav;
789 for (i = tracks.begin(); i != tracks.end(); ++i) {
792 boost::shared_ptr<Region> r;
795 if ( (rtav = dynamic_cast<RouteTimeAxisView*>(*i)) != 0 ) {
796 if (rtav->track()!=0)
797 track_speed = rtav->track()->speed();
800 track_frame = session_frame_to_track_frame(frame, track_speed);
802 if ((r = (*i)->find_next_region (track_frame, point, dir)) == 0) {
808 rpos = r->first_frame ();
812 rpos = r->last_frame ();
816 rpos = r->sync_position ();
820 // rpos is a "track frame", converting it to "_session frame"
821 rpos = track_frame_to_session_frame(rpos, track_speed);
824 distance = rpos - frame;
826 distance = frame - rpos;
829 if (distance < closest) {
841 Editor::find_next_region_boundary (framepos_t pos, int32_t dir, const TrackViewList& tracks)
843 framecnt_t distance = max_framepos;
844 framepos_t current_nearest = -1;
846 for (TrackViewList::const_iterator i = tracks.begin(); i != tracks.end(); ++i) {
847 framepos_t contender;
850 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*i);
856 if ((contender = rtv->find_next_region_boundary (pos, dir)) < 0) {
860 d = ::llabs (pos - contender);
863 current_nearest = contender;
868 return current_nearest;
872 Editor::get_region_boundary (framepos_t pos, int32_t dir, bool with_selection, bool only_onscreen)
877 if (with_selection && Config->get_region_boundaries_from_selected_tracks()) {
879 if (!selection->tracks.empty()) {
881 target = find_next_region_boundary (pos, dir, selection->tracks);
885 if (only_onscreen || Config->get_region_boundaries_from_onscreen_tracks()) {
886 get_onscreen_tracks (tvl);
887 target = find_next_region_boundary (pos, dir, tvl);
889 target = find_next_region_boundary (pos, dir, track_views);
895 if (only_onscreen || Config->get_region_boundaries_from_onscreen_tracks()) {
896 get_onscreen_tracks (tvl);
897 target = find_next_region_boundary (pos, dir, tvl);
899 target = find_next_region_boundary (pos, dir, track_views);
907 Editor::cursor_to_region_boundary (bool with_selection, int32_t dir)
909 framepos_t pos = playhead_cursor->current_frame ();
916 // so we don't find the current region again..
917 if (dir > 0 || pos > 0) {
921 if ((target = get_region_boundary (pos, dir, with_selection, false)) < 0) {
925 _session->request_locate (target);
929 Editor::cursor_to_next_region_boundary (bool with_selection)
931 cursor_to_region_boundary (with_selection, 1);
935 Editor::cursor_to_previous_region_boundary (bool with_selection)
937 cursor_to_region_boundary (with_selection, -1);
941 Editor::cursor_to_region_point (EditorCursor* cursor, RegionPoint point, int32_t dir)
943 boost::shared_ptr<Region> r;
944 framepos_t pos = cursor->current_frame ();
950 TimeAxisView *ontrack = 0;
952 // so we don't find the current region again..
956 if (!selection->tracks.empty()) {
958 r = find_next_region (pos, point, dir, selection->tracks, &ontrack);
960 } else if (clicked_axisview) {
963 t.push_back (clicked_axisview);
965 r = find_next_region (pos, point, dir, t, &ontrack);
969 r = find_next_region (pos, point, dir, track_views, &ontrack);
978 pos = r->first_frame ();
982 pos = r->last_frame ();
986 pos = r->sync_position ();
991 RouteTimeAxisView *rtav;
993 if ( ontrack != 0 && (rtav = dynamic_cast<RouteTimeAxisView*>(ontrack)) != 0 ) {
994 if (rtav->track() != 0) {
995 speed = rtav->track()->speed();
999 pos = track_frame_to_session_frame(pos, speed);
1001 if (cursor == playhead_cursor) {
1002 _session->request_locate (pos);
1004 cursor->set_position (pos);
1009 Editor::cursor_to_next_region_point (EditorCursor* cursor, RegionPoint point)
1011 cursor_to_region_point (cursor, point, 1);
1015 Editor::cursor_to_previous_region_point (EditorCursor* cursor, RegionPoint point)
1017 cursor_to_region_point (cursor, point, -1);
1021 Editor::cursor_to_selection_start (EditorCursor *cursor)
1025 switch (mouse_mode) {
1027 if (!selection->regions.empty()) {
1028 pos = selection->regions.start();
1033 if (!selection->time.empty()) {
1034 pos = selection->time.start ();
1042 if (cursor == playhead_cursor) {
1043 _session->request_locate (pos);
1045 cursor->set_position (pos);
1050 Editor::cursor_to_selection_end (EditorCursor *cursor)
1054 switch (mouse_mode) {
1056 if (!selection->regions.empty()) {
1057 pos = selection->regions.end_frame();
1062 if (!selection->time.empty()) {
1063 pos = selection->time.end_frame ();
1071 if (cursor == playhead_cursor) {
1072 _session->request_locate (pos);
1074 cursor->set_position (pos);
1079 Editor::selected_marker_to_region_boundary (bool with_selection, int32_t dir)
1089 if (selection->markers.empty()) {
1093 if (!mouse_frame (mouse, ignored)) {
1097 add_location_mark (mouse);
1100 if ((loc = find_location_from_marker (selection->markers.front(), ignored)) == 0) {
1104 framepos_t pos = loc->start();
1106 // so we don't find the current region again..
1107 if (dir > 0 || pos > 0) {
1111 if ((target = get_region_boundary (pos, dir, with_selection, false)) < 0) {
1115 loc->move_to (target);
1119 Editor::selected_marker_to_next_region_boundary (bool with_selection)
1121 selected_marker_to_region_boundary (with_selection, 1);
1125 Editor::selected_marker_to_previous_region_boundary (bool with_selection)
1127 selected_marker_to_region_boundary (with_selection, -1);
1131 Editor::selected_marker_to_region_point (RegionPoint point, int32_t dir)
1133 boost::shared_ptr<Region> r;
1138 if (!_session || selection->markers.empty()) {
1142 if ((loc = find_location_from_marker (selection->markers.front(), ignored)) == 0) {
1146 TimeAxisView *ontrack = 0;
1150 // so we don't find the current region again..
1154 if (!selection->tracks.empty()) {
1156 r = find_next_region (pos, point, dir, selection->tracks, &ontrack);
1160 r = find_next_region (pos, point, dir, track_views, &ontrack);
1169 pos = r->first_frame ();
1173 pos = r->last_frame ();
1177 pos = r->adjust_to_sync (r->first_frame());
1182 RouteTimeAxisView *rtav;
1184 if (ontrack != 0 && (rtav = dynamic_cast<RouteTimeAxisView*>(ontrack)) != 0) {
1185 if (rtav->track() != 0) {
1186 speed = rtav->track()->speed();
1190 pos = track_frame_to_session_frame(pos, speed);
1196 Editor::selected_marker_to_next_region_point (RegionPoint point)
1198 selected_marker_to_region_point (point, 1);
1202 Editor::selected_marker_to_previous_region_point (RegionPoint point)
1204 selected_marker_to_region_point (point, -1);
1208 Editor::selected_marker_to_selection_start ()
1214 if (!_session || selection->markers.empty()) {
1218 if ((loc = find_location_from_marker (selection->markers.front(), ignored)) == 0) {
1222 switch (mouse_mode) {
1224 if (!selection->regions.empty()) {
1225 pos = selection->regions.start();
1230 if (!selection->time.empty()) {
1231 pos = selection->time.start ();
1243 Editor::selected_marker_to_selection_end ()
1249 if (!_session || selection->markers.empty()) {
1253 if ((loc = find_location_from_marker (selection->markers.front(), ignored)) == 0) {
1257 switch (mouse_mode) {
1259 if (!selection->regions.empty()) {
1260 pos = selection->regions.end_frame();
1265 if (!selection->time.empty()) {
1266 pos = selection->time.end_frame ();
1278 Editor::scroll_playhead (bool forward)
1280 framepos_t pos = playhead_cursor->current_frame ();
1281 framecnt_t delta = (framecnt_t) floor (current_page_samples() / 0.8);
1284 if (pos == max_framepos) {
1288 if (pos < max_framepos - delta) {
1307 _session->request_locate (pos);
1311 Editor::cursor_align (bool playhead_to_edit)
1317 if (playhead_to_edit) {
1319 if (selection->markers.empty()) {
1323 _session->request_locate (selection->markers.front()->position(), _session->transport_rolling());
1326 /* move selected markers to playhead */
1328 for (MarkerSelection::iterator i = selection->markers.begin(); i != selection->markers.end(); ++i) {
1331 Location* loc = find_location_from_marker (*i, ignored);
1333 if (loc->is_mark()) {
1334 loc->set_start (playhead_cursor->current_frame ());
1336 loc->set (playhead_cursor->current_frame (),
1337 playhead_cursor->current_frame () + loc->length());
1344 Editor::scroll_backward (float pages)
1346 framepos_t const one_page = (framepos_t) rint (_visible_canvas_width * samples_per_pixel);
1347 framepos_t const cnt = (framepos_t) floor (pages * one_page);
1350 if (leftmost_frame < cnt) {
1353 frame = leftmost_frame - cnt;
1356 reset_x_origin (frame);
1360 Editor::scroll_forward (float pages)
1362 framepos_t const one_page = (framepos_t) rint (_visible_canvas_width * samples_per_pixel);
1363 framepos_t const cnt = (framepos_t) floor (pages * one_page);
1366 if (max_framepos - cnt < leftmost_frame) {
1367 frame = max_framepos - cnt;
1369 frame = leftmost_frame + cnt;
1372 reset_x_origin (frame);
1376 Editor::scroll_tracks_down ()
1378 double vert_value = vertical_adjustment.get_value() + vertical_adjustment.get_page_size();
1379 if (vert_value > vertical_adjustment.get_upper() - _visible_canvas_height) {
1380 vert_value = vertical_adjustment.get_upper() - _visible_canvas_height;
1383 vertical_adjustment.set_value (vert_value);
1387 Editor::scroll_tracks_up ()
1389 vertical_adjustment.set_value (vertical_adjustment.get_value() - vertical_adjustment.get_page_size());
1393 Editor::scroll_tracks_down_line ()
1395 double vert_value = vertical_adjustment.get_value() + 60;
1397 if (vert_value > vertical_adjustment.get_upper() - _visible_canvas_height) {
1398 vert_value = vertical_adjustment.get_upper() - _visible_canvas_height;
1401 vertical_adjustment.set_value (vert_value);
1405 Editor::scroll_tracks_up_line ()
1407 reset_y_origin (vertical_adjustment.get_value() - 60);
1411 Editor::scroll_down_one_track ()
1413 TrackViewList::reverse_iterator next = track_views.rend();
1414 std::pair<TimeAxisView*,double> res;
1415 const double top_of_trackviews = vertical_adjustment.get_value();
1417 for (TrackViewList::reverse_iterator t = track_views.rbegin(); t != track_views.rend(); ++t) {
1418 if ((*t)->hidden()) {
1423 /* If this is the upper-most visible trackview, we want to display
1424 the one above it (next)
1427 res = (*t)->covers_y_position (top_of_trackviews);
1435 /* move to the track below the first one that covers the */
1437 if (next != track_views.rend()) {
1438 ensure_time_axis_view_is_visible (**next, true);
1446 Editor::scroll_up_one_track ()
1448 TrackViewList::iterator prev = track_views.end();
1449 std::pair<TimeAxisView*,double> res;
1450 double top_of_trackviews = vertical_adjustment.get_value ();
1452 for (TrackViewList::iterator t = track_views.begin(); t != track_views.end(); ++t) {
1454 if ((*t)->hidden()) {
1458 /* find the trackview at the top of the trackview group */
1459 res = (*t)->covers_y_position (top_of_trackviews);
1468 if (prev != track_views.end()) {
1469 ensure_time_axis_view_is_visible (**prev, true);
1479 Editor::tav_zoom_step (bool coarser)
1481 DisplaySuspender ds;
1485 if (selection->tracks.empty()) {
1488 ts = &selection->tracks;
1491 for (TrackViewList::iterator i = ts->begin(); i != ts->end(); ++i) {
1492 TimeAxisView *tv = (static_cast<TimeAxisView*>(*i));
1493 tv->step_height (coarser);
1498 Editor::tav_zoom_smooth (bool coarser, bool force_all)
1500 DisplaySuspender ds;
1504 if (selection->tracks.empty() || force_all) {
1507 ts = &selection->tracks;
1510 for (TrackViewList::iterator i = ts->begin(); i != ts->end(); ++i) {
1511 TimeAxisView *tv = (static_cast<TimeAxisView*>(*i));
1512 uint32_t h = tv->current_height ();
1517 if (h >= TimeAxisView::preset_height (HeightSmall)) {
1522 tv->set_height (h + 5);
1529 Editor::temporal_zoom_step (bool coarser)
1531 ENSURE_GUI_THREAD (*this, &Editor::temporal_zoom_step, coarser)
1533 framecnt_t nspp = samples_per_pixel;
1541 temporal_zoom (nspp);
1545 Editor::temporal_zoom (framecnt_t fpp)
1551 framepos_t current_page = current_page_samples();
1552 framepos_t current_leftmost = leftmost_frame;
1553 framepos_t current_rightmost;
1554 framepos_t current_center;
1555 framepos_t new_page_size;
1556 framepos_t half_page_size;
1557 framepos_t leftmost_after_zoom = 0;
1559 bool in_track_canvas;
1563 if (fpp == samples_per_pixel) {
1567 // Imposing an arbitrary limit to zoom out as too much zoom out produces
1568 // segfaults for lack of memory. If somebody decides this is not high enough I
1569 // believe it can be raisen to higher values but some limit must be in place.
1571 // This constant represents 1 day @ 48kHz on a 1600 pixel wide display
1572 // all of which is used for the editor track displays. The whole day
1573 // would be 4147200000 samples, so 2592000 samples per pixel.
1575 nfpp = min (fpp, (framecnt_t) 2592000);
1576 nfpp = max ((framecnt_t) 1, nfpp);
1578 new_page_size = (framepos_t) floor (_visible_canvas_width * nfpp);
1579 half_page_size = new_page_size / 2;
1581 switch (zoom_focus) {
1583 leftmost_after_zoom = current_leftmost;
1586 case ZoomFocusRight:
1587 current_rightmost = leftmost_frame + current_page;
1588 if (current_rightmost < new_page_size) {
1589 leftmost_after_zoom = 0;
1591 leftmost_after_zoom = current_rightmost - new_page_size;
1595 case ZoomFocusCenter:
1596 current_center = current_leftmost + (current_page/2);
1597 if (current_center < half_page_size) {
1598 leftmost_after_zoom = 0;
1600 leftmost_after_zoom = current_center - half_page_size;
1604 case ZoomFocusPlayhead:
1605 /* centre playhead */
1606 l = playhead_cursor->current_frame () - (new_page_size * 0.5);
1609 leftmost_after_zoom = 0;
1610 } else if (l > max_framepos) {
1611 leftmost_after_zoom = max_framepos - new_page_size;
1613 leftmost_after_zoom = (framepos_t) l;
1617 case ZoomFocusMouse:
1618 /* try to keep the mouse over the same point in the display */
1620 if (!mouse_frame (where, in_track_canvas)) {
1621 /* use playhead instead */
1622 where = playhead_cursor->current_frame ();
1624 if (where < half_page_size) {
1625 leftmost_after_zoom = 0;
1627 leftmost_after_zoom = where - half_page_size;
1632 l = - ((new_page_size * ((where - current_leftmost)/(double)current_page)) - where);
1635 leftmost_after_zoom = 0;
1636 } else if (l > max_framepos) {
1637 leftmost_after_zoom = max_framepos - new_page_size;
1639 leftmost_after_zoom = (framepos_t) l;
1646 /* try to keep the edit point in the same place */
1647 where = get_preferred_edit_position ();
1651 double l = - ((new_page_size * ((where - current_leftmost)/(double)current_page)) - where);
1654 leftmost_after_zoom = 0;
1655 } else if (l > max_framepos) {
1656 leftmost_after_zoom = max_framepos - new_page_size;
1658 leftmost_after_zoom = (framepos_t) l;
1662 /* edit point not defined */
1669 // leftmost_after_zoom = min (leftmost_after_zoom, _session->current_end_frame());
1671 reposition_and_zoom (leftmost_after_zoom, nfpp);
1675 Editor::calc_extra_zoom_edges(framepos_t &start, framepos_t &end)
1677 /* this func helps make sure we leave a little space
1678 at each end of the editor so that the zoom doesn't fit the region
1679 precisely to the screen.
1682 GdkScreen* screen = gdk_screen_get_default ();
1683 const gint pixwidth = gdk_screen_get_width (screen);
1684 const gint mmwidth = gdk_screen_get_width_mm (screen);
1685 const double pix_per_mm = (double) pixwidth/ (double) mmwidth;
1686 const double one_centimeter_in_pixels = pix_per_mm * 10.0;
1688 const framepos_t range = end - start;
1689 const framecnt_t new_fpp = (framecnt_t) ceil ((double) range / (double) _visible_canvas_width);
1690 const framepos_t extra_samples = (framepos_t) floor (one_centimeter_in_pixels * new_fpp);
1692 if (start > extra_samples) {
1693 start -= extra_samples;
1698 if (max_framepos - extra_samples > end) {
1699 end += extra_samples;
1706 Editor::temporal_zoom_region (bool both_axes)
1708 framepos_t start = max_framepos;
1710 set<TimeAxisView*> tracks;
1712 RegionSelection rs = get_regions_from_selection_and_entered ();
1718 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
1720 if ((*i)->region()->position() < start) {
1721 start = (*i)->region()->position();
1724 if ((*i)->region()->last_frame() + 1 > end) {
1725 end = (*i)->region()->last_frame() + 1;
1728 tracks.insert (&((*i)->get_time_axis_view()));
1731 if ((start == 0 && end == 0) || end < start) {
1735 calc_extra_zoom_edges (start, end);
1737 /* if we're zooming on both axes we need to save track heights etc.
1740 undo_visual_stack.push_back (current_visual_state (both_axes));
1742 PBD::Unwinder<bool> nsv (no_save_visual, true);
1744 temporal_zoom_by_frame (start, end);
1747 uint32_t per_track_height = (uint32_t) floor ((_visible_canvas_height - 10.0) / tracks.size());
1749 /* set visible track heights appropriately */
1751 for (set<TimeAxisView*>::iterator t = tracks.begin(); t != tracks.end(); ++t) {
1752 (*t)->set_height (per_track_height);
1755 /* hide irrelevant tracks */
1757 DisplaySuspender ds;
1759 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1760 if (find (tracks.begin(), tracks.end(), (*i)) == tracks.end()) {
1761 hide_track_in_display (*i);
1765 vertical_adjustment.set_value (0.0);
1768 redo_visual_stack.push_back (current_visual_state (both_axes));
1773 Editor::temporal_zoom_selection (bool both_axes)
1775 if (!selection) return;
1777 //ToDo: if notes are selected, zoom to that
1779 //ToDo: if control points are selected, zoom to that
1781 //if region(s) are selected, zoom to that
1782 if ( !selection->regions.empty() )
1783 temporal_zoom_region (both_axes);
1785 //if a range is selected, zoom to that
1786 if (!selection->time.empty()) {
1788 framepos_t start = selection->time.start();
1789 framepos_t end = selection->time.end_frame();
1791 calc_extra_zoom_edges(start, end);
1793 temporal_zoom_by_frame (start, end);
1796 fit_selected_tracks();
1803 Editor::temporal_zoom_session ()
1805 ENSURE_GUI_THREAD (*this, &Editor::temporal_zoom_session)
1808 framecnt_t start = _session->current_start_frame();
1809 framecnt_t end = _session->current_end_frame();
1811 if (_session->actively_recording () ) {
1812 framepos_t cur = playhead_cursor->current_frame ();
1814 /* recording beyond the end marker; zoom out
1815 * by 5 seconds more so that if 'follow
1816 * playhead' is active we don't immediately
1819 end = cur + _session->frame_rate() * 5;
1823 if ((start == 0 && end == 0) || end < start) {
1827 calc_extra_zoom_edges(start, end);
1829 temporal_zoom_by_frame (start, end);
1834 Editor::temporal_zoom_by_frame (framepos_t start, framepos_t end)
1836 if (!_session) return;
1838 if ((start == 0 && end == 0) || end < start) {
1842 framepos_t range = end - start;
1844 const framecnt_t new_fpp = (framecnt_t) ceil ((double) range / (double) _visible_canvas_width);
1846 framepos_t new_page = range;
1847 framepos_t middle = (framepos_t) floor ((double) start + ((double) range / 2.0f));
1848 framepos_t new_leftmost = (framepos_t) floor ((double) middle - ((double) new_page / 2.0f));
1850 if (new_leftmost > middle) {
1854 if (new_leftmost < 0) {
1858 reposition_and_zoom (new_leftmost, new_fpp);
1862 Editor::temporal_zoom_to_frame (bool coarser, framepos_t frame)
1868 framecnt_t range_before = frame - leftmost_frame;
1872 if (samples_per_pixel <= 1) {
1875 new_spp = samples_per_pixel + (samples_per_pixel/2);
1877 range_before += range_before/2;
1879 if (samples_per_pixel >= 1) {
1880 new_spp = samples_per_pixel - (samples_per_pixel/2);
1882 /* could bail out here since we cannot zoom any finer,
1883 but leave that to the equality test below
1885 new_spp = samples_per_pixel;
1888 range_before -= range_before/2;
1891 if (new_spp == samples_per_pixel) {
1895 /* zoom focus is automatically taken as @param frame when this
1899 framepos_t new_leftmost = frame - (framepos_t)range_before;
1901 if (new_leftmost > frame) {
1905 if (new_leftmost < 0) {
1909 reposition_and_zoom (new_leftmost, new_spp);
1914 Editor::choose_new_marker_name(string &name) {
1916 if (!ARDOUR_UI::config()->get_name_new_markers()) {
1917 /* don't prompt user for a new name */
1921 ArdourPrompter dialog (true);
1923 dialog.set_prompt (_("New Name:"));
1925 dialog.set_title (_("New Location Marker"));
1927 dialog.set_name ("MarkNameWindow");
1928 dialog.set_size_request (250, -1);
1929 dialog.set_position (Gtk::WIN_POS_MOUSE);
1931 dialog.add_button (Stock::OK, RESPONSE_ACCEPT);
1932 dialog.set_initial_text (name);
1936 switch (dialog.run ()) {
1937 case RESPONSE_ACCEPT:
1943 dialog.get_result(name);
1950 Editor::add_location_from_selection ()
1954 if (selection->time.empty()) {
1958 if (_session == 0 || clicked_axisview == 0) {
1962 framepos_t start = selection->time[clicked_selection].start;
1963 framepos_t end = selection->time[clicked_selection].end;
1965 _session->locations()->next_available_name(rangename,"selection");
1966 Location *location = new Location (*_session, start, end, rangename, Location::IsRangeMarker);
1968 begin_reversible_command (_("add marker"));
1970 XMLNode &before = _session->locations()->get_state();
1971 _session->locations()->add (location, true);
1972 XMLNode &after = _session->locations()->get_state();
1973 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
1975 commit_reversible_command ();
1979 Editor::add_location_mark (framepos_t where)
1983 select_new_marker = true;
1985 _session->locations()->next_available_name(markername,"mark");
1986 if (!choose_new_marker_name(markername)) {
1989 Location *location = new Location (*_session, where, where, markername, Location::IsMark);
1990 begin_reversible_command (_("add marker"));
1992 XMLNode &before = _session->locations()->get_state();
1993 _session->locations()->add (location, true);
1994 XMLNode &after = _session->locations()->get_state();
1995 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
1997 commit_reversible_command ();
2001 Editor::add_location_from_playhead_cursor ()
2003 add_location_mark (_session->audible_frame());
2007 Editor::remove_location_at_playhead_cursor ()
2012 begin_reversible_command (_("remove marker"));
2014 XMLNode &before = _session->locations()->get_state();
2015 bool removed = false;
2017 //find location(s) at this time
2018 Locations::LocationList locs;
2019 _session->locations()->find_all_between (_session->audible_frame(), _session->audible_frame()+1, locs, Location::Flags(0));
2020 for (Locations::LocationList::iterator i = locs.begin(); i != locs.end(); ++i) {
2021 if ((*i)->is_mark()) {
2022 _session->locations()->remove (*i);
2029 XMLNode &after = _session->locations()->get_state();
2030 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2032 commit_reversible_command ();
2037 /** Add a range marker around each selected region */
2039 Editor::add_locations_from_region ()
2041 RegionSelection rs = get_regions_from_selection_and_entered ();
2047 begin_reversible_command (selection->regions.size () > 1 ? _("add markers") : _("add marker"));
2049 XMLNode &before = _session->locations()->get_state();
2051 for (RegionSelection::iterator i = rs.begin (); i != rs.end (); ++i) {
2053 boost::shared_ptr<Region> region = (*i)->region ();
2055 Location *location = new Location (*_session, region->position(), region->last_frame(), region->name(), Location::IsRangeMarker);
2057 _session->locations()->add (location, true);
2060 XMLNode &after = _session->locations()->get_state();
2061 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2063 commit_reversible_command ();
2066 /** Add a single range marker around all selected regions */
2068 Editor::add_location_from_region ()
2070 RegionSelection rs = get_regions_from_selection_and_entered ();
2076 begin_reversible_command (_("add marker"));
2078 XMLNode &before = _session->locations()->get_state();
2082 if (rs.size() > 1) {
2083 _session->locations()->next_available_name(markername, "regions");
2085 RegionView* rv = *(rs.begin());
2086 boost::shared_ptr<Region> region = rv->region();
2087 markername = region->name();
2090 if (!choose_new_marker_name(markername)) {
2094 // single range spanning all selected
2095 Location *location = new Location (*_session, selection->regions.start(), selection->regions.end_frame(), markername, Location::IsRangeMarker);
2096 _session->locations()->add (location, true);
2098 XMLNode &after = _session->locations()->get_state();
2099 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2101 commit_reversible_command ();
2107 Editor::jump_forward_to_mark ()
2113 framepos_t pos = _session->locations()->first_mark_after (playhead_cursor->current_frame());
2119 _session->request_locate (pos, _session->transport_rolling());
2123 Editor::jump_backward_to_mark ()
2129 framepos_t pos = _session->locations()->first_mark_before (playhead_cursor->current_frame());
2135 _session->request_locate (pos, _session->transport_rolling());
2141 framepos_t const pos = _session->audible_frame ();
2144 _session->locations()->next_available_name (markername, "mark");
2146 if (!choose_new_marker_name (markername)) {
2150 _session->locations()->add (new Location (*_session, pos, 0, markername, Location::IsMark), true);
2154 Editor::clear_markers ()
2157 begin_reversible_command (_("clear markers"));
2159 XMLNode &before = _session->locations()->get_state();
2160 _session->locations()->clear_markers ();
2161 XMLNode &after = _session->locations()->get_state();
2162 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2164 commit_reversible_command ();
2169 Editor::clear_ranges ()
2172 begin_reversible_command (_("clear ranges"));
2174 XMLNode &before = _session->locations()->get_state();
2176 _session->locations()->clear_ranges ();
2178 XMLNode &after = _session->locations()->get_state();
2179 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2181 commit_reversible_command ();
2186 Editor::clear_locations ()
2188 begin_reversible_command (_("clear locations"));
2190 XMLNode &before = _session->locations()->get_state();
2191 _session->locations()->clear ();
2192 XMLNode &after = _session->locations()->get_state();
2193 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2195 commit_reversible_command ();
2199 Editor::unhide_markers ()
2201 for (LocationMarkerMap::iterator i = location_markers.begin(); i != location_markers.end(); ++i) {
2202 Location *l = (*i).first;
2203 if (l->is_hidden() && l->is_mark()) {
2204 l->set_hidden(false, this);
2210 Editor::unhide_ranges ()
2212 for (LocationMarkerMap::iterator i = location_markers.begin(); i != location_markers.end(); ++i) {
2213 Location *l = (*i).first;
2214 if (l->is_hidden() && l->is_range_marker()) {
2215 l->set_hidden(false, this);
2220 /* INSERT/REPLACE */
2223 Editor::insert_region_list_selection (float times)
2225 RouteTimeAxisView *tv = 0;
2226 boost::shared_ptr<Playlist> playlist;
2228 if (clicked_routeview != 0) {
2229 tv = clicked_routeview;
2230 } else if (!selection->tracks.empty()) {
2231 if ((tv = dynamic_cast<RouteTimeAxisView*>(selection->tracks.front())) == 0) {
2234 } else if (entered_track != 0) {
2235 if ((tv = dynamic_cast<RouteTimeAxisView*>(entered_track)) == 0) {
2242 if ((playlist = tv->playlist()) == 0) {
2246 boost::shared_ptr<Region> region = _regions->get_single_selection ();
2251 begin_reversible_command (_("insert region"));
2252 playlist->clear_changes ();
2253 playlist->add_region ((RegionFactory::create (region, true)), get_preferred_edit_position(), times);
2254 if (Config->get_edit_mode() == Ripple)
2255 playlist->ripple (get_preferred_edit_position(), region->length() * times, boost::shared_ptr<Region>());
2257 _session->add_command(new StatefulDiffCommand (playlist));
2258 commit_reversible_command ();
2261 /* BUILT-IN EFFECTS */
2264 Editor::reverse_selection ()
2269 /* GAIN ENVELOPE EDITING */
2272 Editor::edit_envelope ()
2279 Editor::transition_to_rolling (bool fwd)
2285 if (_session->config.get_external_sync()) {
2286 switch (Config->get_sync_source()) {
2290 /* transport controlled by the master */
2295 if (_session->is_auditioning()) {
2296 _session->cancel_audition ();
2300 _session->request_transport_speed (fwd ? 1.0f : -1.0f);
2304 Editor::play_from_start ()
2306 _session->request_locate (_session->current_start_frame(), true);
2310 Editor::play_from_edit_point ()
2312 _session->request_locate (get_preferred_edit_position(), true);
2316 Editor::play_from_edit_point_and_return ()
2318 framepos_t start_frame;
2319 framepos_t return_frame;
2321 start_frame = get_preferred_edit_position (true);
2323 if (_session->transport_rolling()) {
2324 _session->request_locate (start_frame, false);
2328 /* don't reset the return frame if its already set */
2330 if ((return_frame = _session->requested_return_frame()) < 0) {
2331 return_frame = _session->audible_frame();
2334 if (start_frame >= 0) {
2335 _session->request_roll_at_and_return (start_frame, return_frame);
2340 Editor::play_selection ()
2342 if (selection->time.empty()) {
2346 _session->request_play_range (&selection->time, true);
2350 Editor::get_preroll ()
2352 return 1.0 /*Config->get_edit_preroll_seconds()*/ * _session->frame_rate();
2357 Editor::maybe_locate_with_edit_preroll ( framepos_t location )
2359 if ( _session->transport_rolling() || !ARDOUR_UI::config()->get_follow_edits() || _ignore_follow_edits )
2362 location -= get_preroll();
2364 //don't try to locate before the beginning of time
2368 //if follow_playhead is on, keep the playhead on the screen
2369 if ( _follow_playhead )
2370 if ( location < leftmost_frame )
2371 location = leftmost_frame;
2373 _session->request_locate( location );
2377 Editor::play_with_preroll ()
2379 if (selection->time.empty()) {
2382 framepos_t preroll = get_preroll();
2384 framepos_t start = 0;
2385 if (selection->time[clicked_selection].start > preroll)
2386 start = selection->time[clicked_selection].start - preroll;
2388 framepos_t end = selection->time[clicked_selection].end + preroll;
2390 AudioRange ar (start, end, 0);
2391 list<AudioRange> lar;
2394 _session->request_play_range (&lar, true);
2399 Editor::play_location (Location& location)
2401 if (location.start() <= location.end()) {
2405 _session->request_bounded_roll (location.start(), location.end());
2409 Editor::loop_location (Location& location)
2411 if (location.start() <= location.end()) {
2417 if ((tll = transport_loop_location()) != 0) {
2418 tll->set (location.start(), location.end());
2420 // enable looping, reposition and start rolling
2421 _session->request_locate (tll->start(), true);
2422 _session->request_play_loop (true);
2427 Editor::do_layer_operation (LayerOperation op)
2429 if (selection->regions.empty ()) {
2433 bool const multiple = selection->regions.size() > 1;
2437 begin_reversible_command (_("raise regions"));
2439 begin_reversible_command (_("raise region"));
2445 begin_reversible_command (_("raise regions to top"));
2447 begin_reversible_command (_("raise region to top"));
2453 begin_reversible_command (_("lower regions"));
2455 begin_reversible_command (_("lower region"));
2461 begin_reversible_command (_("lower regions to bottom"));
2463 begin_reversible_command (_("lower region"));
2468 set<boost::shared_ptr<Playlist> > playlists = selection->regions.playlists ();
2469 for (set<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
2470 (*i)->clear_owned_changes ();
2473 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
2474 boost::shared_ptr<Region> r = (*i)->region ();
2486 r->lower_to_bottom ();
2490 for (set<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
2491 vector<Command*> cmds;
2493 _session->add_commands (cmds);
2496 commit_reversible_command ();
2500 Editor::raise_region ()
2502 do_layer_operation (Raise);
2506 Editor::raise_region_to_top ()
2508 do_layer_operation (RaiseToTop);
2512 Editor::lower_region ()
2514 do_layer_operation (Lower);
2518 Editor::lower_region_to_bottom ()
2520 do_layer_operation (LowerToBottom);
2523 /** Show the region editor for the selected regions */
2525 Editor::show_region_properties ()
2527 selection->foreach_regionview (&RegionView::show_region_editor);
2530 /** Show the midi list editor for the selected MIDI regions */
2532 Editor::show_midi_list_editor ()
2534 selection->foreach_midi_regionview (&MidiRegionView::show_list_editor);
2538 Editor::rename_region ()
2540 RegionSelection rs = get_regions_from_selection_and_entered ();
2546 ArdourDialog d (*this, _("Rename Region"), true, false);
2548 Label label (_("New name:"));
2551 hbox.set_spacing (6);
2552 hbox.pack_start (label, false, false);
2553 hbox.pack_start (entry, true, true);
2555 d.get_vbox()->set_border_width (12);
2556 d.get_vbox()->pack_start (hbox, false, false);
2558 d.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
2559 d.add_button(Gtk::Stock::OK, Gtk::RESPONSE_OK);
2561 d.set_size_request (300, -1);
2563 entry.set_text (rs.front()->region()->name());
2564 entry.select_region (0, -1);
2566 entry.signal_activate().connect (sigc::bind (sigc::mem_fun (d, &Dialog::response), RESPONSE_OK));
2572 int const ret = d.run();
2576 if (ret != RESPONSE_OK) {
2580 std::string str = entry.get_text();
2581 strip_whitespace_edges (str);
2583 rs.front()->region()->set_name (str);
2584 _regions->redisplay ();
2589 Editor::audition_playlist_region_via_route (boost::shared_ptr<Region> region, Route& route)
2591 if (_session->is_auditioning()) {
2592 _session->cancel_audition ();
2595 // note: some potential for creativity here, because region doesn't
2596 // have to belong to the playlist that Route is handling
2598 // bool was_soloed = route.soloed();
2600 route.set_solo (true, this);
2602 _session->request_bounded_roll (region->position(), region->position() + region->length());
2604 /* XXX how to unset the solo state ? */
2607 /** Start an audition of the first selected region */
2609 Editor::play_edit_range ()
2611 framepos_t start, end;
2613 if (get_edit_op_range (start, end)) {
2614 _session->request_bounded_roll (start, end);
2619 Editor::play_selected_region ()
2621 framepos_t start = max_framepos;
2624 RegionSelection rs = get_regions_from_selection_and_entered ();
2630 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
2631 if ((*i)->region()->position() < start) {
2632 start = (*i)->region()->position();
2634 if ((*i)->region()->last_frame() + 1 > end) {
2635 end = (*i)->region()->last_frame() + 1;
2639 _session->request_bounded_roll (start, end);
2643 Editor::audition_playlist_region_standalone (boost::shared_ptr<Region> region)
2645 _session->audition_region (region);
2649 Editor::region_from_selection ()
2651 if (clicked_axisview == 0) {
2655 if (selection->time.empty()) {
2659 framepos_t start = selection->time[clicked_selection].start;
2660 framepos_t end = selection->time[clicked_selection].end;
2662 TrackViewList tracks = get_tracks_for_range_action ();
2664 framepos_t selection_cnt = end - start + 1;
2666 for (TrackSelection::iterator i = tracks.begin(); i != tracks.end(); ++i) {
2667 boost::shared_ptr<Region> current;
2668 boost::shared_ptr<Playlist> pl;
2669 framepos_t internal_start;
2672 if ((pl = (*i)->playlist()) == 0) {
2676 if ((current = pl->top_region_at (start)) == 0) {
2680 internal_start = start - current->position();
2681 RegionFactory::region_name (new_name, current->name(), true);
2685 plist.add (ARDOUR::Properties::start, current->start() + internal_start);
2686 plist.add (ARDOUR::Properties::length, selection_cnt);
2687 plist.add (ARDOUR::Properties::name, new_name);
2688 plist.add (ARDOUR::Properties::layer, 0);
2690 boost::shared_ptr<Region> region (RegionFactory::create (current, plist));
2695 Editor::create_region_from_selection (vector<boost::shared_ptr<Region> >& new_regions)
2697 if (selection->time.empty() || selection->tracks.empty()) {
2701 framepos_t start, end;
2702 if (clicked_selection) {
2703 start = selection->time[clicked_selection].start;
2704 end = selection->time[clicked_selection].end;
2706 start = selection->time.start();
2707 end = selection->time.end_frame();
2710 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
2711 sort_track_selection (ts);
2713 for (TrackSelection::iterator i = ts.begin(); i != ts.end(); ++i) {
2714 boost::shared_ptr<Region> current;
2715 boost::shared_ptr<Playlist> playlist;
2716 framepos_t internal_start;
2719 if ((playlist = (*i)->playlist()) == 0) {
2723 if ((current = playlist->top_region_at(start)) == 0) {
2727 internal_start = start - current->position();
2728 RegionFactory::region_name (new_name, current->name(), true);
2732 plist.add (ARDOUR::Properties::start, current->start() + internal_start);
2733 plist.add (ARDOUR::Properties::length, end - start + 1);
2734 plist.add (ARDOUR::Properties::name, new_name);
2736 new_regions.push_back (RegionFactory::create (current, plist));
2741 Editor::split_multichannel_region ()
2743 RegionSelection rs = get_regions_from_selection_and_entered ();
2749 vector< boost::shared_ptr<Region> > v;
2751 for (list<RegionView*>::iterator x = rs.begin(); x != rs.end(); ++x) {
2752 (*x)->region()->separate_by_channel (*_session, v);
2757 Editor::new_region_from_selection ()
2759 region_from_selection ();
2760 cancel_selection ();
2764 add_if_covered (RegionView* rv, const AudioRange* ar, RegionSelection* rs)
2766 switch (rv->region()->coverage (ar->start, ar->end - 1)) {
2767 // n.b. -1 because AudioRange::end is one past the end, but coverage expects inclusive ranges
2768 case Evoral::OverlapNone:
2776 * - selected tracks, or if there are none...
2777 * - tracks containing selected regions, or if there are none...
2782 Editor::get_tracks_for_range_action () const
2786 if (selection->tracks.empty()) {
2788 /* use tracks with selected regions */
2790 RegionSelection rs = selection->regions;
2792 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
2793 TimeAxisView* tv = &(*i)->get_time_axis_view();
2795 if (!t.contains (tv)) {
2801 /* no regions and no tracks: use all tracks */
2807 t = selection->tracks;
2810 return t.filter_to_unique_playlists();
2814 Editor::separate_regions_between (const TimeSelection& ts)
2816 bool in_command = false;
2817 boost::shared_ptr<Playlist> playlist;
2818 RegionSelection new_selection;
2820 TrackViewList tmptracks = get_tracks_for_range_action ();
2821 sort_track_selection (tmptracks);
2823 for (TrackSelection::iterator i = tmptracks.begin(); i != tmptracks.end(); ++i) {
2825 RouteTimeAxisView* rtv;
2827 if ((rtv = dynamic_cast<RouteTimeAxisView*> ((*i))) != 0) {
2829 if (rtv->is_track()) {
2831 /* no edits to destructive tracks */
2833 if (rtv->track()->destructive()) {
2837 if ((playlist = rtv->playlist()) != 0) {
2839 playlist->clear_changes ();
2841 /* XXX need to consider musical time selections here at some point */
2843 double speed = rtv->track()->speed();
2846 for (list<AudioRange>::const_iterator t = ts.begin(); t != ts.end(); ++t) {
2848 sigc::connection c = rtv->view()->RegionViewAdded.connect (
2849 sigc::mem_fun(*this, &Editor::collect_new_region_view));
2851 latest_regionviews.clear ();
2853 playlist->partition ((framepos_t)((*t).start * speed),
2854 (framepos_t)((*t).end * speed), false);
2858 if (!latest_regionviews.empty()) {
2860 rtv->view()->foreach_regionview (sigc::bind (
2861 sigc::ptr_fun (add_if_covered),
2862 &(*t), &new_selection));
2865 begin_reversible_command (_("separate"));
2869 /* pick up changes to existing regions */
2871 vector<Command*> cmds;
2872 playlist->rdiff (cmds);
2873 _session->add_commands (cmds);
2875 /* pick up changes to the playlist itself (adds/removes)
2878 _session->add_command(new StatefulDiffCommand (playlist));
2887 // selection->set (new_selection);
2889 commit_reversible_command ();
2893 struct PlaylistState {
2894 boost::shared_ptr<Playlist> playlist;
2898 /** Take tracks from get_tracks_for_range_action and cut any regions
2899 * on those tracks so that the tracks are empty over the time
2903 Editor::separate_region_from_selection ()
2905 /* preferentially use *all* ranges in the time selection if we're in range mode
2906 to allow discontiguous operation, since get_edit_op_range() currently
2907 returns a single range.
2910 if (!selection->time.empty()) {
2912 separate_regions_between (selection->time);
2919 if (get_edit_op_range (start, end)) {
2921 AudioRange ar (start, end, 1);
2925 separate_regions_between (ts);
2931 Editor::separate_region_from_punch ()
2933 Location* loc = _session->locations()->auto_punch_location();
2935 separate_regions_using_location (*loc);
2940 Editor::separate_region_from_loop ()
2942 Location* loc = _session->locations()->auto_loop_location();
2944 separate_regions_using_location (*loc);
2949 Editor::separate_regions_using_location (Location& loc)
2951 if (loc.is_mark()) {
2955 AudioRange ar (loc.start(), loc.end(), 1);
2960 separate_regions_between (ts);
2963 /** Separate regions under the selected region */
2965 Editor::separate_under_selected_regions ()
2967 vector<PlaylistState> playlists;
2971 rs = get_regions_from_selection_and_entered();
2973 if (!_session || rs.empty()) {
2977 begin_reversible_command (_("separate region under"));
2979 list<boost::shared_ptr<Region> > regions_to_remove;
2981 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
2982 // we can't just remove the region(s) in this loop because
2983 // this removes them from the RegionSelection, and they thus
2984 // disappear from underneath the iterator, and the ++i above
2985 // SEGVs in a puzzling fashion.
2987 // so, first iterate over the regions to be removed from rs and
2988 // add them to the regions_to_remove list, and then
2989 // iterate over the list to actually remove them.
2991 regions_to_remove.push_back ((*i)->region());
2994 for (list<boost::shared_ptr<Region> >::iterator rl = regions_to_remove.begin(); rl != regions_to_remove.end(); ++rl) {
2996 boost::shared_ptr<Playlist> playlist = (*rl)->playlist();
2999 // is this check necessary?
3003 vector<PlaylistState>::iterator i;
3005 //only take state if this is a new playlist.
3006 for (i = playlists.begin(); i != playlists.end(); ++i) {
3007 if ((*i).playlist == playlist) {
3012 if (i == playlists.end()) {
3014 PlaylistState before;
3015 before.playlist = playlist;
3016 before.before = &playlist->get_state();
3018 playlist->freeze ();
3019 playlists.push_back(before);
3022 //Partition on the region bounds
3023 playlist->partition ((*rl)->first_frame() - 1, (*rl)->last_frame() + 1, true);
3025 //Re-add region that was just removed due to the partition operation
3026 playlist->add_region( (*rl), (*rl)->first_frame() );
3029 vector<PlaylistState>::iterator pl;
3031 for (pl = playlists.begin(); pl != playlists.end(); ++pl) {
3032 (*pl).playlist->thaw ();
3033 _session->add_command(new MementoCommand<Playlist>(*(*pl).playlist, (*pl).before, &(*pl).playlist->get_state()));
3036 commit_reversible_command ();
3040 Editor::crop_region_to_selection ()
3042 if (!selection->time.empty()) {
3044 crop_region_to (selection->time.start(), selection->time.end_frame());
3051 if (get_edit_op_range (start, end)) {
3052 crop_region_to (start, end);
3059 Editor::crop_region_to (framepos_t start, framepos_t end)
3061 vector<boost::shared_ptr<Playlist> > playlists;
3062 boost::shared_ptr<Playlist> playlist;
3065 if (selection->tracks.empty()) {
3066 ts = track_views.filter_to_unique_playlists();
3068 ts = selection->tracks.filter_to_unique_playlists ();
3071 sort_track_selection (ts);
3073 for (TrackSelection::iterator i = ts.begin(); i != ts.end(); ++i) {
3075 RouteTimeAxisView* rtv;
3077 if ((rtv = dynamic_cast<RouteTimeAxisView*> ((*i))) != 0) {
3079 boost::shared_ptr<Track> t = rtv->track();
3081 if (t != 0 && ! t->destructive()) {
3083 if ((playlist = rtv->playlist()) != 0) {
3084 playlists.push_back (playlist);
3090 if (playlists.empty()) {
3094 framepos_t the_start;
3098 begin_reversible_command (_("trim to selection"));
3100 for (vector<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
3102 boost::shared_ptr<Region> region;
3106 if ((region = (*i)->top_region_at(the_start)) == 0) {
3110 /* now adjust lengths to that we do the right thing
3111 if the selection extends beyond the region
3114 the_start = max (the_start, (framepos_t) region->position());
3115 if (max_framepos - the_start < region->length()) {
3116 the_end = the_start + region->length() - 1;
3118 the_end = max_framepos;
3120 the_end = min (end, the_end);
3121 cnt = the_end - the_start + 1;
3123 region->clear_changes ();
3124 region->trim_to (the_start, cnt);
3125 _session->add_command (new StatefulDiffCommand (region));
3128 commit_reversible_command ();
3132 Editor::region_fill_track ()
3134 RegionSelection rs = get_regions_from_selection_and_entered ();
3136 if (!_session || rs.empty()) {
3140 framepos_t const end = _session->current_end_frame ();
3142 begin_reversible_command (Operations::region_fill);
3144 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3146 boost::shared_ptr<Region> region ((*i)->region());
3148 boost::shared_ptr<Playlist> pl = region->playlist();
3150 if (end <= region->last_frame()) {
3154 double times = (double) (end - region->last_frame()) / (double) region->length();
3160 pl->clear_changes ();
3161 pl->add_region (RegionFactory::create (region, true), region->last_frame(), times);
3162 _session->add_command (new StatefulDiffCommand (pl));
3165 commit_reversible_command ();
3169 Editor::region_fill_selection ()
3171 if (clicked_routeview == 0 || !clicked_routeview->is_audio_track()) {
3175 if (selection->time.empty()) {
3179 boost::shared_ptr<Region> region = _regions->get_single_selection ();
3184 framepos_t start = selection->time[clicked_selection].start;
3185 framepos_t end = selection->time[clicked_selection].end;
3187 boost::shared_ptr<Playlist> playlist;
3189 if (selection->tracks.empty()) {
3193 framepos_t selection_length = end - start;
3194 float times = (float)selection_length / region->length();
3196 begin_reversible_command (Operations::fill_selection);
3198 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
3200 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
3202 if ((playlist = (*i)->playlist()) == 0) {
3206 playlist->clear_changes ();
3207 playlist->add_region (RegionFactory::create (region, true), start, times);
3208 _session->add_command (new StatefulDiffCommand (playlist));
3211 commit_reversible_command ();
3215 Editor::set_region_sync_position ()
3217 set_sync_point (get_preferred_edit_position (), get_regions_from_selection_and_edit_point ());
3221 Editor::set_sync_point (framepos_t where, const RegionSelection& rs)
3223 bool in_command = false;
3225 for (RegionSelection::const_iterator r = rs.begin(); r != rs.end(); ++r) {
3227 if (!(*r)->region()->covers (where)) {
3231 boost::shared_ptr<Region> region ((*r)->region());
3234 begin_reversible_command (_("set sync point"));
3238 region->clear_changes ();
3239 region->set_sync_position (where);
3240 _session->add_command(new StatefulDiffCommand (region));
3244 commit_reversible_command ();
3248 /** Remove the sync positions of the selection */
3250 Editor::remove_region_sync ()
3252 RegionSelection rs = get_regions_from_selection_and_entered ();
3258 begin_reversible_command (_("remove region sync"));
3260 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3262 (*i)->region()->clear_changes ();
3263 (*i)->region()->clear_sync_position ();
3264 _session->add_command(new StatefulDiffCommand ((*i)->region()));
3267 commit_reversible_command ();
3271 Editor::naturalize_region ()
3273 RegionSelection rs = get_regions_from_selection_and_entered ();
3279 if (rs.size() > 1) {
3280 begin_reversible_command (_("move regions to original position"));
3282 begin_reversible_command (_("move region to original position"));
3285 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3286 (*i)->region()->clear_changes ();
3287 (*i)->region()->move_to_natural_position ();
3288 _session->add_command (new StatefulDiffCommand ((*i)->region()));
3291 commit_reversible_command ();
3295 Editor::align_regions (RegionPoint what)
3297 RegionSelection const rs = get_regions_from_selection_and_edit_point ();
3303 begin_reversible_command (_("align selection"));
3305 framepos_t const position = get_preferred_edit_position ();
3307 for (RegionSelection::const_iterator i = rs.begin(); i != rs.end(); ++i) {
3308 align_region_internal ((*i)->region(), what, position);
3311 commit_reversible_command ();
3314 struct RegionSortByTime {
3315 bool operator() (const RegionView* a, const RegionView* b) {
3316 return a->region()->position() < b->region()->position();
3321 Editor::align_regions_relative (RegionPoint point)
3323 RegionSelection const rs = get_regions_from_selection_and_edit_point ();
3329 framepos_t const position = get_preferred_edit_position ();
3331 framepos_t distance = 0;
3335 list<RegionView*> sorted;
3336 rs.by_position (sorted);
3338 boost::shared_ptr<Region> r ((*sorted.begin())->region());
3343 if (position > r->position()) {
3344 distance = position - r->position();
3346 distance = r->position() - position;
3352 if (position > r->last_frame()) {
3353 distance = position - r->last_frame();
3354 pos = r->position() + distance;
3356 distance = r->last_frame() - position;
3357 pos = r->position() - distance;
3363 pos = r->adjust_to_sync (position);
3364 if (pos > r->position()) {
3365 distance = pos - r->position();
3367 distance = r->position() - pos;
3373 if (pos == r->position()) {
3377 begin_reversible_command (_("align selection (relative)"));
3379 /* move first one specially */
3381 r->clear_changes ();
3382 r->set_position (pos);
3383 _session->add_command(new StatefulDiffCommand (r));
3385 /* move rest by the same amount */
3389 for (list<RegionView*>::iterator i = sorted.begin(); i != sorted.end(); ++i) {
3391 boost::shared_ptr<Region> region ((*i)->region());
3393 region->clear_changes ();
3396 region->set_position (region->position() + distance);
3398 region->set_position (region->position() - distance);
3401 _session->add_command(new StatefulDiffCommand (region));
3405 commit_reversible_command ();
3409 Editor::align_region (boost::shared_ptr<Region> region, RegionPoint point, framepos_t position)
3411 begin_reversible_command (_("align region"));
3412 align_region_internal (region, point, position);
3413 commit_reversible_command ();
3417 Editor::align_region_internal (boost::shared_ptr<Region> region, RegionPoint point, framepos_t position)
3419 region->clear_changes ();
3423 region->set_position (region->adjust_to_sync (position));
3427 if (position > region->length()) {
3428 region->set_position (position - region->length());
3433 region->set_position (position);
3437 _session->add_command(new StatefulDiffCommand (region));
3441 Editor::trim_region_front ()
3447 Editor::trim_region_back ()
3449 trim_region (false);
3453 Editor::trim_region (bool front)
3455 framepos_t where = get_preferred_edit_position();
3456 RegionSelection rs = get_regions_from_selection_and_edit_point ();
3462 begin_reversible_command (front ? _("trim front") : _("trim back"));
3464 for (list<RegionView*>::const_iterator i = rs.by_layer().begin(); i != rs.by_layer().end(); ++i) {
3465 if (!(*i)->region()->locked()) {
3467 (*i)->region()->clear_changes ();
3470 (*i)->region()->trim_front (where);
3471 maybe_locate_with_edit_preroll ( where );
3473 (*i)->region()->trim_end (where);
3474 maybe_locate_with_edit_preroll ( where );
3477 _session->add_command (new StatefulDiffCommand ((*i)->region()));
3481 commit_reversible_command ();
3484 /** Trim the end of the selected regions to the position of the edit cursor */
3486 Editor::trim_region_to_loop ()
3488 Location* loc = _session->locations()->auto_loop_location();
3492 trim_region_to_location (*loc, _("trim to loop"));
3496 Editor::trim_region_to_punch ()
3498 Location* loc = _session->locations()->auto_punch_location();
3502 trim_region_to_location (*loc, _("trim to punch"));
3506 Editor::trim_region_to_location (const Location& loc, const char* str)
3508 RegionSelection rs = get_regions_from_selection_and_entered ();
3510 begin_reversible_command (str);
3512 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
3513 RegionView* rv = (*x);
3515 /* require region to span proposed trim */
3516 switch (rv->region()->coverage (loc.start(), loc.end())) {
3517 case Evoral::OverlapInternal:
3523 RouteTimeAxisView* tav = dynamic_cast<RouteTimeAxisView*> (&rv->get_time_axis_view());
3532 if (tav->track() != 0) {
3533 speed = tav->track()->speed();
3536 start = session_frame_to_track_frame (loc.start(), speed);
3537 end = session_frame_to_track_frame (loc.end(), speed);
3539 rv->region()->clear_changes ();
3540 rv->region()->trim_to (start, (end - start));
3541 _session->add_command(new StatefulDiffCommand (rv->region()));
3544 commit_reversible_command ();
3548 Editor::trim_region_to_previous_region_end ()
3550 return trim_to_region(false);
3554 Editor::trim_region_to_next_region_start ()
3556 return trim_to_region(true);
3560 Editor::trim_to_region(bool forward)
3562 RegionSelection rs = get_regions_from_selection_and_entered ();
3564 begin_reversible_command (_("trim to region"));
3566 boost::shared_ptr<Region> next_region;
3568 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
3570 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*x);
3576 AudioTimeAxisView* atav = dynamic_cast<AudioTimeAxisView*> (&arv->get_time_axis_view());
3584 if (atav->track() != 0) {
3585 speed = atav->track()->speed();
3589 boost::shared_ptr<Region> region = arv->region();
3590 boost::shared_ptr<Playlist> playlist (region->playlist());
3592 region->clear_changes ();
3596 next_region = playlist->find_next_region (region->first_frame(), Start, 1);
3602 region->trim_end((framepos_t) ( (next_region->first_frame() - 1) * speed));
3603 arv->region_changed (PropertyChange (ARDOUR::Properties::length));
3607 next_region = playlist->find_next_region (region->first_frame(), Start, 0);
3613 region->trim_front((framepos_t) ((next_region->last_frame() + 1) * speed));
3615 arv->region_changed (ARDOUR::bounds_change);
3618 _session->add_command(new StatefulDiffCommand (region));
3621 commit_reversible_command ();
3625 Editor::unfreeze_route ()
3627 if (clicked_routeview == 0 || !clicked_routeview->is_track()) {
3631 clicked_routeview->track()->unfreeze ();
3635 Editor::_freeze_thread (void* arg)
3637 return static_cast<Editor*>(arg)->freeze_thread ();
3641 Editor::freeze_thread ()
3643 /* create event pool because we may need to talk to the session */
3644 SessionEvent::create_per_thread_pool ("freeze events", 64);
3645 /* create per-thread buffers for process() tree to use */
3646 clicked_routeview->audio_track()->freeze_me (*current_interthread_info);
3647 current_interthread_info->done = true;
3652 Editor::freeze_route ()
3658 /* stop transport before we start. this is important */
3660 _session->request_transport_speed (0.0);
3662 /* wait for just a little while, because the above call is asynchronous */
3664 Glib::usleep (250000);
3666 if (clicked_routeview == 0 || !clicked_routeview->is_audio_track()) {
3670 if (!clicked_routeview->track()->bounceable (clicked_routeview->track()->main_outs(), true)) {
3672 _("This track/bus cannot be frozen because the signal adds or loses channels before reaching the outputs.\n"
3673 "This is typically caused by plugins that generate stereo output from mono input or vice versa.")
3675 d.set_title (_("Cannot freeze"));
3680 if (clicked_routeview->track()->has_external_redirects()) {
3681 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"
3682 "Freezing will only process the signal as far as the first send/insert/return."),
3683 clicked_routeview->track()->name()), true, MESSAGE_INFO, BUTTONS_NONE, true);
3685 d.add_button (_("Freeze anyway"), Gtk::RESPONSE_OK);
3686 d.add_button (_("Don't freeze"), Gtk::RESPONSE_CANCEL);
3687 d.set_title (_("Freeze Limits"));
3689 int response = d.run ();
3692 case Gtk::RESPONSE_CANCEL:
3699 InterThreadInfo itt;
3700 current_interthread_info = &itt;
3702 InterthreadProgressWindow ipw (current_interthread_info, _("Freeze"), _("Cancel Freeze"));
3704 pthread_create_and_store (X_("freezer"), &itt.thread, _freeze_thread, this);
3706 CursorContext::Handle cursor_ctx = CursorContext::create(*this, _cursors->wait);
3708 while (!itt.done && !itt.cancel) {
3709 gtk_main_iteration ();
3712 current_interthread_info = 0;
3716 Editor::bounce_range_selection (bool replace, bool enable_processing)
3718 if (selection->time.empty()) {
3722 TrackSelection views = selection->tracks;
3724 for (TrackViewList::iterator i = views.begin(); i != views.end(); ++i) {
3726 if (enable_processing) {
3728 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*i);
3730 if (rtv && rtv->track() && replace && enable_processing && !rtv->track()->bounceable (rtv->track()->main_outs(), false)) {
3732 _("You can't perform this operation because the processing of the signal "
3733 "will cause one or more of the tracks to end up with a region with more channels than this track has inputs.\n\n"
3734 "You can do this without processing, which is a different operation.")
3736 d.set_title (_("Cannot bounce"));
3743 framepos_t start = selection->time[clicked_selection].start;
3744 framepos_t end = selection->time[clicked_selection].end;
3745 framepos_t cnt = end - start + 1;
3747 begin_reversible_command (_("bounce range"));
3749 for (TrackViewList::iterator i = views.begin(); i != views.end(); ++i) {
3751 RouteTimeAxisView* rtv;
3753 if ((rtv = dynamic_cast<RouteTimeAxisView*> (*i)) == 0) {
3757 boost::shared_ptr<Playlist> playlist;
3759 if ((playlist = rtv->playlist()) == 0) {
3763 InterThreadInfo itt;
3765 playlist->clear_changes ();
3766 playlist->clear_owned_changes ();
3768 boost::shared_ptr<Region> r;
3770 if (enable_processing) {
3771 r = rtv->track()->bounce_range (start, start+cnt, itt, rtv->track()->main_outs(), false);
3773 r = rtv->track()->bounce_range (start, start+cnt, itt, boost::shared_ptr<Processor>(), false);
3781 list<AudioRange> ranges;
3782 ranges.push_back (AudioRange (start, start+cnt, 0));
3783 playlist->cut (ranges); // discard result
3784 playlist->add_region (r, start);
3787 vector<Command*> cmds;
3788 playlist->rdiff (cmds);
3789 _session->add_commands (cmds);
3791 _session->add_command (new StatefulDiffCommand (playlist));
3794 commit_reversible_command ();
3797 /** Delete selected regions, automation points or a time range */
3801 //special case: if the user is pointing in the editor/mixer strip, they may be trying to delete a plugin.
3802 //we need this because the editor-mixer strip is in the editor window, so it doesn't get the bindings from the mix window
3803 bool deleted = false;
3804 if ( current_mixer_strip && current_mixer_strip == MixerStrip::entered_mixer_strip() )
3805 deleted = current_mixer_strip->delete_processors ();
3811 /** Cut selected regions, automation points or a time range */
3818 /** Copy selected regions, automation points or a time range */
3826 /** @return true if a Cut, Copy or Clear is possible */
3828 Editor::can_cut_copy () const
3830 if (!selection->time.empty() || !selection->regions.empty() || !selection->points.empty())
3837 /** Cut, copy or clear selected regions, automation points or a time range.
3838 * @param op Operation (Delete, Cut, Copy or Clear)
3841 Editor::cut_copy (CutCopyOp op)
3843 /* only cancel selection if cut/copy is successful.*/
3849 opname = _("delete");
3858 opname = _("clear");
3862 /* if we're deleting something, and the mouse is still pressed,
3863 the thing we started a drag for will be gone when we release
3864 the mouse button(s). avoid this. see part 2 at the end of
3868 if (op == Delete || op == Cut || op == Clear) {
3869 if (_drags->active ()) {
3874 if ( op != Delete ) //"Delete" doesn't change copy/paste buf
3875 cut_buffer->clear ();
3877 if (entered_marker) {
3879 /* cut/delete op while pointing at a marker */
3882 Location* loc = find_location_from_marker (entered_marker, ignored);
3884 if (_session && loc) {
3885 Glib::signal_idle().connect (sigc::bind (sigc::mem_fun(*this, &Editor::really_remove_marker), loc));
3892 switch (mouse_mode) {
3895 begin_reversible_command (opname + ' ' + X_("MIDI"));
3897 commit_reversible_command ();
3903 bool did_edit = false;
3905 if (!selection->regions.empty() || !selection->points.empty()) {
3906 begin_reversible_command (opname + ' ' + _("objects"));
3909 if (!selection->regions.empty()) {
3910 cut_copy_regions (op, selection->regions);
3912 if (op == Cut || op == Delete) {
3913 selection->clear_regions ();
3917 if (!selection->points.empty()) {
3918 cut_copy_points (op);
3920 if (op == Cut || op == Delete) {
3921 selection->clear_points ();
3924 } else if (selection->time.empty()) {
3925 framepos_t start, end;
3926 /* no time selection, see if we can get an edit range
3929 if (get_edit_op_range (start, end)) {
3930 selection->set (start, end);
3932 } else if (!selection->time.empty()) {
3933 begin_reversible_command (opname + ' ' + _("range"));
3936 cut_copy_ranges (op);
3938 if (op == Cut || op == Delete) {
3939 selection->clear_time ();
3944 /* reset repeated paste state */
3947 commit_reversible_command ();
3950 if (op == Delete || op == Cut || op == Clear) {
3955 struct AutomationRecord {
3956 AutomationRecord () : state (0) , line(NULL) {}
3957 AutomationRecord (XMLNode* s, const AutomationLine* l) : state (s) , line (l) {}
3959 XMLNode* state; ///< state before any operation
3960 const AutomationLine* line; ///< line this came from
3961 boost::shared_ptr<Evoral::ControlList> copy; ///< copied events for the cut buffer
3964 /** Cut, copy or clear selected automation points.
3965 * @param op Operation (Cut, Copy or Clear)
3968 Editor::cut_copy_points (Editing::CutCopyOp op, Evoral::MusicalTime earliest, bool midi)
3970 if (selection->points.empty ()) {
3974 /* XXX: not ideal, as there may be more than one track involved in the point selection */
3975 _last_cut_copy_source_track = &selection->points.front()->line().trackview;
3977 /* Keep a record of the AutomationLists that we end up using in this operation */
3978 typedef std::map<boost::shared_ptr<AutomationList>, AutomationRecord> Lists;
3981 /* Go through all selected points, making an AutomationRecord for each distinct AutomationList */
3982 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
3983 const AutomationLine& line = (*i)->line();
3984 const boost::shared_ptr<AutomationList> al = line.the_list();
3985 if (lists.find (al) == lists.end ()) {
3986 /* We haven't seen this list yet, so make a record for it. This includes
3987 taking a copy of its current state, in case this is needed for undo later.
3989 lists[al] = AutomationRecord (&al->get_state (), &line);
3993 if (op == Cut || op == Copy) {
3994 /* This operation will involve putting things in the cut buffer, so create an empty
3995 ControlList for each of our source lists to put the cut buffer data in.
3997 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
3998 i->second.copy = i->first->create (i->first->parameter (), i->first->descriptor());
4001 /* Add all selected points to the relevant copy ControlLists */
4002 framepos_t start = std::numeric_limits<framepos_t>::max();
4003 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
4004 boost::shared_ptr<AutomationList> al = (*i)->line().the_list();
4005 AutomationList::const_iterator j = (*i)->model();
4007 lists[al].copy->fast_simple_add ((*j)->when, (*j)->value);
4009 /* Update earliest MIDI start time in beats */
4010 earliest = std::min(earliest, Evoral::MusicalTime((*j)->when));
4012 /* Update earliest session start time in frames */
4013 start = std::min(start, (*i)->line().session_position(j));
4017 /* Snap start time backwards, so copy/paste is snap aligned. */
4019 if (earliest == Evoral::MusicalTime::max()) {
4020 earliest = Evoral::MusicalTime(); // Weird... don't offset
4022 earliest.round_down_to_beat();
4024 if (start == std::numeric_limits<double>::max()) {
4025 start = 0; // Weird... don't offset
4027 snap_to(start, RoundDownMaybe);
4030 const double line_offset = midi ? earliest.to_double() : start;
4031 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
4032 /* Correct this copy list so that it is relative to the earliest
4033 start time, so relative ordering between points is preserved
4034 when copying from several lists and the paste starts at the
4035 earliest copied piece of data. */
4036 for (AutomationList::iterator j = i->second.copy->begin(); j != i->second.copy->end(); ++j) {
4037 (*j)->when -= line_offset;
4040 /* And add it to the cut buffer */
4041 cut_buffer->add (i->second.copy);
4045 if (op == Delete || op == Cut) {
4046 /* This operation needs to remove things from the main AutomationList, so do that now */
4048 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
4049 i->first->freeze ();
4052 /* Remove each selected point from its AutomationList */
4053 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
4054 boost::shared_ptr<AutomationList> al = (*i)->line().the_list();
4055 al->erase ((*i)->model ());
4058 /* Thaw the lists and add undo records for them */
4059 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
4060 boost::shared_ptr<AutomationList> al = i->first;
4062 _session->add_command (new MementoCommand<AutomationList> (*al.get(), i->second.state, &(al->get_state ())));
4067 /** Cut, copy or clear selected automation points.
4068 * @param op Operation (Cut, Copy or Clear)
4071 Editor::cut_copy_midi (CutCopyOp op)
4073 Evoral::MusicalTime earliest = Evoral::MusicalTime::max();
4074 for (MidiRegionSelection::iterator i = selection->midi_regions.begin(); i != selection->midi_regions.end(); ++i) {
4075 MidiRegionView* mrv = dynamic_cast<MidiRegionView*>(*i);
4077 if (!mrv->selection().empty()) {
4078 earliest = std::min(earliest, (*mrv->selection().begin())->note()->time());
4080 mrv->cut_copy_clear (op);
4082 /* XXX: not ideal, as there may be more than one track involved in the selection */
4083 _last_cut_copy_source_track = &mrv->get_time_axis_view();
4087 if (!selection->points.empty()) {
4088 cut_copy_points (op, earliest, true);
4089 if (op == Cut || op == Delete) {
4090 selection->clear_points ();
4095 struct lt_playlist {
4096 bool operator () (const PlaylistState& a, const PlaylistState& b) {
4097 return a.playlist < b.playlist;
4101 struct PlaylistMapping {
4103 boost::shared_ptr<Playlist> pl;
4105 PlaylistMapping (TimeAxisView* tvp) : tv (tvp) {}
4108 /** Remove `clicked_regionview' */
4110 Editor::remove_clicked_region ()
4112 if (clicked_routeview == 0 || clicked_regionview == 0) {
4116 begin_reversible_command (_("remove region"));
4118 boost::shared_ptr<Playlist> playlist = clicked_routeview->playlist();
4120 playlist->clear_changes ();
4121 playlist->clear_owned_changes ();
4122 playlist->remove_region (clicked_regionview->region());
4123 if (Config->get_edit_mode() == Ripple)
4124 playlist->ripple (clicked_regionview->region()->position(), -clicked_regionview->region()->length(), boost::shared_ptr<Region>());
4126 /* We might have removed regions, which alters other regions' layering_index,
4127 so we need to do a recursive diff here.
4129 vector<Command*> cmds;
4130 playlist->rdiff (cmds);
4131 _session->add_commands (cmds);
4133 _session->add_command(new StatefulDiffCommand (playlist));
4134 commit_reversible_command ();
4138 /** Remove the selected regions */
4140 Editor::remove_selected_regions ()
4142 RegionSelection rs = get_regions_from_selection_and_entered ();
4144 if (!_session || rs.empty()) {
4148 begin_reversible_command (_("remove region"));
4150 list<boost::shared_ptr<Region> > regions_to_remove;
4152 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
4153 // we can't just remove the region(s) in this loop because
4154 // this removes them from the RegionSelection, and they thus
4155 // disappear from underneath the iterator, and the ++i above
4156 // SEGVs in a puzzling fashion.
4158 // so, first iterate over the regions to be removed from rs and
4159 // add them to the regions_to_remove list, and then
4160 // iterate over the list to actually remove them.
4162 regions_to_remove.push_back ((*i)->region());
4165 vector<boost::shared_ptr<Playlist> > playlists;
4167 for (list<boost::shared_ptr<Region> >::iterator rl = regions_to_remove.begin(); rl != regions_to_remove.end(); ++rl) {
4169 boost::shared_ptr<Playlist> playlist = (*rl)->playlist();
4172 // is this check necessary?
4176 /* get_regions_from_selection_and_entered() guarantees that
4177 the playlists involved are unique, so there is no need
4181 playlists.push_back (playlist);
4183 playlist->clear_changes ();
4184 playlist->clear_owned_changes ();
4185 playlist->freeze ();
4186 playlist->remove_region (*rl);
4187 if (Config->get_edit_mode() == Ripple)
4188 playlist->ripple ((*rl)->position(), -(*rl)->length(), boost::shared_ptr<Region>());
4192 vector<boost::shared_ptr<Playlist> >::iterator pl;
4194 for (pl = playlists.begin(); pl != playlists.end(); ++pl) {
4197 /* We might have removed regions, which alters other regions' layering_index,
4198 so we need to do a recursive diff here.
4200 vector<Command*> cmds;
4201 (*pl)->rdiff (cmds);
4202 _session->add_commands (cmds);
4204 _session->add_command(new StatefulDiffCommand (*pl));
4207 commit_reversible_command ();
4210 /** Cut, copy or clear selected regions.
4211 * @param op Operation (Cut, Copy or Clear)
4214 Editor::cut_copy_regions (CutCopyOp op, RegionSelection& rs)
4216 /* we can't use a std::map here because the ordering is important, and we can't trivially sort
4217 a map when we want ordered access to both elements. i think.
4220 vector<PlaylistMapping> pmap;
4222 framepos_t first_position = max_framepos;
4224 typedef set<boost::shared_ptr<Playlist> > FreezeList;
4225 FreezeList freezelist;
4227 /* get ordering correct before we cut/copy */
4229 rs.sort_by_position_and_track ();
4231 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
4233 first_position = min ((framepos_t) (*x)->region()->position(), first_position);
4235 if (op == Cut || op == Clear || op == Delete) {
4236 boost::shared_ptr<Playlist> pl = (*x)->region()->playlist();
4239 FreezeList::iterator fl;
4241 // only take state if this is a new playlist.
4242 for (fl = freezelist.begin(); fl != freezelist.end(); ++fl) {
4248 if (fl == freezelist.end()) {
4249 pl->clear_changes();
4250 pl->clear_owned_changes ();
4252 freezelist.insert (pl);
4257 TimeAxisView* tv = &(*x)->get_time_axis_view();
4258 vector<PlaylistMapping>::iterator z;
4260 for (z = pmap.begin(); z != pmap.end(); ++z) {
4261 if ((*z).tv == tv) {
4266 if (z == pmap.end()) {
4267 pmap.push_back (PlaylistMapping (tv));
4271 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ) {
4273 boost::shared_ptr<Playlist> pl = (*x)->region()->playlist();
4276 /* region not yet associated with a playlist (e.g. unfinished
4283 TimeAxisView& tv = (*x)->get_time_axis_view();
4284 boost::shared_ptr<Playlist> npl;
4285 RegionSelection::iterator tmp;
4292 vector<PlaylistMapping>::iterator z;
4294 for (z = pmap.begin(); z != pmap.end(); ++z) {
4295 if ((*z).tv == &tv) {
4300 assert (z != pmap.end());
4303 npl = PlaylistFactory::create (pl->data_type(), *_session, "cutlist", true);
4311 boost::shared_ptr<Region> r = (*x)->region();
4312 boost::shared_ptr<Region> _xx;
4318 pl->remove_region (r);
4319 if (Config->get_edit_mode() == Ripple)
4320 pl->ripple (r->position(), -r->length(), boost::shared_ptr<Region>());
4324 _xx = RegionFactory::create (r);
4325 npl->add_region (_xx, r->position() - first_position);
4326 pl->remove_region (r);
4327 if (Config->get_edit_mode() == Ripple)
4328 pl->ripple (r->position(), -r->length(), boost::shared_ptr<Region>());
4332 /* copy region before adding, so we're not putting same object into two different playlists */
4333 npl->add_region (RegionFactory::create (r), r->position() - first_position);
4337 pl->remove_region (r);
4338 if (Config->get_edit_mode() == Ripple)
4339 pl->ripple (r->position(), -r->length(), boost::shared_ptr<Region>());
4348 list<boost::shared_ptr<Playlist> > foo;
4350 /* the pmap is in the same order as the tracks in which selected regions occured */
4352 for (vector<PlaylistMapping>::iterator i = pmap.begin(); i != pmap.end(); ++i) {
4355 foo.push_back ((*i).pl);
4360 cut_buffer->set (foo);
4364 _last_cut_copy_source_track = 0;
4366 _last_cut_copy_source_track = pmap.front().tv;
4370 for (FreezeList::iterator pl = freezelist.begin(); pl != freezelist.end(); ++pl) {
4373 /* We might have removed regions, which alters other regions' layering_index,
4374 so we need to do a recursive diff here.
4376 vector<Command*> cmds;
4377 (*pl)->rdiff (cmds);
4378 _session->add_commands (cmds);
4380 _session->add_command (new StatefulDiffCommand (*pl));
4385 Editor::cut_copy_ranges (CutCopyOp op)
4387 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4389 /* Sort the track selection now, so that it if is used, the playlists
4390 selected by the calls below to cut_copy_clear are in the order that
4391 their tracks appear in the editor. This makes things like paste
4392 of ranges work properly.
4395 sort_track_selection (ts);
4398 if (!entered_track) {
4401 ts.push_back (entered_track);
4404 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4405 (*i)->cut_copy_clear (*selection, op);
4410 Editor::paste (float times, bool from_context)
4412 DEBUG_TRACE (DEBUG::CutNPaste, "paste to preferred edit pos\n");
4414 paste_internal (get_preferred_edit_position (false, from_context), times);
4418 Editor::mouse_paste ()
4423 if (!mouse_frame (where, ignored)) {
4428 paste_internal (where, 1);
4432 Editor::paste_internal (framepos_t position, float times)
4434 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("apparent paste position is %1\n", position));
4436 if (cut_buffer->empty(internal_editing())) {
4440 if (position == max_framepos) {
4441 position = get_preferred_edit_position();
4442 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("preferred edit position is %1\n", position));
4445 if (position == last_paste_pos) {
4446 /* repeated paste in the same position */
4449 /* paste in new location, reset repeated paste state */
4451 last_paste_pos = position;
4454 /* get everything in the correct order */
4457 if (!selection->tracks.empty()) {
4458 /* If there is a track selection, paste into exactly those tracks and
4459 only those tracks. This allows the user to be explicit and override
4460 the below "do the reasonable thing" logic. */
4461 ts = selection->tracks.filter_to_unique_playlists ();
4462 sort_track_selection (ts);
4464 /* Figure out which track to base the paste at. */
4465 TimeAxisView* base_track = NULL;
4466 if (_edit_point == Editing::EditAtMouse && entered_track) {
4467 /* With the mouse edit point, paste onto the track under the mouse. */
4468 base_track = entered_track;
4469 } else if (_edit_point == Editing::EditAtMouse && entered_regionview) {
4470 /* With the mouse edit point, paste onto the track of the region under the mouse. */
4471 base_track = &entered_regionview->get_time_axis_view();
4472 } else if (_last_cut_copy_source_track) {
4473 /* Paste to the track that the cut/copy came from (see mantis #333). */
4474 base_track = _last_cut_copy_source_track;
4476 /* This is "impossible" since we've copied... well, do nothing. */
4480 /* Walk up to parent if necessary, so base track is a route. */
4481 while (base_track->get_parent()) {
4482 base_track = base_track->get_parent();
4485 /* Add base track and all tracks below it. The paste logic will select
4486 the appropriate object types from the cut buffer in relative order. */
4487 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4488 if ((*i)->order() >= base_track->order()) {
4493 /* Sort tracks so the nth track of type T will pick the nth object of type T. */
4494 sort_track_selection (ts);
4496 /* Add automation children of each track in order, for pasting several lines. */
4497 for (TrackViewList::iterator i = ts.begin(); i != ts.end();) {
4498 /* Add any automation children for pasting several lines */
4499 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*i++);
4504 typedef RouteTimeAxisView::AutomationTracks ATracks;
4505 const ATracks& atracks = rtv->automation_tracks();
4506 for (ATracks::const_iterator a = atracks.begin(); a != atracks.end(); ++a) {
4507 i = ts.insert(i, a->second.get());
4512 /* We now have a list of trackviews starting at base_track, including
4513 automation children, in the order shown in the editor, e.g. R1,
4514 R1.A1, R1.A2, R2, R2.A1, ... */
4517 begin_reversible_command (Operations::paste);
4519 if (ts.size() == 1 && cut_buffer->lines.size() == 1 &&
4520 dynamic_cast<AutomationTimeAxisView*>(ts.front())) {
4521 /* Only one line copied, and one automation track selected. Do a
4522 "greedy" paste from one automation type to another. */
4524 PasteContext ctx(paste_count, times, ItemCounts(), true);
4525 ts.front()->paste (position, *cut_buffer, ctx);
4529 /* Paste into tracks */
4531 PasteContext ctx(paste_count, times, ItemCounts(), false);
4532 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4533 (*i)->paste (position, *cut_buffer, ctx);
4537 commit_reversible_command ();
4541 Editor::duplicate_some_regions (RegionSelection& regions, float times)
4543 boost::shared_ptr<Playlist> playlist;
4544 RegionSelection sel = regions; // clear (below) may clear the argument list if its the current region selection
4545 RegionSelection foo;
4547 framepos_t const start_frame = regions.start ();
4548 framepos_t const end_frame = regions.end_frame ();
4550 begin_reversible_command (Operations::duplicate_region);
4552 selection->clear_regions ();
4554 for (RegionSelection::iterator i = sel.begin(); i != sel.end(); ++i) {
4556 boost::shared_ptr<Region> r ((*i)->region());
4558 TimeAxisView& tv = (*i)->get_time_axis_view();
4559 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (&tv);
4560 latest_regionviews.clear ();
4561 sigc::connection c = rtv->view()->RegionViewAdded.connect (sigc::mem_fun(*this, &Editor::collect_new_region_view));
4563 playlist = (*i)->region()->playlist();
4564 playlist->clear_changes ();
4565 playlist->duplicate (r, end_frame + (r->first_frame() - start_frame), times);
4566 _session->add_command(new StatefulDiffCommand (playlist));
4570 foo.insert (foo.end(), latest_regionviews.begin(), latest_regionviews.end());
4574 selection->set (foo);
4577 commit_reversible_command ();
4581 Editor::duplicate_selection (float times)
4583 if (selection->time.empty() || selection->tracks.empty()) {
4587 boost::shared_ptr<Playlist> playlist;
4588 vector<boost::shared_ptr<Region> > new_regions;
4589 vector<boost::shared_ptr<Region> >::iterator ri;
4591 create_region_from_selection (new_regions);
4593 if (new_regions.empty()) {
4597 begin_reversible_command (_("duplicate selection"));
4599 ri = new_regions.begin();
4601 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4603 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4604 if ((playlist = (*i)->playlist()) == 0) {
4607 playlist->clear_changes ();
4609 if (clicked_selection) {
4610 end = selection->time[clicked_selection].end;
4612 end = selection->time.end_frame();
4614 playlist->duplicate (*ri, end, times);
4615 _session->add_command (new StatefulDiffCommand (playlist));
4618 if (ri == new_regions.end()) {
4623 commit_reversible_command ();
4626 /** Reset all selected points to the relevant default value */
4628 Editor::reset_point_selection ()
4630 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
4631 ARDOUR::AutomationList::iterator j = (*i)->model ();
4632 (*j)->value = (*i)->line().the_list()->default_value ();
4637 Editor::center_playhead ()
4639 float const page = _visible_canvas_width * samples_per_pixel;
4640 center_screen_internal (playhead_cursor->current_frame (), page);
4644 Editor::center_edit_point ()
4646 float const page = _visible_canvas_width * samples_per_pixel;
4647 center_screen_internal (get_preferred_edit_position(), page);
4650 /** Caller must begin and commit a reversible command */
4652 Editor::clear_playlist (boost::shared_ptr<Playlist> playlist)
4654 playlist->clear_changes ();
4656 _session->add_command (new StatefulDiffCommand (playlist));
4660 Editor::nudge_track (bool use_edit, bool forwards)
4662 boost::shared_ptr<Playlist> playlist;
4663 framepos_t distance;
4664 framepos_t next_distance;
4668 start = get_preferred_edit_position();
4673 if ((distance = get_nudge_distance (start, next_distance)) == 0) {
4677 if (selection->tracks.empty()) {
4681 begin_reversible_command (_("nudge track"));
4683 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4685 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4687 if ((playlist = (*i)->playlist()) == 0) {
4691 playlist->clear_changes ();
4692 playlist->clear_owned_changes ();
4694 playlist->nudge_after (start, distance, forwards);
4696 vector<Command*> cmds;
4698 playlist->rdiff (cmds);
4699 _session->add_commands (cmds);
4701 _session->add_command (new StatefulDiffCommand (playlist));
4704 commit_reversible_command ();
4708 Editor::remove_last_capture ()
4710 vector<string> choices;
4717 if (Config->get_verify_remove_last_capture()) {
4718 prompt = _("Do you really want to destroy the last capture?"
4719 "\n(This is destructive and cannot be undone)");
4721 choices.push_back (_("No, do nothing."));
4722 choices.push_back (_("Yes, destroy it."));
4724 Gtkmm2ext::Choice prompter (_("Destroy last capture"), prompt, choices);
4726 if (prompter.run () == 1) {
4727 _session->remove_last_capture ();
4728 _regions->redisplay ();
4732 _session->remove_last_capture();
4733 _regions->redisplay ();
4738 Editor::normalize_region ()
4744 RegionSelection rs = get_regions_from_selection_and_entered ();
4750 NormalizeDialog dialog (rs.size() > 1);
4752 if (dialog.run () == RESPONSE_CANCEL) {
4756 CursorContext::Handle cursor_ctx = CursorContext::create(*this, _cursors->wait);
4759 /* XXX: should really only count audio regions here */
4760 int const regions = rs.size ();
4762 /* Make a list of the selected audio regions' maximum amplitudes, and also
4763 obtain the maximum amplitude of them all.
4765 list<double> max_amps;
4767 for (RegionSelection::const_iterator i = rs.begin(); i != rs.end(); ++i) {
4768 AudioRegionView const * arv = dynamic_cast<AudioRegionView const *> (*i);
4770 dialog.descend (1.0 / regions);
4771 double const a = arv->audio_region()->maximum_amplitude (&dialog);
4774 /* the user cancelled the operation */
4778 max_amps.push_back (a);
4779 max_amp = max (max_amp, a);
4784 begin_reversible_command (_("normalize"));
4786 list<double>::const_iterator a = max_amps.begin ();
4788 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
4789 AudioRegionView* const arv = dynamic_cast<AudioRegionView*> (*r);
4794 arv->region()->clear_changes ();
4796 double const amp = dialog.normalize_individually() ? *a : max_amp;
4798 arv->audio_region()->normalize (amp, dialog.target ());
4799 _session->add_command (new StatefulDiffCommand (arv->region()));
4804 commit_reversible_command ();
4809 Editor::reset_region_scale_amplitude ()
4815 RegionSelection rs = get_regions_from_selection_and_entered ();
4821 begin_reversible_command ("reset gain");
4823 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
4824 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
4827 arv->region()->clear_changes ();
4828 arv->audio_region()->set_scale_amplitude (1.0f);
4829 _session->add_command (new StatefulDiffCommand (arv->region()));
4832 commit_reversible_command ();
4836 Editor::adjust_region_gain (bool up)
4838 RegionSelection rs = get_regions_from_selection_and_entered ();
4840 if (!_session || rs.empty()) {
4844 begin_reversible_command ("adjust region gain");
4846 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
4847 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
4852 arv->region()->clear_changes ();
4854 double dB = accurate_coefficient_to_dB (arv->audio_region()->scale_amplitude ());
4862 arv->audio_region()->set_scale_amplitude (dB_to_coefficient (dB));
4863 _session->add_command (new StatefulDiffCommand (arv->region()));
4866 commit_reversible_command ();
4871 Editor::reverse_region ()
4877 Reverse rev (*_session);
4878 apply_filter (rev, _("reverse regions"));
4882 Editor::strip_region_silence ()
4888 RegionSelection rs = get_regions_from_selection_and_entered ();
4894 std::list<RegionView*> audio_only;
4896 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
4897 AudioRegionView* const arv = dynamic_cast<AudioRegionView*> (*i);
4899 audio_only.push_back (arv);
4903 StripSilenceDialog d (_session, audio_only);
4904 int const r = d.run ();
4908 if (r == Gtk::RESPONSE_OK) {
4909 ARDOUR::AudioIntervalMap silences;
4910 d.silences (silences);
4911 StripSilence s (*_session, silences, d.fade_length());
4912 apply_filter (s, _("strip silence"), &d);
4917 Editor::apply_midi_note_edit_op_to_region (MidiOperator& op, MidiRegionView& mrv)
4919 Evoral::Sequence<Evoral::MusicalTime>::Notes selected;
4920 mrv.selection_as_notelist (selected, true);
4922 vector<Evoral::Sequence<Evoral::MusicalTime>::Notes> v;
4923 v.push_back (selected);
4925 framepos_t pos_frames = mrv.midi_region()->position() - mrv.midi_region()->start();
4926 Evoral::MusicalTime pos_beats = _session->tempo_map().framewalk_to_beats(0, pos_frames);
4928 return op (mrv.midi_region()->model(), pos_beats, v);
4932 Editor::apply_midi_note_edit_op (MidiOperator& op, const RegionSelection& rs)
4938 begin_reversible_command (op.name ());
4940 for (RegionSelection::const_iterator r = rs.begin(); r != rs.end(); ) {
4941 RegionSelection::const_iterator tmp = r;
4944 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*r);
4947 Command* cmd = apply_midi_note_edit_op_to_region (op, *mrv);
4950 _session->add_command (cmd);
4957 commit_reversible_command ();
4961 Editor::fork_region ()
4963 RegionSelection rs = get_regions_from_selection_and_entered ();
4969 begin_reversible_command (_("Fork Region(s)"));
4971 CursorContext::Handle cursor_ctx = CursorContext::create(*this, _cursors->wait);
4974 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
4975 RegionSelection::iterator tmp = r;
4978 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*>(*r);
4982 boost::shared_ptr<Playlist> playlist = mrv->region()->playlist();
4983 boost::shared_ptr<MidiSource> new_source = _session->create_midi_source_by_stealing_name (mrv->midi_view()->track());
4984 boost::shared_ptr<MidiRegion> newregion = mrv->midi_region()->clone (new_source);
4986 playlist->clear_changes ();
4987 playlist->replace_region (mrv->region(), newregion, mrv->region()->position());
4988 _session->add_command(new StatefulDiffCommand (playlist));
4990 error << string_compose (_("Could not unlink %1"), mrv->region()->name()) << endmsg;
4997 commit_reversible_command ();
5001 Editor::quantize_region ()
5004 quantize_regions(get_regions_from_selection_and_entered ());
5009 Editor::quantize_regions (const RegionSelection& rs)
5011 if (rs.n_midi_regions() == 0) {
5015 QuantizeDialog* qd = new QuantizeDialog (*this);
5018 const int r = qd->run ();
5021 if (r == Gtk::RESPONSE_OK) {
5022 Quantize quant (qd->snap_start(), qd->snap_end(),
5023 qd->start_grid_size(), qd->end_grid_size(),
5024 qd->strength(), qd->swing(), qd->threshold());
5026 apply_midi_note_edit_op (quant, rs);
5031 Editor::legatize_region (bool shrink_only)
5034 legatize_regions(get_regions_from_selection_and_entered (), shrink_only);
5039 Editor::legatize_regions (const RegionSelection& rs, bool shrink_only)
5041 if (rs.n_midi_regions() == 0) {
5045 Legatize legatize(shrink_only);
5046 apply_midi_note_edit_op (legatize, rs);
5050 Editor::transform_region ()
5053 transform_regions(get_regions_from_selection_and_entered ());
5058 Editor::transform_regions (const RegionSelection& rs)
5060 if (rs.n_midi_regions() == 0) {
5064 TransformDialog* td = new TransformDialog();
5067 const int r = td->run();
5070 if (r == Gtk::RESPONSE_OK) {
5071 Transform transform(td->get());
5072 apply_midi_note_edit_op(transform, rs);
5077 Editor::insert_patch_change (bool from_context)
5079 RegionSelection rs = get_regions_from_selection_and_entered ();
5085 const framepos_t p = get_preferred_edit_position (false, from_context);
5087 /* XXX: bit of a hack; use the MIDNAM from the first selected region;
5088 there may be more than one, but the PatchChangeDialog can only offer
5089 one set of patch menus.
5091 MidiRegionView* first = dynamic_cast<MidiRegionView*> (rs.front ());
5093 Evoral::PatchChange<Evoral::MusicalTime> empty (Evoral::MusicalTime(), 0, 0, 0);
5094 PatchChangeDialog d (0, _session, empty, first->instrument_info(), Gtk::Stock::ADD);
5096 if (d.run() == RESPONSE_CANCEL) {
5100 for (RegionSelection::iterator i = rs.begin (); i != rs.end(); ++i) {
5101 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*i);
5103 if (p >= mrv->region()->first_frame() && p <= mrv->region()->last_frame()) {
5104 mrv->add_patch_change (p - mrv->region()->position(), d.patch ());
5111 Editor::apply_filter (Filter& filter, string command, ProgressReporter* progress)
5113 RegionSelection rs = get_regions_from_selection_and_entered ();
5119 begin_reversible_command (command);
5121 CursorContext::Handle cursor_ctx = CursorContext::create(*this, _cursors->wait);
5125 int const N = rs.size ();
5127 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
5128 RegionSelection::iterator tmp = r;
5131 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
5133 boost::shared_ptr<Playlist> playlist = arv->region()->playlist();
5136 progress->descend (1.0 / N);
5139 if (arv->audio_region()->apply (filter, progress) == 0) {
5141 playlist->clear_changes ();
5142 playlist->clear_owned_changes ();
5144 if (filter.results.empty ()) {
5146 /* no regions returned; remove the old one */
5147 playlist->remove_region (arv->region ());
5151 std::vector<boost::shared_ptr<Region> >::iterator res = filter.results.begin ();
5153 /* first region replaces the old one */
5154 playlist->replace_region (arv->region(), *res, (*res)->position());
5158 while (res != filter.results.end()) {
5159 playlist->add_region (*res, (*res)->position());
5165 /* We might have removed regions, which alters other regions' layering_index,
5166 so we need to do a recursive diff here.
5168 vector<Command*> cmds;
5169 playlist->rdiff (cmds);
5170 _session->add_commands (cmds);
5172 _session->add_command(new StatefulDiffCommand (playlist));
5178 progress->ascend ();
5186 commit_reversible_command ();
5190 Editor::external_edit_region ()
5196 Editor::reset_region_gain_envelopes ()
5198 RegionSelection rs = get_regions_from_selection_and_entered ();
5200 if (!_session || rs.empty()) {
5204 begin_reversible_command (_("reset region gain"));
5206 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5207 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
5209 boost::shared_ptr<AutomationList> alist (arv->audio_region()->envelope());
5210 XMLNode& before (alist->get_state());
5212 arv->audio_region()->set_default_envelope ();
5213 _session->add_command (new MementoCommand<AutomationList>(*arv->audio_region()->envelope().get(), &before, &alist->get_state()));
5217 commit_reversible_command ();
5221 Editor::set_region_gain_visibility (RegionView* rv)
5223 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (rv);
5225 arv->update_envelope_visibility();
5230 Editor::set_gain_envelope_visibility ()
5236 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5237 AudioTimeAxisView* v = dynamic_cast<AudioTimeAxisView*>(*i);
5239 v->audio_view()->foreach_regionview (sigc::mem_fun (this, &Editor::set_region_gain_visibility));
5245 Editor::toggle_gain_envelope_active ()
5247 if (_ignore_region_action) {
5251 RegionSelection rs = get_regions_from_selection_and_entered ();
5253 if (!_session || rs.empty()) {
5257 begin_reversible_command (_("region gain envelope active"));
5259 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5260 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
5262 arv->region()->clear_changes ();
5263 arv->audio_region()->set_envelope_active (!arv->audio_region()->envelope_active());
5264 _session->add_command (new StatefulDiffCommand (arv->region()));
5268 commit_reversible_command ();
5272 Editor::toggle_region_lock ()
5274 if (_ignore_region_action) {
5278 RegionSelection rs = get_regions_from_selection_and_entered ();
5280 if (!_session || rs.empty()) {
5284 begin_reversible_command (_("toggle region lock"));
5286 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5287 (*i)->region()->clear_changes ();
5288 (*i)->region()->set_locked (!(*i)->region()->locked());
5289 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5292 commit_reversible_command ();
5296 Editor::toggle_region_video_lock ()
5298 if (_ignore_region_action) {
5302 RegionSelection rs = get_regions_from_selection_and_entered ();
5304 if (!_session || rs.empty()) {
5308 begin_reversible_command (_("Toggle Video Lock"));
5310 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5311 (*i)->region()->clear_changes ();
5312 (*i)->region()->set_video_locked (!(*i)->region()->video_locked());
5313 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5316 commit_reversible_command ();
5320 Editor::toggle_region_lock_style ()
5322 if (_ignore_region_action) {
5326 RegionSelection rs = get_regions_from_selection_and_entered ();
5328 if (!_session || rs.empty()) {
5332 begin_reversible_command (_("region lock style"));
5334 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5335 (*i)->region()->clear_changes ();
5336 PositionLockStyle const ns = (*i)->region()->position_lock_style() == AudioTime ? MusicTime : AudioTime;
5337 (*i)->region()->set_position_lock_style (ns);
5338 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5341 commit_reversible_command ();
5345 Editor::toggle_opaque_region ()
5347 if (_ignore_region_action) {
5351 RegionSelection rs = get_regions_from_selection_and_entered ();
5353 if (!_session || rs.empty()) {
5357 begin_reversible_command (_("change region opacity"));
5359 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5360 (*i)->region()->clear_changes ();
5361 (*i)->region()->set_opaque (!(*i)->region()->opaque());
5362 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5365 commit_reversible_command ();
5369 Editor::toggle_record_enable ()
5371 bool new_state = false;
5373 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5374 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5377 if (!rtav->is_track())
5381 new_state = !rtav->track()->record_enabled();
5385 rtav->track()->set_record_enabled (new_state, this);
5390 Editor::toggle_solo ()
5392 bool new_state = false;
5394 boost::shared_ptr<RouteList> rl (new RouteList);
5396 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5397 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5404 new_state = !rtav->route()->soloed ();
5408 rl->push_back (rtav->route());
5411 _session->set_solo (rl, new_state, Session::rt_cleanup, true);
5415 Editor::toggle_mute ()
5417 bool new_state = false;
5419 boost::shared_ptr<RouteList> rl (new RouteList);
5421 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5422 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5429 new_state = !rtav->route()->muted();
5433 rl->push_back (rtav->route());
5436 _session->set_mute (rl, new_state, Session::rt_cleanup, true);
5440 Editor::toggle_solo_isolate ()
5446 Editor::fade_range ()
5448 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
5450 begin_reversible_command (_("fade range"));
5452 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
5453 (*i)->fade_range (selection->time);
5456 commit_reversible_command ();
5461 Editor::set_fade_length (bool in)
5463 RegionSelection rs = get_regions_from_selection_and_entered ();
5469 /* we need a region to measure the offset from the start */
5471 RegionView* rv = rs.front ();
5473 framepos_t pos = get_preferred_edit_position();
5477 if (pos > rv->region()->last_frame() || pos < rv->region()->first_frame()) {
5478 /* edit point is outside the relevant region */
5483 if (pos <= rv->region()->position()) {
5487 len = pos - rv->region()->position();
5488 cmd = _("set fade in length");
5490 if (pos >= rv->region()->last_frame()) {
5494 len = rv->region()->last_frame() - pos;
5495 cmd = _("set fade out length");
5498 begin_reversible_command (cmd);
5500 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5501 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5507 boost::shared_ptr<AutomationList> alist;
5509 alist = tmp->audio_region()->fade_in();
5511 alist = tmp->audio_region()->fade_out();
5514 XMLNode &before = alist->get_state();
5517 tmp->audio_region()->set_fade_in_length (len);
5518 tmp->audio_region()->set_fade_in_active (true);
5520 tmp->audio_region()->set_fade_out_length (len);
5521 tmp->audio_region()->set_fade_out_active (true);
5524 XMLNode &after = alist->get_state();
5525 _session->add_command(new MementoCommand<AutomationList>(*alist, &before, &after));
5528 commit_reversible_command ();
5532 Editor::set_fade_in_shape (FadeShape shape)
5534 RegionSelection rs = get_regions_from_selection_and_entered ();
5540 begin_reversible_command (_("set fade in shape"));
5542 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5543 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5549 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_in();
5550 XMLNode &before = alist->get_state();
5552 tmp->audio_region()->set_fade_in_shape (shape);
5554 XMLNode &after = alist->get_state();
5555 _session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
5558 commit_reversible_command ();
5563 Editor::set_fade_out_shape (FadeShape shape)
5565 RegionSelection rs = get_regions_from_selection_and_entered ();
5571 begin_reversible_command (_("set fade out shape"));
5573 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5574 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5580 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_out();
5581 XMLNode &before = alist->get_state();
5583 tmp->audio_region()->set_fade_out_shape (shape);
5585 XMLNode &after = alist->get_state();
5586 _session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
5589 commit_reversible_command ();
5593 Editor::set_fade_in_active (bool yn)
5595 RegionSelection rs = get_regions_from_selection_and_entered ();
5601 begin_reversible_command (_("set fade in active"));
5603 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5604 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5611 boost::shared_ptr<AudioRegion> ar (tmp->audio_region());
5613 ar->clear_changes ();
5614 ar->set_fade_in_active (yn);
5615 _session->add_command (new StatefulDiffCommand (ar));
5618 commit_reversible_command ();
5622 Editor::set_fade_out_active (bool yn)
5624 RegionSelection rs = get_regions_from_selection_and_entered ();
5630 begin_reversible_command (_("set fade out active"));
5632 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5633 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5639 boost::shared_ptr<AudioRegion> ar (tmp->audio_region());
5641 ar->clear_changes ();
5642 ar->set_fade_out_active (yn);
5643 _session->add_command(new StatefulDiffCommand (ar));
5646 commit_reversible_command ();
5650 Editor::toggle_region_fades (int dir)
5652 if (_ignore_region_action) {
5656 boost::shared_ptr<AudioRegion> ar;
5659 RegionSelection rs = get_regions_from_selection_and_entered ();
5665 RegionSelection::iterator i;
5666 for (i = rs.begin(); i != rs.end(); ++i) {
5667 if ((ar = boost::dynamic_pointer_cast<AudioRegion>((*i)->region())) != 0) {
5669 yn = ar->fade_out_active ();
5671 yn = ar->fade_in_active ();
5677 if (i == rs.end()) {
5681 /* XXX should this undo-able? */
5683 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5684 if ((ar = boost::dynamic_pointer_cast<AudioRegion>((*i)->region())) == 0) {
5687 if (dir == 1 || dir == 0) {
5688 ar->set_fade_in_active (!yn);
5691 if (dir == -1 || dir == 0) {
5692 ar->set_fade_out_active (!yn);
5698 /** Update region fade visibility after its configuration has been changed */
5700 Editor::update_region_fade_visibility ()
5702 bool _fade_visibility = _session->config.get_show_region_fades ();
5704 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5705 AudioTimeAxisView* v = dynamic_cast<AudioTimeAxisView*>(*i);
5707 if (_fade_visibility) {
5708 v->audio_view()->show_all_fades ();
5710 v->audio_view()->hide_all_fades ();
5717 Editor::set_edit_point ()
5722 if (!mouse_frame (where, ignored)) {
5728 if (selection->markers.empty()) {
5730 mouse_add_new_marker (where);
5735 Location* loc = find_location_from_marker (selection->markers.front(), ignored);
5738 loc->move_to (where);
5744 Editor::set_playhead_cursor ()
5746 if (entered_marker) {
5747 _session->request_locate (entered_marker->position(), _session->transport_rolling());
5752 if (!mouse_frame (where, ignored)) {
5759 _session->request_locate (where, _session->transport_rolling());
5763 if (ARDOUR_UI::config()->get_follow_edits()) {
5764 cancel_time_selection();
5769 Editor::split_region ()
5771 if ( !selection->time.empty()) {
5772 separate_regions_between (selection->time);
5776 RegionSelection rs = get_regions_from_selection_and_edit_point ();
5778 framepos_t where = get_preferred_edit_position ();
5784 split_regions_at (where, rs);
5787 struct EditorOrderRouteSorter {
5788 bool operator() (boost::shared_ptr<Route> a, boost::shared_ptr<Route> b) {
5789 return a->order_key () < b->order_key ();
5794 Editor::select_next_route()
5796 if (selection->tracks.empty()) {
5797 selection->set (track_views.front());
5801 TimeAxisView* current = selection->tracks.front();
5805 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5806 if (*i == current) {
5808 if (i != track_views.end()) {
5811 current = (*(track_views.begin()));
5812 //selection->set (*(track_views.begin()));
5817 rui = dynamic_cast<RouteUI *>(current);
5818 } while ( current->hidden() || (rui != NULL && !rui->route()->active()));
5820 selection->set(current);
5822 ensure_time_axis_view_is_visible (*current, false);
5826 Editor::select_prev_route()
5828 if (selection->tracks.empty()) {
5829 selection->set (track_views.front());
5833 TimeAxisView* current = selection->tracks.front();
5837 for (TrackViewList::reverse_iterator i = track_views.rbegin(); i != track_views.rend(); ++i) {
5838 if (*i == current) {
5840 if (i != track_views.rend()) {
5843 current = *(track_views.rbegin());
5848 rui = dynamic_cast<RouteUI *>(current);
5849 } while ( current->hidden() || (rui != NULL && !rui->route()->active()));
5851 selection->set (current);
5853 ensure_time_axis_view_is_visible (*current, false);
5857 Editor::set_loop_from_selection (bool play)
5859 if (_session == 0 || selection->time.empty()) {
5863 framepos_t start = selection->time[clicked_selection].start;
5864 framepos_t end = selection->time[clicked_selection].end;
5866 set_loop_range (start, end, _("set loop range from selection"));
5869 _session->request_locate (start, true);
5870 _session->request_play_loop (true);
5875 Editor::set_loop_from_edit_range (bool play)
5877 if (_session == 0) {
5884 if (!get_edit_op_range (start, end)) {
5888 set_loop_range (start, end, _("set loop range from edit range"));
5891 _session->request_locate (start, true);
5892 _session->request_play_loop (true);
5897 Editor::set_loop_from_region (bool play)
5899 framepos_t start = max_framepos;
5902 RegionSelection rs = get_regions_from_selection_and_entered ();
5908 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5909 if ((*i)->region()->position() < start) {
5910 start = (*i)->region()->position();
5912 if ((*i)->region()->last_frame() + 1 > end) {
5913 end = (*i)->region()->last_frame() + 1;
5917 set_loop_range (start, end, _("set loop range from region"));
5920 _session->request_locate (start, true);
5921 _session->request_play_loop (true);
5926 Editor::set_punch_from_selection ()
5928 if (_session == 0 || selection->time.empty()) {
5932 framepos_t start = selection->time[clicked_selection].start;
5933 framepos_t end = selection->time[clicked_selection].end;
5935 set_punch_range (start, end, _("set punch range from selection"));
5939 Editor::set_session_extents_from_selection ()
5941 if (_session == 0 || selection->time.empty()) {
5945 begin_reversible_command (_("set session start/stop from selection"));
5947 framepos_t start = selection->time[clicked_selection].start;
5948 framepos_t end = selection->time[clicked_selection].end;
5951 if ((loc = _session->locations()->session_range_location()) == 0) {
5952 _session->set_session_extents ( start, end ); // this will create a new session range; no need for UNDO
5954 XMLNode &before = loc->get_state();
5956 _session->set_session_extents ( start, end );
5958 XMLNode &after = loc->get_state();
5960 _session->add_command (new MementoCommand<Location>(*loc, &before, &after));
5962 commit_reversible_command ();
5967 Editor::set_punch_from_edit_range ()
5969 if (_session == 0) {
5976 if (!get_edit_op_range (start, end)) {
5980 set_punch_range (start, end, _("set punch range from edit range"));
5984 Editor::set_punch_from_region ()
5986 framepos_t start = max_framepos;
5989 RegionSelection rs = get_regions_from_selection_and_entered ();
5995 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5996 if ((*i)->region()->position() < start) {
5997 start = (*i)->region()->position();
5999 if ((*i)->region()->last_frame() + 1 > end) {
6000 end = (*i)->region()->last_frame() + 1;
6004 set_punch_range (start, end, _("set punch range from region"));
6008 Editor::pitch_shift_region ()
6010 RegionSelection rs = get_regions_from_selection_and_entered ();
6012 RegionSelection audio_rs;
6013 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
6014 if (dynamic_cast<AudioRegionView*> (*i)) {
6015 audio_rs.push_back (*i);
6019 if (audio_rs.empty()) {
6023 pitch_shift (audio_rs, 1.2);
6027 Editor::transpose_region ()
6029 RegionSelection rs = get_regions_from_selection_and_entered ();
6031 list<MidiRegionView*> midi_region_views;
6032 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
6033 MidiRegionView* mrv = dynamic_cast<MidiRegionView*> (*i);
6035 midi_region_views.push_back (mrv);
6040 int const r = d.run ();
6041 if (r != RESPONSE_ACCEPT) {
6045 for (list<MidiRegionView*>::iterator i = midi_region_views.begin(); i != midi_region_views.end(); ++i) {
6046 (*i)->midi_region()->transpose (d.semitones ());
6051 Editor::set_tempo_from_region ()
6053 RegionSelection rs = get_regions_from_selection_and_entered ();
6055 if (!_session || rs.empty()) {
6059 RegionView* rv = rs.front();
6061 define_one_bar (rv->region()->position(), rv->region()->last_frame() + 1);
6065 Editor::use_range_as_bar ()
6067 framepos_t start, end;
6068 if (get_edit_op_range (start, end)) {
6069 define_one_bar (start, end);
6074 Editor::define_one_bar (framepos_t start, framepos_t end)
6076 framepos_t length = end - start;
6078 const Meter& m (_session->tempo_map().meter_at (start));
6080 /* length = 1 bar */
6082 /* now we want frames per beat.
6083 we have frames per bar, and beats per bar, so ...
6086 /* XXXX METER MATH */
6088 double frames_per_beat = length / m.divisions_per_bar();
6090 /* beats per minute = */
6092 double beats_per_minute = (_session->frame_rate() * 60.0) / frames_per_beat;
6094 /* now decide whether to:
6096 (a) set global tempo
6097 (b) add a new tempo marker
6101 const TempoSection& t (_session->tempo_map().tempo_section_at (start));
6103 bool do_global = false;
6105 if ((_session->tempo_map().n_tempos() == 1) && (_session->tempo_map().n_meters() == 1)) {
6107 /* only 1 tempo & 1 meter: ask if the user wants to set the tempo
6108 at the start, or create a new marker
6111 vector<string> options;
6112 options.push_back (_("Cancel"));
6113 options.push_back (_("Add new marker"));
6114 options.push_back (_("Set global tempo"));
6117 _("Define one bar"),
6118 _("Do you want to set the global tempo or add a new tempo marker?"),
6122 c.set_default_response (2);
6138 /* more than 1 tempo and/or meter section already, go ahead do the "usual":
6139 if the marker is at the region starter, change it, otherwise add
6144 begin_reversible_command (_("set tempo from region"));
6145 XMLNode& before (_session->tempo_map().get_state());
6148 _session->tempo_map().change_initial_tempo (beats_per_minute, t.note_type());
6149 } else if (t.frame() == start) {
6150 _session->tempo_map().change_existing_tempo_at (start, beats_per_minute, t.note_type());
6152 Timecode::BBT_Time bbt;
6153 _session->tempo_map().bbt_time (start, bbt);
6154 _session->tempo_map().add_tempo (Tempo (beats_per_minute, t.note_type()), bbt);
6157 XMLNode& after (_session->tempo_map().get_state());
6159 _session->add_command (new MementoCommand<TempoMap>(_session->tempo_map(), &before, &after));
6160 commit_reversible_command ();
6164 Editor::split_region_at_transients ()
6166 AnalysisFeatureList positions;
6168 RegionSelection rs = get_regions_from_selection_and_entered ();
6170 if (!_session || rs.empty()) {
6174 begin_reversible_command (_("split regions"));
6176 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ) {
6178 RegionSelection::iterator tmp;
6183 boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion> ((*i)->region());
6185 if (ar && (ar->get_transients (positions) == 0)) {
6186 split_region_at_points ((*i)->region(), positions, true);
6193 commit_reversible_command ();
6198 Editor::split_region_at_points (boost::shared_ptr<Region> r, AnalysisFeatureList& positions, bool can_ferret, bool select_new)
6200 bool use_rhythmic_rodent = false;
6202 boost::shared_ptr<Playlist> pl = r->playlist();
6204 list<boost::shared_ptr<Region> > new_regions;
6210 if (positions.empty()) {
6215 if (positions.size() > 20 && can_ferret) {
6216 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);
6217 MessageDialog msg (msgstr,
6220 Gtk::BUTTONS_OK_CANCEL);
6223 msg.add_button (_("Call for the Ferret!"), RESPONSE_APPLY);
6224 msg.set_secondary_text (_("Press OK to continue with this split operation\nor ask the Ferret dialog to tune the analysis"));
6226 msg.set_secondary_text (_("Press OK to continue with this split operation"));
6229 msg.set_title (_("Excessive split?"));
6232 int response = msg.run();
6238 case RESPONSE_APPLY:
6239 use_rhythmic_rodent = true;
6246 if (use_rhythmic_rodent) {
6247 show_rhythm_ferret ();
6251 AnalysisFeatureList::const_iterator x;
6253 pl->clear_changes ();
6254 pl->clear_owned_changes ();
6256 x = positions.begin();
6258 if (x == positions.end()) {
6263 pl->remove_region (r);
6267 while (x != positions.end()) {
6269 /* deal with positons that are out of scope of present region bounds */
6270 if (*x <= 0 || *x > r->length()) {
6275 /* file start = original start + how far we from the initial position ?
6278 framepos_t file_start = r->start() + pos;
6280 /* length = next position - current position
6283 framepos_t len = (*x) - pos;
6285 /* XXX we do we really want to allow even single-sample regions?
6286 shouldn't we have some kind of lower limit on region size?
6295 if (RegionFactory::region_name (new_name, r->name())) {
6299 /* do NOT announce new regions 1 by one, just wait till they are all done */
6303 plist.add (ARDOUR::Properties::start, file_start);
6304 plist.add (ARDOUR::Properties::length, len);
6305 plist.add (ARDOUR::Properties::name, new_name);
6306 plist.add (ARDOUR::Properties::layer, 0);
6308 boost::shared_ptr<Region> nr = RegionFactory::create (r->sources(), plist, false);
6309 /* because we set annouce to false, manually add the new region to the
6312 RegionFactory::map_add (nr);
6314 pl->add_region (nr, r->position() + pos);
6317 new_regions.push_front(nr);
6326 RegionFactory::region_name (new_name, r->name());
6328 /* Add the final region */
6331 plist.add (ARDOUR::Properties::start, r->start() + pos);
6332 plist.add (ARDOUR::Properties::length, r->last_frame() - (r->position() + pos) + 1);
6333 plist.add (ARDOUR::Properties::name, new_name);
6334 plist.add (ARDOUR::Properties::layer, 0);
6336 boost::shared_ptr<Region> nr = RegionFactory::create (r->sources(), plist, false);
6337 /* because we set annouce to false, manually add the new region to the
6340 RegionFactory::map_add (nr);
6341 pl->add_region (nr, r->position() + pos);
6344 new_regions.push_front(nr);
6349 /* We might have removed regions, which alters other regions' layering_index,
6350 so we need to do a recursive diff here.
6352 vector<Command*> cmds;
6354 _session->add_commands (cmds);
6356 _session->add_command (new StatefulDiffCommand (pl));
6360 for (list<boost::shared_ptr<Region> >::iterator i = new_regions.begin(); i != new_regions.end(); ++i){
6361 set_selected_regionview_from_region_list ((*i), Selection::Add);
6367 Editor::place_transient()
6373 RegionSelection rs = get_regions_from_selection_and_edit_point ();
6379 framepos_t where = get_preferred_edit_position();
6381 begin_reversible_command (_("place transient"));
6383 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6384 framepos_t position = (*r)->region()->position();
6385 (*r)->region()->add_transient(where - position);
6388 commit_reversible_command ();
6392 Editor::remove_transient(ArdourCanvas::Item* item)
6398 ArdourCanvas::Line* _line = reinterpret_cast<ArdourCanvas::Line*> (item);
6401 AudioRegionView* _arv = reinterpret_cast<AudioRegionView*> (item->get_data ("regionview"));
6402 _arv->remove_transient (*(float*) _line->get_data ("position"));
6406 Editor::snap_regions_to_grid ()
6408 list <boost::shared_ptr<Playlist > > used_playlists;
6410 RegionSelection rs = get_regions_from_selection_and_entered ();
6412 if (!_session || rs.empty()) {
6416 begin_reversible_command (_("snap regions to grid"));
6418 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6420 boost::shared_ptr<Playlist> pl = (*r)->region()->playlist();
6422 if (!pl->frozen()) {
6423 /* we haven't seen this playlist before */
6425 /* remember used playlists so we can thaw them later */
6426 used_playlists.push_back(pl);
6430 framepos_t start_frame = (*r)->region()->first_frame ();
6431 snap_to (start_frame);
6432 (*r)->region()->set_position (start_frame);
6435 while (used_playlists.size() > 0) {
6436 list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
6438 used_playlists.pop_front();
6441 commit_reversible_command ();
6445 Editor::close_region_gaps ()
6447 list <boost::shared_ptr<Playlist > > used_playlists;
6449 RegionSelection rs = get_regions_from_selection_and_entered ();
6451 if (!_session || rs.empty()) {
6455 Dialog dialog (_("Close Region Gaps"));
6458 table.set_spacings (12);
6459 table.set_border_width (12);
6460 Label* l = manage (left_aligned_label (_("Crossfade length")));
6461 table.attach (*l, 0, 1, 0, 1);
6463 SpinButton spin_crossfade (1, 0);
6464 spin_crossfade.set_range (0, 15);
6465 spin_crossfade.set_increments (1, 1);
6466 spin_crossfade.set_value (5);
6467 table.attach (spin_crossfade, 1, 2, 0, 1);
6469 table.attach (*manage (new Label (_("ms"))), 2, 3, 0, 1);
6471 l = manage (left_aligned_label (_("Pull-back length")));
6472 table.attach (*l, 0, 1, 1, 2);
6474 SpinButton spin_pullback (1, 0);
6475 spin_pullback.set_range (0, 100);
6476 spin_pullback.set_increments (1, 1);
6477 spin_pullback.set_value(30);
6478 table.attach (spin_pullback, 1, 2, 1, 2);
6480 table.attach (*manage (new Label (_("ms"))), 2, 3, 1, 2);
6482 dialog.get_vbox()->pack_start (table);
6483 dialog.add_button (Stock::CANCEL, RESPONSE_CANCEL);
6484 dialog.add_button (_("Ok"), RESPONSE_ACCEPT);
6487 if (dialog.run () == RESPONSE_CANCEL) {
6491 framepos_t crossfade_len = spin_crossfade.get_value();
6492 framepos_t pull_back_frames = spin_pullback.get_value();
6494 crossfade_len = lrintf (crossfade_len * _session->frame_rate()/1000);
6495 pull_back_frames = lrintf (pull_back_frames * _session->frame_rate()/1000);
6497 /* Iterate over the region list and make adjacent regions overlap by crossfade_len_ms */
6499 begin_reversible_command (_("close region gaps"));
6502 boost::shared_ptr<Region> last_region;
6504 rs.sort_by_position_and_track();
6506 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6508 boost::shared_ptr<Playlist> pl = (*r)->region()->playlist();
6510 if (!pl->frozen()) {
6511 /* we haven't seen this playlist before */
6513 /* remember used playlists so we can thaw them later */
6514 used_playlists.push_back(pl);
6518 framepos_t position = (*r)->region()->position();
6520 if (idx == 0 || position < last_region->position()){
6521 last_region = (*r)->region();
6526 (*r)->region()->trim_front( (position - pull_back_frames));
6527 last_region->trim_end( (position - pull_back_frames + crossfade_len));
6529 last_region = (*r)->region();
6534 while (used_playlists.size() > 0) {
6535 list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
6537 used_playlists.pop_front();
6540 commit_reversible_command ();
6544 Editor::tab_to_transient (bool forward)
6546 AnalysisFeatureList positions;
6548 RegionSelection rs = get_regions_from_selection_and_entered ();
6554 framepos_t pos = _session->audible_frame ();
6556 if (!selection->tracks.empty()) {
6558 /* don't waste time searching for transients in duplicate playlists.
6561 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
6563 for (TrackViewList::iterator t = ts.begin(); t != ts.end(); ++t) {
6565 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*t);
6568 boost::shared_ptr<Track> tr = rtv->track();
6570 boost::shared_ptr<Playlist> pl = tr->playlist ();
6572 framepos_t result = pl->find_next_transient (pos, forward ? 1 : -1);
6575 positions.push_back (result);
6588 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6589 (*r)->region()->get_transients (positions);
6593 TransientDetector::cleanup_transients (positions, _session->frame_rate(), 3.0);
6596 AnalysisFeatureList::iterator x;
6598 for (x = positions.begin(); x != positions.end(); ++x) {
6604 if (x != positions.end ()) {
6605 _session->request_locate (*x);
6609 AnalysisFeatureList::reverse_iterator x;
6611 for (x = positions.rbegin(); x != positions.rend(); ++x) {
6617 if (x != positions.rend ()) {
6618 _session->request_locate (*x);
6624 Editor::playhead_forward_to_grid ()
6630 framepos_t pos = playhead_cursor->current_frame ();
6631 if (pos < max_framepos - 1) {
6633 snap_to_internal (pos, RoundUpAlways, false);
6634 _session->request_locate (pos);
6640 Editor::playhead_backward_to_grid ()
6646 framepos_t pos = playhead_cursor->current_frame ();
6649 snap_to_internal (pos, RoundDownAlways, false);
6650 _session->request_locate (pos);
6655 Editor::set_track_height (Height h)
6657 TrackSelection& ts (selection->tracks);
6659 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
6660 (*x)->set_height_enum (h);
6665 Editor::toggle_tracks_active ()
6667 TrackSelection& ts (selection->tracks);
6669 bool target = false;
6675 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
6676 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*x);
6680 target = !rtv->_route->active();
6683 rtv->_route->set_active (target, this);
6689 Editor::remove_tracks ()
6691 TrackSelection& ts (selection->tracks);
6697 vector<string> choices;
6701 const char* trackstr;
6703 vector<boost::shared_ptr<Route> > routes;
6704 bool special_bus = false;
6706 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
6707 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*x);
6711 if (rtv->is_track()) {
6716 routes.push_back (rtv->_route);
6718 if (rtv->route()->is_master() || rtv->route()->is_monitor()) {
6723 if (special_bus && !Config->get_allow_special_bus_removal()) {
6724 MessageDialog msg (_("That would be bad news ...."),
6728 msg.set_secondary_text (string_compose (_(
6729 "Removing the master or monitor bus is such a bad idea\n\
6730 that %1 is not going to allow it.\n\
6732 If you really want to do this sort of thing\n\
6733 edit your ardour.rc file to set the\n\
6734 \"allow-special-bus-removal\" option to be \"yes\""), PROGRAM_NAME));
6741 if (ntracks + nbusses == 0) {
6745 // XXX should be using gettext plural forms, maybe?
6747 trackstr = _("tracks");
6749 trackstr = _("track");
6753 busstr = _("busses");
6760 prompt = string_compose (_("Do you really want to remove %1 %2 and %3 %4?\n"
6761 "(You may also lose the playlists associated with the %2)\n\n"
6762 "This action cannot be undone, and the session file will be overwritten!"),
6763 ntracks, trackstr, nbusses, busstr);
6765 prompt = string_compose (_("Do you really want to remove %1 %2?\n"
6766 "(You may also lose the playlists associated with the %2)\n\n"
6767 "This action cannot be undone, and the session file will be overwritten!"),
6770 } else if (nbusses) {
6771 prompt = string_compose (_("Do you really want to remove %1 %2?\n\n"
6772 "This action cannot be undone, and the session file will be overwritten"),
6776 choices.push_back (_("No, do nothing."));
6777 if (ntracks + nbusses > 1) {
6778 choices.push_back (_("Yes, remove them."));
6780 choices.push_back (_("Yes, remove it."));
6785 title = string_compose (_("Remove %1"), trackstr);
6787 title = string_compose (_("Remove %1"), busstr);
6790 Choice prompter (title, prompt, choices);
6792 if (prompter.run () != 1) {
6797 Session::StateProtector sp (_session);
6798 DisplaySuspender ds;
6799 for (vector<boost::shared_ptr<Route> >::iterator x = routes.begin(); x != routes.end(); ++x) {
6800 _session->remove_route (*x);
6806 Editor::do_insert_time ()
6808 if (selection->tracks.empty()) {
6812 InsertTimeDialog d (*this);
6813 int response = d.run ();
6815 if (response != RESPONSE_OK) {
6819 if (d.distance() == 0) {
6823 InsertTimeOption opt = d.intersected_region_action ();
6826 get_preferred_edit_position(),
6832 d.move_glued_markers(),
6833 d.move_locked_markers(),
6839 Editor::insert_time (
6840 framepos_t pos, framecnt_t frames, InsertTimeOption opt,
6841 bool all_playlists, bool ignore_music_glue, bool markers_too, bool glued_markers_too, bool locked_markers_too, bool tempo_too
6844 bool commit = false;
6846 if (Config->get_edit_mode() == Lock) {
6850 begin_reversible_command (_("insert time"));
6852 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
6854 for (TrackViewList::iterator x = ts.begin(); x != ts.end(); ++x) {
6858 /* don't operate on any playlist more than once, which could
6859 * happen if "all playlists" is enabled, but there is more
6860 * than 1 track using playlists "from" a given track.
6863 set<boost::shared_ptr<Playlist> > pl;
6865 if (all_playlists) {
6866 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*x);
6868 vector<boost::shared_ptr<Playlist> > all = _session->playlists->playlists_for_track (rtav->track ());
6869 for (vector<boost::shared_ptr<Playlist> >::iterator p = all.begin(); p != all.end(); ++p) {
6874 if ((*x)->playlist ()) {
6875 pl.insert ((*x)->playlist ());
6879 for (set<boost::shared_ptr<Playlist> >::iterator i = pl.begin(); i != pl.end(); ++i) {
6881 (*i)->clear_changes ();
6882 (*i)->clear_owned_changes ();
6884 if (opt == SplitIntersected) {
6888 (*i)->shift (pos, frames, (opt == MoveIntersected), ignore_music_glue);
6890 vector<Command*> cmds;
6892 _session->add_commands (cmds);
6894 _session->add_command (new StatefulDiffCommand (*i));
6899 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*x);
6901 rtav->route ()->shift (pos, frames);
6909 XMLNode& before (_session->locations()->get_state());
6910 Locations::LocationList copy (_session->locations()->list());
6912 for (Locations::LocationList::iterator i = copy.begin(); i != copy.end(); ++i) {
6914 Locations::LocationList::const_iterator tmp;
6916 bool const was_locked = (*i)->locked ();
6917 if (locked_markers_too) {
6921 if ((*i)->position_lock_style() == AudioTime || glued_markers_too) {
6923 if ((*i)->start() >= pos) {
6924 (*i)->set_start ((*i)->start() + frames);
6925 if (!(*i)->is_mark()) {
6926 (*i)->set_end ((*i)->end() + frames);
6939 XMLNode& after (_session->locations()->get_state());
6940 _session->add_command (new MementoCommand<Locations>(*_session->locations(), &before, &after));
6945 _session->tempo_map().insert_time (pos, frames);
6949 commit_reversible_command ();
6954 Editor::fit_selected_tracks ()
6956 if (!selection->tracks.empty()) {
6957 fit_tracks (selection->tracks);
6961 /* no selected tracks - use tracks with selected regions */
6963 if (!selection->regions.empty()) {
6964 for (RegionSelection::iterator r = selection->regions.begin(); r != selection->regions.end(); ++r) {
6965 tvl.push_back (&(*r)->get_time_axis_view ());
6971 } else if (internal_editing()) {
6972 /* no selected tracks, or regions, but in internal edit mode, so follow the mouse and use
6975 if (entered_track) {
6976 tvl.push_back (entered_track);
6985 Editor::fit_tracks (TrackViewList & tracks)
6987 if (tracks.empty()) {
6991 uint32_t child_heights = 0;
6992 int visible_tracks = 0;
6994 for (TrackSelection::iterator t = tracks.begin(); t != tracks.end(); ++t) {
6996 if (!(*t)->marked_for_display()) {
7000 child_heights += (*t)->effective_height() - (*t)->current_height();
7004 /* compute the per-track height from:
7006 total canvas visible height -
7007 height that will be taken by visible children of selected
7008 tracks - height of the ruler/hscroll area
7010 uint32_t h = (uint32_t) floor ((trackviews_height() - child_heights) / visible_tracks);
7011 double first_y_pos = DBL_MAX;
7013 if (h < TimeAxisView::preset_height (HeightSmall)) {
7014 MessageDialog msg (*this, _("There are too many tracks to fit in the current window"));
7015 /* too small to be displayed */
7019 undo_visual_stack.push_back (current_visual_state (true));
7020 no_save_visual = true;
7022 /* build a list of all tracks, including children */
7025 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
7027 TimeAxisView::Children c = (*i)->get_child_list ();
7028 for (TimeAxisView::Children::iterator j = c.begin(); j != c.end(); ++j) {
7029 all.push_back (j->get());
7033 bool prev_was_selected = false;
7034 bool is_selected = tracks.contains (all.front());
7035 bool next_is_selected;
7037 for (TrackViewList::iterator t = all.begin(); t != all.end(); ++t) {
7039 TrackViewList::iterator next;
7044 if (next != all.end()) {
7045 next_is_selected = tracks.contains (*next);
7047 next_is_selected = false;
7050 if ((*t)->marked_for_display ()) {
7052 (*t)->set_height (h);
7053 first_y_pos = std::min ((*t)->y_position (), first_y_pos);
7055 if (prev_was_selected && next_is_selected) {
7056 hide_track_in_display (*t);
7061 prev_was_selected = is_selected;
7062 is_selected = next_is_selected;
7066 set the controls_layout height now, because waiting for its size
7067 request signal handler will cause the vertical adjustment setting to fail
7070 controls_layout.property_height () = _full_canvas_height;
7071 vertical_adjustment.set_value (first_y_pos);
7073 redo_visual_stack.push_back (current_visual_state (true));
7075 visible_tracks_selector.set_text (_("Sel"));
7079 Editor::save_visual_state (uint32_t n)
7081 while (visual_states.size() <= n) {
7082 visual_states.push_back (0);
7085 if (visual_states[n] != 0) {
7086 delete visual_states[n];
7089 visual_states[n] = current_visual_state (true);
7094 Editor::goto_visual_state (uint32_t n)
7096 if (visual_states.size() <= n) {
7100 if (visual_states[n] == 0) {
7104 use_visual_state (*visual_states[n]);
7108 Editor::start_visual_state_op (uint32_t n)
7110 save_visual_state (n);
7112 PopUp* pup = new PopUp (WIN_POS_MOUSE, 1000, true);
7114 snprintf (buf, sizeof (buf), _("Saved view %u"), n+1);
7115 pup->set_text (buf);
7120 Editor::cancel_visual_state_op (uint32_t n)
7122 goto_visual_state (n);
7126 Editor::toggle_region_mute ()
7128 if (_ignore_region_action) {
7132 RegionSelection rs = get_regions_from_selection_and_entered ();
7138 if (rs.size() > 1) {
7139 begin_reversible_command (_("mute regions"));
7141 begin_reversible_command (_("mute region"));
7144 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
7146 (*i)->region()->playlist()->clear_changes ();
7147 (*i)->region()->set_muted (!(*i)->region()->muted ());
7148 _session->add_command (new StatefulDiffCommand ((*i)->region()));
7152 commit_reversible_command ();
7156 Editor::combine_regions ()
7158 /* foreach track with selected regions, take all selected regions
7159 and join them into a new region containing the subregions (as a
7163 typedef set<RouteTimeAxisView*> RTVS;
7166 if (selection->regions.empty()) {
7170 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
7171 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(&(*i)->get_time_axis_view());
7174 tracks.insert (rtv);
7178 begin_reversible_command (_("combine regions"));
7180 vector<RegionView*> new_selection;
7182 for (RTVS::iterator i = tracks.begin(); i != tracks.end(); ++i) {
7185 if ((rv = (*i)->combine_regions ()) != 0) {
7186 new_selection.push_back (rv);
7190 selection->clear_regions ();
7191 for (vector<RegionView*>::iterator i = new_selection.begin(); i != new_selection.end(); ++i) {
7192 selection->add (*i);
7195 commit_reversible_command ();
7199 Editor::uncombine_regions ()
7201 typedef set<RouteTimeAxisView*> RTVS;
7204 if (selection->regions.empty()) {
7208 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
7209 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(&(*i)->get_time_axis_view());
7212 tracks.insert (rtv);
7216 begin_reversible_command (_("uncombine regions"));
7218 for (RTVS::iterator i = tracks.begin(); i != tracks.end(); ++i) {
7219 (*i)->uncombine_regions ();
7222 commit_reversible_command ();
7226 Editor::toggle_midi_input_active (bool flip_others)
7229 boost::shared_ptr<RouteList> rl (new RouteList);
7231 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
7232 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
7238 boost::shared_ptr<MidiTrack> mt = rtav->midi_track();
7241 rl->push_back (rtav->route());
7242 onoff = !mt->input_active();
7246 _session->set_exclusive_input_active (rl, onoff, flip_others);
7253 lock_dialog = new Gtk::Dialog (string_compose (_("%1: Locked"), PROGRAM_NAME), true);
7255 Gtk::Image* padlock = manage (new Gtk::Image (ARDOUR_UI_UTILS::get_icon ("padlock_closed")));
7256 lock_dialog->get_vbox()->pack_start (*padlock);
7258 ArdourButton* b = manage (new ArdourButton);
7259 b->set_name ("lock button");
7260 b->set_text (_("Click to unlock"));
7261 b->signal_clicked.connect (sigc::mem_fun (*this, &Editor::unlock));
7262 lock_dialog->get_vbox()->pack_start (*b);
7264 lock_dialog->get_vbox()->show_all ();
7265 lock_dialog->set_size_request (200, 200);
7269 /* The global menu bar continues to be accessible to applications
7270 with modal dialogs, which means that we need to desensitize
7271 all items in the menu bar. Since those items are really just
7272 proxies for actions, that means disabling all actions.
7274 ActionManager::disable_all_actions ();
7276 lock_dialog->present ();
7282 lock_dialog->hide ();
7285 ActionManager::pop_action_state ();
7288 if (ARDOUR_UI::config()->get_lock_gui_after_seconds()) {
7289 start_lock_event_timing ();
7294 Editor::bring_in_callback (Gtk::Label* label, uint32_t n, uint32_t total, string name)
7296 Gtkmm2ext::UI::instance()->call_slot (invalidator (*this), boost::bind (&Editor::update_bring_in_message, this, label, n, total, name));
7300 Editor::update_bring_in_message (Gtk::Label* label, uint32_t n, uint32_t total, string name)
7302 label->set_text (string_compose ("Copying %1, %2 of %3", name, n, total));
7303 Gtkmm2ext::UI::instance()->flush_pending ();
7307 Editor::bring_all_sources_into_session ()
7314 ArdourDialog w (_("Moving embedded files into session folder"));
7315 w.get_vbox()->pack_start (msg);
7318 /* flush all pending GUI events because we're about to start copying
7322 Gtkmm2ext::UI::instance()->flush_pending ();
7326 _session->bring_all_sources_into_session (boost::bind (&Editor::bring_in_callback, this, &msg, _1, _2, _3));