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/region_factory.h"
54 #include "ardour/reverse.h"
55 #include "ardour/session.h"
56 #include "ardour/session_playlists.h"
57 #include "ardour/strip_silence.h"
58 #include "ardour/transient_detector.h"
60 #include "canvas/canvas.h"
63 #include "ardour_ui.h"
64 #include "audio_region_view.h"
65 #include "audio_streamview.h"
66 #include "audio_time_axis.h"
67 #include "automation_region_view.h"
68 #include "automation_time_axis.h"
69 #include "control_point.h"
73 #include "editor_cursors.h"
74 #include "editor_drag.h"
75 #include "editor_regions.h"
76 #include "editor_routes.h"
77 #include "gui_thread.h"
78 #include "insert_time_dialog.h"
79 #include "interthread_progress_window.h"
80 #include "item_counts.h"
82 #include "midi_region_view.h"
83 #include "mixer_strip.h"
84 #include "mouse_cursors.h"
85 #include "normalize_dialog.h"
86 #include "patch_change_dialog.h"
87 #include "quantize_dialog.h"
88 #include "region_gain_line.h"
89 #include "rgb_macros.h"
90 #include "route_time_axis.h"
91 #include "selection.h"
92 #include "selection_templates.h"
93 #include "streamview.h"
94 #include "strip_silence_dialog.h"
95 #include "time_axis_view.h"
96 #include "transpose_dialog.h"
101 using namespace ARDOUR;
104 using namespace Gtkmm2ext;
105 using namespace Editing;
106 using Gtkmm2ext::Keyboard;
108 /***********************************************************************
110 ***********************************************************************/
113 Editor::undo (uint32_t n)
115 if (_drags->active ()) {
125 Editor::redo (uint32_t n)
127 if (_drags->active ()) {
137 Editor::split_regions_at (framepos_t where, RegionSelection& regions)
141 RegionSelection pre_selected_regions = selection->regions;
142 bool working_on_selection = !pre_selected_regions.empty();
144 list<boost::shared_ptr<Playlist> > used_playlists;
145 list<RouteTimeAxisView*> used_trackviews;
147 if (regions.empty()) {
151 begin_reversible_command (_("split"));
153 // if splitting a single region, and snap-to is using
154 // region boundaries, don't pay attention to them
156 if (regions.size() == 1) {
157 switch (_snap_type) {
158 case SnapToRegionStart:
159 case SnapToRegionSync:
160 case SnapToRegionEnd:
169 EditorFreeze(); /* Emit Signal */
172 for (RegionSelection::iterator a = regions.begin(); a != regions.end(); ) {
174 RegionSelection::iterator tmp;
176 /* XXX this test needs to be more complicated, to make sure we really
177 have something to split.
180 if (!(*a)->region()->covers (where)) {
188 boost::shared_ptr<Playlist> pl = (*a)->region()->playlist();
196 /* we haven't seen this playlist before */
198 /* remember used playlists so we can thaw them later */
199 used_playlists.push_back(pl);
201 TimeAxisView& tv = (*a)->get_time_axis_view();
202 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (&tv);
204 used_trackviews.push_back (rtv);
211 pl->clear_changes ();
212 pl->split_region ((*a)->region(), where);
213 _session->add_command (new StatefulDiffCommand (pl));
219 vector<sigc::connection> region_added_connections;
221 for (list<RouteTimeAxisView*>::iterator i = used_trackviews.begin(); i != used_trackviews.end(); ++i) {
222 region_added_connections.push_back ((*i)->view()->RegionViewAdded.connect (sigc::mem_fun(*this, &Editor::collect_new_region_view)));
225 latest_regionviews.clear ();
227 while (used_playlists.size() > 0) {
228 list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
230 used_playlists.pop_front();
233 for (vector<sigc::connection>::iterator c = region_added_connections.begin(); c != region_added_connections.end(); ++c) {
237 commit_reversible_command ();
240 EditorThaw(); /* Emit Signal */
243 if (ARDOUR::Profile->get_mixbus()) {
244 //IFF we were working on selected regions, try to reinstate the other region selections that existed before the freeze/thaw.
245 _ignore_follow_edits = true; //a split will change the region selection in mysterious ways; its not practical or wanted to follow this edit
246 if( working_on_selection ) {
247 selection->add ( pre_selected_regions );
248 selection->add (latest_regionviews); //these are the new regions created after the split
250 _ignore_follow_edits = false;
254 /** Move one extreme of the current range selection. If more than one range is selected,
255 * the start of the earliest range or the end of the latest range is moved.
257 * @param move_end true to move the end of the current range selection, false to move
259 * @param next true to move the extreme to the next region boundary, false to move to
263 Editor::move_range_selection_start_or_end_to_region_boundary (bool move_end, bool next)
265 if (selection->time.start() == selection->time.end_frame()) {
269 framepos_t start = selection->time.start ();
270 framepos_t end = selection->time.end_frame ();
272 /* the position of the thing we may move */
273 framepos_t pos = move_end ? end : start;
274 int dir = next ? 1 : -1;
276 /* so we don't find the current region again */
277 if (dir > 0 || pos > 0) {
281 framepos_t const target = get_region_boundary (pos, dir, true, false);
296 begin_reversible_command (_("alter selection"));
297 selection->set_preserving_all_ranges (start, end);
298 commit_reversible_command ();
302 Editor::nudge_forward_release (GdkEventButton* ev)
304 if (ev->state & Keyboard::PrimaryModifier) {
305 nudge_forward (false, true);
307 nudge_forward (false, false);
313 Editor::nudge_backward_release (GdkEventButton* ev)
315 if (ev->state & Keyboard::PrimaryModifier) {
316 nudge_backward (false, true);
318 nudge_backward (false, false);
325 Editor::nudge_forward (bool next, bool force_playhead)
328 framepos_t next_distance;
334 RegionSelection rs = get_regions_from_selection_and_entered ();
336 if (!force_playhead && !rs.empty()) {
338 begin_reversible_command (_("nudge regions forward"));
340 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
341 boost::shared_ptr<Region> r ((*i)->region());
343 distance = get_nudge_distance (r->position(), next_distance);
346 distance = next_distance;
350 r->set_position (r->position() + distance);
351 _session->add_command (new StatefulDiffCommand (r));
354 commit_reversible_command ();
357 } else if (!force_playhead && !selection->markers.empty()) {
361 begin_reversible_command (_("nudge location forward"));
363 for (MarkerSelection::iterator i = selection->markers.begin(); i != selection->markers.end(); ++i) {
365 Location* loc = find_location_from_marker ((*i), is_start);
369 XMLNode& before (loc->get_state());
372 distance = get_nudge_distance (loc->start(), next_distance);
374 distance = next_distance;
376 if (max_framepos - distance > loc->start() + loc->length()) {
377 loc->set_start (loc->start() + distance);
379 loc->set_start (max_framepos - loc->length());
382 distance = get_nudge_distance (loc->end(), next_distance);
384 distance = next_distance;
386 if (max_framepos - distance > loc->end()) {
387 loc->set_end (loc->end() + distance);
389 loc->set_end (max_framepos);
392 XMLNode& after (loc->get_state());
393 _session->add_command (new MementoCommand<Location>(*loc, &before, &after));
397 commit_reversible_command ();
400 distance = get_nudge_distance (playhead_cursor->current_frame (), next_distance);
401 _session->request_locate (playhead_cursor->current_frame () + distance);
406 Editor::nudge_backward (bool next, bool force_playhead)
409 framepos_t next_distance;
415 RegionSelection rs = get_regions_from_selection_and_entered ();
417 if (!force_playhead && !rs.empty()) {
419 begin_reversible_command (_("nudge regions backward"));
421 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
422 boost::shared_ptr<Region> r ((*i)->region());
424 distance = get_nudge_distance (r->position(), next_distance);
427 distance = next_distance;
432 if (r->position() > distance) {
433 r->set_position (r->position() - distance);
437 _session->add_command (new StatefulDiffCommand (r));
440 commit_reversible_command ();
442 } else if (!force_playhead && !selection->markers.empty()) {
446 begin_reversible_command (_("nudge location forward"));
448 for (MarkerSelection::iterator i = selection->markers.begin(); i != selection->markers.end(); ++i) {
450 Location* loc = find_location_from_marker ((*i), is_start);
454 XMLNode& before (loc->get_state());
457 distance = get_nudge_distance (loc->start(), next_distance);
459 distance = next_distance;
461 if (distance < loc->start()) {
462 loc->set_start (loc->start() - distance);
467 distance = get_nudge_distance (loc->end(), next_distance);
470 distance = next_distance;
473 if (distance < loc->end() - loc->length()) {
474 loc->set_end (loc->end() - distance);
476 loc->set_end (loc->length());
480 XMLNode& after (loc->get_state());
481 _session->add_command (new MementoCommand<Location>(*loc, &before, &after));
485 commit_reversible_command ();
489 distance = get_nudge_distance (playhead_cursor->current_frame (), next_distance);
491 if (playhead_cursor->current_frame () > distance) {
492 _session->request_locate (playhead_cursor->current_frame () - distance);
494 _session->goto_start();
500 Editor::nudge_forward_capture_offset ()
502 RegionSelection rs = get_regions_from_selection_and_entered ();
504 if (!_session || rs.empty()) {
508 begin_reversible_command (_("nudge forward"));
510 framepos_t const distance = _session->worst_output_latency();
512 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
513 boost::shared_ptr<Region> r ((*i)->region());
516 r->set_position (r->position() + distance);
517 _session->add_command(new StatefulDiffCommand (r));
520 commit_reversible_command ();
524 Editor::nudge_backward_capture_offset ()
526 RegionSelection rs = get_regions_from_selection_and_entered ();
528 if (!_session || rs.empty()) {
532 begin_reversible_command (_("nudge backward"));
534 framepos_t const distance = _session->worst_output_latency();
536 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
537 boost::shared_ptr<Region> r ((*i)->region());
541 if (r->position() > distance) {
542 r->set_position (r->position() - distance);
546 _session->add_command(new StatefulDiffCommand (r));
549 commit_reversible_command ();
552 struct RegionSelectionPositionSorter {
553 bool operator() (RegionView* a, RegionView* b) {
554 return a->region()->position() < b->region()->position();
559 Editor::sequence_regions ()
562 framepos_t r_end_prev;
570 RegionSelection rs = get_regions_from_selection_and_entered ();
571 rs.sort(RegionSelectionPositionSorter());
575 begin_reversible_command (_("sequence regions"));
576 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
577 boost::shared_ptr<Region> r ((*i)->region());
585 if(r->position_locked())
592 r->set_position(r_end_prev);
595 _session->add_command (new StatefulDiffCommand (r));
597 r_end=r->position() + r->length();
601 commit_reversible_command ();
609 Editor::move_to_start ()
611 _session->goto_start ();
615 Editor::move_to_end ()
618 _session->request_locate (_session->current_end_frame());
622 Editor::build_region_boundary_cache ()
625 vector<RegionPoint> interesting_points;
626 boost::shared_ptr<Region> r;
627 TrackViewList tracks;
630 region_boundary_cache.clear ();
636 switch (_snap_type) {
637 case SnapToRegionStart:
638 interesting_points.push_back (Start);
640 case SnapToRegionEnd:
641 interesting_points.push_back (End);
643 case SnapToRegionSync:
644 interesting_points.push_back (SyncPoint);
646 case SnapToRegionBoundary:
647 interesting_points.push_back (Start);
648 interesting_points.push_back (End);
651 fatal << string_compose (_("build_region_boundary_cache called with snap_type = %1"), _snap_type) << endmsg;
652 abort(); /*NOTREACHED*/
656 TimeAxisView *ontrack = 0;
659 if (!selection->tracks.empty()) {
660 tlist = selection->tracks.filter_to_unique_playlists ();
662 tlist = track_views.filter_to_unique_playlists ();
665 while (pos < _session->current_end_frame() && !at_end) {
668 framepos_t lpos = max_framepos;
670 for (vector<RegionPoint>::iterator p = interesting_points.begin(); p != interesting_points.end(); ++p) {
672 if ((r = find_next_region (pos, *p, 1, tlist, &ontrack)) == 0) {
673 if (*p == interesting_points.back()) {
676 /* move to next point type */
682 rpos = r->first_frame();
686 rpos = r->last_frame();
690 rpos = r->sync_position ();
698 RouteTimeAxisView *rtav;
700 if (ontrack != 0 && (rtav = dynamic_cast<RouteTimeAxisView*>(ontrack)) != 0 ) {
701 if (rtav->track() != 0) {
702 speed = rtav->track()->speed();
706 rpos = track_frame_to_session_frame (rpos, speed);
712 /* prevent duplicates, but we don't use set<> because we want to be able
716 vector<framepos_t>::iterator ri;
718 for (ri = region_boundary_cache.begin(); ri != region_boundary_cache.end(); ++ri) {
724 if (ri == region_boundary_cache.end()) {
725 region_boundary_cache.push_back (rpos);
732 /* finally sort to be sure that the order is correct */
734 sort (region_boundary_cache.begin(), region_boundary_cache.end());
737 boost::shared_ptr<Region>
738 Editor::find_next_region (framepos_t frame, RegionPoint point, int32_t dir, TrackViewList& tracks, TimeAxisView **ontrack)
740 TrackViewList::iterator i;
741 framepos_t closest = max_framepos;
742 boost::shared_ptr<Region> ret;
746 framepos_t track_frame;
747 RouteTimeAxisView *rtav;
749 for (i = tracks.begin(); i != tracks.end(); ++i) {
752 boost::shared_ptr<Region> r;
755 if ( (rtav = dynamic_cast<RouteTimeAxisView*>(*i)) != 0 ) {
756 if (rtav->track()!=0)
757 track_speed = rtav->track()->speed();
760 track_frame = session_frame_to_track_frame(frame, track_speed);
762 if ((r = (*i)->find_next_region (track_frame, point, dir)) == 0) {
768 rpos = r->first_frame ();
772 rpos = r->last_frame ();
776 rpos = r->sync_position ();
780 // rpos is a "track frame", converting it to "_session frame"
781 rpos = track_frame_to_session_frame(rpos, track_speed);
784 distance = rpos - frame;
786 distance = frame - rpos;
789 if (distance < closest) {
801 Editor::find_next_region_boundary (framepos_t pos, int32_t dir, const TrackViewList& tracks)
803 framecnt_t distance = max_framepos;
804 framepos_t current_nearest = -1;
806 for (TrackViewList::const_iterator i = tracks.begin(); i != tracks.end(); ++i) {
807 framepos_t contender;
810 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*i);
816 if ((contender = rtv->find_next_region_boundary (pos, dir)) < 0) {
820 d = ::llabs (pos - contender);
823 current_nearest = contender;
828 return current_nearest;
832 Editor::get_region_boundary (framepos_t pos, int32_t dir, bool with_selection, bool only_onscreen)
837 if (with_selection && Config->get_region_boundaries_from_selected_tracks()) {
839 if (!selection->tracks.empty()) {
841 target = find_next_region_boundary (pos, dir, selection->tracks);
845 if (only_onscreen || Config->get_region_boundaries_from_onscreen_tracks()) {
846 get_onscreen_tracks (tvl);
847 target = find_next_region_boundary (pos, dir, tvl);
849 target = find_next_region_boundary (pos, dir, track_views);
855 if (only_onscreen || Config->get_region_boundaries_from_onscreen_tracks()) {
856 get_onscreen_tracks (tvl);
857 target = find_next_region_boundary (pos, dir, tvl);
859 target = find_next_region_boundary (pos, dir, track_views);
867 Editor::cursor_to_region_boundary (bool with_selection, int32_t dir)
869 framepos_t pos = playhead_cursor->current_frame ();
876 // so we don't find the current region again..
877 if (dir > 0 || pos > 0) {
881 if ((target = get_region_boundary (pos, dir, with_selection, false)) < 0) {
885 _session->request_locate (target);
889 Editor::cursor_to_next_region_boundary (bool with_selection)
891 cursor_to_region_boundary (with_selection, 1);
895 Editor::cursor_to_previous_region_boundary (bool with_selection)
897 cursor_to_region_boundary (with_selection, -1);
901 Editor::cursor_to_region_point (EditorCursor* cursor, RegionPoint point, int32_t dir)
903 boost::shared_ptr<Region> r;
904 framepos_t pos = cursor->current_frame ();
910 TimeAxisView *ontrack = 0;
912 // so we don't find the current region again..
916 if (!selection->tracks.empty()) {
918 r = find_next_region (pos, point, dir, selection->tracks, &ontrack);
920 } else if (clicked_axisview) {
923 t.push_back (clicked_axisview);
925 r = find_next_region (pos, point, dir, t, &ontrack);
929 r = find_next_region (pos, point, dir, track_views, &ontrack);
938 pos = r->first_frame ();
942 pos = r->last_frame ();
946 pos = r->sync_position ();
951 RouteTimeAxisView *rtav;
953 if ( ontrack != 0 && (rtav = dynamic_cast<RouteTimeAxisView*>(ontrack)) != 0 ) {
954 if (rtav->track() != 0) {
955 speed = rtav->track()->speed();
959 pos = track_frame_to_session_frame(pos, speed);
961 if (cursor == playhead_cursor) {
962 _session->request_locate (pos);
964 cursor->set_position (pos);
969 Editor::cursor_to_next_region_point (EditorCursor* cursor, RegionPoint point)
971 cursor_to_region_point (cursor, point, 1);
975 Editor::cursor_to_previous_region_point (EditorCursor* cursor, RegionPoint point)
977 cursor_to_region_point (cursor, point, -1);
981 Editor::cursor_to_selection_start (EditorCursor *cursor)
985 switch (mouse_mode) {
987 if (!selection->regions.empty()) {
988 pos = selection->regions.start();
993 if (!selection->time.empty()) {
994 pos = selection->time.start ();
1002 if (cursor == playhead_cursor) {
1003 _session->request_locate (pos);
1005 cursor->set_position (pos);
1010 Editor::cursor_to_selection_end (EditorCursor *cursor)
1014 switch (mouse_mode) {
1016 if (!selection->regions.empty()) {
1017 pos = selection->regions.end_frame();
1022 if (!selection->time.empty()) {
1023 pos = selection->time.end_frame ();
1031 if (cursor == playhead_cursor) {
1032 _session->request_locate (pos);
1034 cursor->set_position (pos);
1039 Editor::selected_marker_to_region_boundary (bool with_selection, int32_t dir)
1049 if (selection->markers.empty()) {
1053 if (!mouse_frame (mouse, ignored)) {
1057 add_location_mark (mouse);
1060 if ((loc = find_location_from_marker (selection->markers.front(), ignored)) == 0) {
1064 framepos_t pos = loc->start();
1066 // so we don't find the current region again..
1067 if (dir > 0 || pos > 0) {
1071 if ((target = get_region_boundary (pos, dir, with_selection, false)) < 0) {
1075 loc->move_to (target);
1079 Editor::selected_marker_to_next_region_boundary (bool with_selection)
1081 selected_marker_to_region_boundary (with_selection, 1);
1085 Editor::selected_marker_to_previous_region_boundary (bool with_selection)
1087 selected_marker_to_region_boundary (with_selection, -1);
1091 Editor::selected_marker_to_region_point (RegionPoint point, int32_t dir)
1093 boost::shared_ptr<Region> r;
1098 if (!_session || selection->markers.empty()) {
1102 if ((loc = find_location_from_marker (selection->markers.front(), ignored)) == 0) {
1106 TimeAxisView *ontrack = 0;
1110 // so we don't find the current region again..
1114 if (!selection->tracks.empty()) {
1116 r = find_next_region (pos, point, dir, selection->tracks, &ontrack);
1120 r = find_next_region (pos, point, dir, track_views, &ontrack);
1129 pos = r->first_frame ();
1133 pos = r->last_frame ();
1137 pos = r->adjust_to_sync (r->first_frame());
1142 RouteTimeAxisView *rtav;
1144 if (ontrack != 0 && (rtav = dynamic_cast<RouteTimeAxisView*>(ontrack)) != 0) {
1145 if (rtav->track() != 0) {
1146 speed = rtav->track()->speed();
1150 pos = track_frame_to_session_frame(pos, speed);
1156 Editor::selected_marker_to_next_region_point (RegionPoint point)
1158 selected_marker_to_region_point (point, 1);
1162 Editor::selected_marker_to_previous_region_point (RegionPoint point)
1164 selected_marker_to_region_point (point, -1);
1168 Editor::selected_marker_to_selection_start ()
1174 if (!_session || selection->markers.empty()) {
1178 if ((loc = find_location_from_marker (selection->markers.front(), ignored)) == 0) {
1182 switch (mouse_mode) {
1184 if (!selection->regions.empty()) {
1185 pos = selection->regions.start();
1190 if (!selection->time.empty()) {
1191 pos = selection->time.start ();
1203 Editor::selected_marker_to_selection_end ()
1209 if (!_session || selection->markers.empty()) {
1213 if ((loc = find_location_from_marker (selection->markers.front(), ignored)) == 0) {
1217 switch (mouse_mode) {
1219 if (!selection->regions.empty()) {
1220 pos = selection->regions.end_frame();
1225 if (!selection->time.empty()) {
1226 pos = selection->time.end_frame ();
1238 Editor::scroll_playhead (bool forward)
1240 framepos_t pos = playhead_cursor->current_frame ();
1241 framecnt_t delta = (framecnt_t) floor (current_page_samples() / 0.8);
1244 if (pos == max_framepos) {
1248 if (pos < max_framepos - delta) {
1267 _session->request_locate (pos);
1271 Editor::cursor_align (bool playhead_to_edit)
1277 if (playhead_to_edit) {
1279 if (selection->markers.empty()) {
1283 _session->request_locate (selection->markers.front()->position(), _session->transport_rolling());
1286 /* move selected markers to playhead */
1288 for (MarkerSelection::iterator i = selection->markers.begin(); i != selection->markers.end(); ++i) {
1291 Location* loc = find_location_from_marker (*i, ignored);
1293 if (loc->is_mark()) {
1294 loc->set_start (playhead_cursor->current_frame ());
1296 loc->set (playhead_cursor->current_frame (),
1297 playhead_cursor->current_frame () + loc->length());
1304 Editor::scroll_backward (float pages)
1306 framepos_t const one_page = (framepos_t) rint (_visible_canvas_width * samples_per_pixel);
1307 framepos_t const cnt = (framepos_t) floor (pages * one_page);
1310 if (leftmost_frame < cnt) {
1313 frame = leftmost_frame - cnt;
1316 reset_x_origin (frame);
1320 Editor::scroll_forward (float pages)
1322 framepos_t const one_page = (framepos_t) rint (_visible_canvas_width * samples_per_pixel);
1323 framepos_t const cnt = (framepos_t) floor (pages * one_page);
1326 if (max_framepos - cnt < leftmost_frame) {
1327 frame = max_framepos - cnt;
1329 frame = leftmost_frame + cnt;
1332 reset_x_origin (frame);
1336 Editor::scroll_tracks_down ()
1338 double vert_value = vertical_adjustment.get_value() + vertical_adjustment.get_page_size();
1339 if (vert_value > vertical_adjustment.get_upper() - _visible_canvas_height) {
1340 vert_value = vertical_adjustment.get_upper() - _visible_canvas_height;
1343 vertical_adjustment.set_value (vert_value);
1347 Editor::scroll_tracks_up ()
1349 vertical_adjustment.set_value (vertical_adjustment.get_value() - vertical_adjustment.get_page_size());
1353 Editor::scroll_tracks_down_line ()
1355 double vert_value = vertical_adjustment.get_value() + 60;
1357 if (vert_value > vertical_adjustment.get_upper() - _visible_canvas_height) {
1358 vert_value = vertical_adjustment.get_upper() - _visible_canvas_height;
1361 vertical_adjustment.set_value (vert_value);
1365 Editor::scroll_tracks_up_line ()
1367 reset_y_origin (vertical_adjustment.get_value() - 60);
1371 Editor::scroll_down_one_track ()
1373 TrackViewList::reverse_iterator next = track_views.rend();
1374 std::pair<TimeAxisView*,double> res;
1375 const double top_of_trackviews = vertical_adjustment.get_value();
1377 for (TrackViewList::reverse_iterator t = track_views.rbegin(); t != track_views.rend(); ++t) {
1378 if ((*t)->hidden()) {
1383 /* If this is the upper-most visible trackview, we want to display
1384 the one above it (next)
1387 res = (*t)->covers_y_position (top_of_trackviews);
1395 /* move to the track below the first one that covers the */
1397 if (next != track_views.rend()) {
1398 ensure_time_axis_view_is_visible (**next, true);
1406 Editor::scroll_up_one_track ()
1408 TrackViewList::iterator prev = track_views.end();
1409 std::pair<TimeAxisView*,double> res;
1410 double top_of_trackviews = vertical_adjustment.get_value ();
1412 for (TrackViewList::iterator t = track_views.begin(); t != track_views.end(); ++t) {
1414 if ((*t)->hidden()) {
1418 /* find the trackview at the top of the trackview group */
1419 res = (*t)->covers_y_position (top_of_trackviews);
1428 if (prev != track_views.end()) {
1429 ensure_time_axis_view_is_visible (**prev, true);
1439 Editor::tav_zoom_step (bool coarser)
1441 DisplaySuspender ds;
1445 if (selection->tracks.empty()) {
1448 ts = &selection->tracks;
1451 for (TrackViewList::iterator i = ts->begin(); i != ts->end(); ++i) {
1452 TimeAxisView *tv = (static_cast<TimeAxisView*>(*i));
1453 tv->step_height (coarser);
1458 Editor::tav_zoom_smooth (bool coarser, bool force_all)
1460 DisplaySuspender ds;
1464 if (selection->tracks.empty() || force_all) {
1467 ts = &selection->tracks;
1470 for (TrackViewList::iterator i = ts->begin(); i != ts->end(); ++i) {
1471 TimeAxisView *tv = (static_cast<TimeAxisView*>(*i));
1472 uint32_t h = tv->current_height ();
1477 if (h >= TimeAxisView::preset_height (HeightSmall)) {
1482 tv->set_height (h + 5);
1489 Editor::temporal_zoom_step (bool coarser)
1491 ENSURE_GUI_THREAD (*this, &Editor::temporal_zoom_step, coarser)
1493 framecnt_t nspp = samples_per_pixel;
1501 temporal_zoom (nspp);
1505 Editor::temporal_zoom (framecnt_t fpp)
1511 framepos_t current_page = current_page_samples();
1512 framepos_t current_leftmost = leftmost_frame;
1513 framepos_t current_rightmost;
1514 framepos_t current_center;
1515 framepos_t new_page_size;
1516 framepos_t half_page_size;
1517 framepos_t leftmost_after_zoom = 0;
1519 bool in_track_canvas;
1523 if (fpp == samples_per_pixel) {
1527 // Imposing an arbitrary limit to zoom out as too much zoom out produces
1528 // segfaults for lack of memory. If somebody decides this is not high enough I
1529 // believe it can be raisen to higher values but some limit must be in place.
1531 // This constant represents 1 day @ 48kHz on a 1600 pixel wide display
1532 // all of which is used for the editor track displays. The whole day
1533 // would be 4147200000 samples, so 2592000 samples per pixel.
1535 nfpp = min (fpp, (framecnt_t) 2592000);
1536 nfpp = max ((framecnt_t) 1, fpp);
1538 new_page_size = (framepos_t) floor (_visible_canvas_width * nfpp);
1539 half_page_size = new_page_size / 2;
1541 switch (zoom_focus) {
1543 leftmost_after_zoom = current_leftmost;
1546 case ZoomFocusRight:
1547 current_rightmost = leftmost_frame + current_page;
1548 if (current_rightmost < new_page_size) {
1549 leftmost_after_zoom = 0;
1551 leftmost_after_zoom = current_rightmost - new_page_size;
1555 case ZoomFocusCenter:
1556 current_center = current_leftmost + (current_page/2);
1557 if (current_center < half_page_size) {
1558 leftmost_after_zoom = 0;
1560 leftmost_after_zoom = current_center - half_page_size;
1564 case ZoomFocusPlayhead:
1565 /* centre playhead */
1566 l = playhead_cursor->current_frame () - (new_page_size * 0.5);
1569 leftmost_after_zoom = 0;
1570 } else if (l > max_framepos) {
1571 leftmost_after_zoom = max_framepos - new_page_size;
1573 leftmost_after_zoom = (framepos_t) l;
1577 case ZoomFocusMouse:
1578 /* try to keep the mouse over the same point in the display */
1580 if (!mouse_frame (where, in_track_canvas)) {
1581 /* use playhead instead */
1582 where = playhead_cursor->current_frame ();
1584 if (where < half_page_size) {
1585 leftmost_after_zoom = 0;
1587 leftmost_after_zoom = where - half_page_size;
1592 l = - ((new_page_size * ((where - current_leftmost)/(double)current_page)) - where);
1595 leftmost_after_zoom = 0;
1596 } else if (l > max_framepos) {
1597 leftmost_after_zoom = max_framepos - new_page_size;
1599 leftmost_after_zoom = (framepos_t) l;
1606 /* try to keep the edit point in the same place */
1607 where = get_preferred_edit_position ();
1611 double l = - ((new_page_size * ((where - current_leftmost)/(double)current_page)) - where);
1614 leftmost_after_zoom = 0;
1615 } else if (l > max_framepos) {
1616 leftmost_after_zoom = max_framepos - new_page_size;
1618 leftmost_after_zoom = (framepos_t) l;
1622 /* edit point not defined */
1629 // leftmost_after_zoom = min (leftmost_after_zoom, _session->current_end_frame());
1631 reposition_and_zoom (leftmost_after_zoom, nfpp);
1635 Editor::calc_extra_zoom_edges(framepos_t &start, framepos_t &end)
1637 /* this func helps make sure we leave a little space
1638 at each end of the editor so that the zoom doesn't fit the region
1639 precisely to the screen.
1642 GdkScreen* screen = gdk_screen_get_default ();
1643 const gint pixwidth = gdk_screen_get_width (screen);
1644 const gint mmwidth = gdk_screen_get_width_mm (screen);
1645 const double pix_per_mm = (double) pixwidth/ (double) mmwidth;
1646 const double one_centimeter_in_pixels = pix_per_mm * 10.0;
1648 const framepos_t range = end - start;
1649 const framecnt_t new_fpp = (framecnt_t) ceil ((double) range / (double) _visible_canvas_width);
1650 const framepos_t extra_samples = (framepos_t) floor (one_centimeter_in_pixels * new_fpp);
1652 if (start > extra_samples) {
1653 start -= extra_samples;
1658 if (max_framepos - extra_samples > end) {
1659 end += extra_samples;
1666 Editor::temporal_zoom_region (bool both_axes)
1668 framepos_t start = max_framepos;
1670 set<TimeAxisView*> tracks;
1672 RegionSelection rs = get_regions_from_selection_and_entered ();
1678 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
1680 if ((*i)->region()->position() < start) {
1681 start = (*i)->region()->position();
1684 if ((*i)->region()->last_frame() + 1 > end) {
1685 end = (*i)->region()->last_frame() + 1;
1688 tracks.insert (&((*i)->get_time_axis_view()));
1691 if ((start == 0 && end == 0) || end < start) {
1695 calc_extra_zoom_edges (start, end);
1697 /* if we're zooming on both axes we need to save track heights etc.
1700 undo_visual_stack.push_back (current_visual_state (both_axes));
1702 PBD::Unwinder<bool> nsv (no_save_visual, true);
1704 temporal_zoom_by_frame (start, end);
1707 uint32_t per_track_height = (uint32_t) floor ((_visible_canvas_height - 10.0) / tracks.size());
1709 /* set visible track heights appropriately */
1711 for (set<TimeAxisView*>::iterator t = tracks.begin(); t != tracks.end(); ++t) {
1712 (*t)->set_height (per_track_height);
1715 /* hide irrelevant tracks */
1717 DisplaySuspender ds;
1719 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1720 if (find (tracks.begin(), tracks.end(), (*i)) == tracks.end()) {
1721 hide_track_in_display (*i);
1725 vertical_adjustment.set_value (0.0);
1728 redo_visual_stack.push_back (current_visual_state (both_axes));
1732 Editor::zoom_to_region (bool both_axes)
1734 temporal_zoom_region (both_axes);
1738 Editor::temporal_zoom_selection (bool both_axes)
1740 if (!selection) return;
1742 //if a range is selected, zoom to that
1743 if (!selection->time.empty()) {
1745 framepos_t start = selection->time.start();
1746 framepos_t end = selection->time.end_frame();
1748 calc_extra_zoom_edges(start, end);
1750 temporal_zoom_by_frame (start, end);
1753 fit_selected_tracks();
1756 temporal_zoom_region (both_axes);
1763 Editor::temporal_zoom_session ()
1765 ENSURE_GUI_THREAD (*this, &Editor::temporal_zoom_session)
1768 framecnt_t start = _session->current_start_frame();
1769 framecnt_t end = _session->current_end_frame();
1771 if (_session->actively_recording () ) {
1772 framepos_t cur = playhead_cursor->current_frame ();
1774 /* recording beyond the end marker; zoom out
1775 * by 5 seconds more so that if 'follow
1776 * playhead' is active we don't immediately
1779 end = cur + _session->frame_rate() * 5;
1783 if ((start == 0 && end == 0) || end < start) {
1787 calc_extra_zoom_edges(start, end);
1789 temporal_zoom_by_frame (start, end);
1794 Editor::temporal_zoom_by_frame (framepos_t start, framepos_t end)
1796 if (!_session) return;
1798 if ((start == 0 && end == 0) || end < start) {
1802 framepos_t range = end - start;
1804 const framecnt_t new_fpp = (framecnt_t) ceil ((double) range / (double) _visible_canvas_width);
1806 framepos_t new_page = range;
1807 framepos_t middle = (framepos_t) floor ((double) start + ((double) range / 2.0f));
1808 framepos_t new_leftmost = (framepos_t) floor ((double) middle - ((double) new_page / 2.0f));
1810 if (new_leftmost > middle) {
1814 if (new_leftmost < 0) {
1818 reposition_and_zoom (new_leftmost, new_fpp);
1822 Editor::temporal_zoom_to_frame (bool coarser, framepos_t frame)
1828 framecnt_t range_before = frame - leftmost_frame;
1832 if (samples_per_pixel <= 1) {
1835 new_spp = samples_per_pixel + (samples_per_pixel/2);
1837 range_before += range_before/2;
1839 if (samples_per_pixel >= 1) {
1840 new_spp = samples_per_pixel - (samples_per_pixel/2);
1842 /* could bail out here since we cannot zoom any finer,
1843 but leave that to the equality test below
1845 new_spp = samples_per_pixel;
1848 range_before -= range_before/2;
1851 if (new_spp == samples_per_pixel) {
1855 /* zoom focus is automatically taken as @param frame when this
1859 framepos_t new_leftmost = frame - (framepos_t)range_before;
1861 if (new_leftmost > frame) {
1865 if (new_leftmost < 0) {
1869 reposition_and_zoom (new_leftmost, new_spp);
1874 Editor::choose_new_marker_name(string &name) {
1876 if (!Config->get_name_new_markers()) {
1877 /* don't prompt user for a new name */
1881 ArdourPrompter dialog (true);
1883 dialog.set_prompt (_("New Name:"));
1885 dialog.set_title (_("New Location Marker"));
1887 dialog.set_name ("MarkNameWindow");
1888 dialog.set_size_request (250, -1);
1889 dialog.set_position (Gtk::WIN_POS_MOUSE);
1891 dialog.add_button (Stock::OK, RESPONSE_ACCEPT);
1892 dialog.set_initial_text (name);
1896 switch (dialog.run ()) {
1897 case RESPONSE_ACCEPT:
1903 dialog.get_result(name);
1910 Editor::add_location_from_selection ()
1914 if (selection->time.empty()) {
1918 if (_session == 0 || clicked_axisview == 0) {
1922 framepos_t start = selection->time[clicked_selection].start;
1923 framepos_t end = selection->time[clicked_selection].end;
1925 _session->locations()->next_available_name(rangename,"selection");
1926 Location *location = new Location (*_session, start, end, rangename, Location::IsRangeMarker);
1928 _session->begin_reversible_command (_("add marker"));
1929 XMLNode &before = _session->locations()->get_state();
1930 _session->locations()->add (location, true);
1931 XMLNode &after = _session->locations()->get_state();
1932 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
1933 _session->commit_reversible_command ();
1937 Editor::add_location_mark (framepos_t where)
1941 select_new_marker = true;
1943 _session->locations()->next_available_name(markername,"mark");
1944 if (!choose_new_marker_name(markername)) {
1947 Location *location = new Location (*_session, where, where, markername, Location::IsMark);
1948 _session->begin_reversible_command (_("add marker"));
1949 XMLNode &before = _session->locations()->get_state();
1950 _session->locations()->add (location, true);
1951 XMLNode &after = _session->locations()->get_state();
1952 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
1953 _session->commit_reversible_command ();
1957 Editor::add_location_from_playhead_cursor ()
1959 add_location_mark (_session->audible_frame());
1963 Editor::remove_location_at_playhead_cursor ()
1968 _session->begin_reversible_command (_("remove marker"));
1969 XMLNode &before = _session->locations()->get_state();
1970 bool removed = false;
1972 //find location(s) at this time
1973 Locations::LocationList locs;
1974 _session->locations()->find_all_between (_session->audible_frame(), _session->audible_frame()+1, locs, Location::Flags(0));
1975 for (Locations::LocationList::iterator i = locs.begin(); i != locs.end(); ++i) {
1976 if ((*i)->is_mark()) {
1977 _session->locations()->remove (*i);
1984 XMLNode &after = _session->locations()->get_state();
1985 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
1986 _session->commit_reversible_command ();
1991 /** Add a range marker around each selected region */
1993 Editor::add_locations_from_region ()
1995 RegionSelection rs = get_regions_from_selection_and_entered ();
2001 _session->begin_reversible_command (selection->regions.size () > 1 ? _("add markers") : _("add marker"));
2002 XMLNode &before = _session->locations()->get_state();
2004 for (RegionSelection::iterator i = rs.begin (); i != rs.end (); ++i) {
2006 boost::shared_ptr<Region> region = (*i)->region ();
2008 Location *location = new Location (*_session, region->position(), region->last_frame(), region->name(), Location::IsRangeMarker);
2010 _session->locations()->add (location, true);
2013 XMLNode &after = _session->locations()->get_state();
2014 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2015 _session->commit_reversible_command ();
2018 /** Add a single range marker around all selected regions */
2020 Editor::add_location_from_region ()
2022 RegionSelection rs = get_regions_from_selection_and_entered ();
2028 _session->begin_reversible_command (_("add marker"));
2029 XMLNode &before = _session->locations()->get_state();
2033 if (rs.size() > 1) {
2034 _session->locations()->next_available_name(markername, "regions");
2036 RegionView* rv = *(rs.begin());
2037 boost::shared_ptr<Region> region = rv->region();
2038 markername = region->name();
2041 if (!choose_new_marker_name(markername)) {
2045 // single range spanning all selected
2046 Location *location = new Location (*_session, selection->regions.start(), selection->regions.end_frame(), markername, Location::IsRangeMarker);
2047 _session->locations()->add (location, true);
2049 XMLNode &after = _session->locations()->get_state();
2050 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2051 _session->commit_reversible_command ();
2057 Editor::jump_forward_to_mark ()
2063 framepos_t pos = _session->locations()->first_mark_after (playhead_cursor->current_frame());
2069 _session->request_locate (pos, _session->transport_rolling());
2073 Editor::jump_backward_to_mark ()
2079 framepos_t pos = _session->locations()->first_mark_before (playhead_cursor->current_frame());
2085 _session->request_locate (pos, _session->transport_rolling());
2091 framepos_t const pos = _session->audible_frame ();
2094 _session->locations()->next_available_name (markername, "mark");
2096 if (!choose_new_marker_name (markername)) {
2100 _session->locations()->add (new Location (*_session, pos, 0, markername, Location::IsMark), true);
2104 Editor::clear_markers ()
2107 _session->begin_reversible_command (_("clear markers"));
2108 XMLNode &before = _session->locations()->get_state();
2109 _session->locations()->clear_markers ();
2110 XMLNode &after = _session->locations()->get_state();
2111 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2112 _session->commit_reversible_command ();
2117 Editor::clear_ranges ()
2120 _session->begin_reversible_command (_("clear ranges"));
2121 XMLNode &before = _session->locations()->get_state();
2123 _session->locations()->clear_ranges ();
2125 XMLNode &after = _session->locations()->get_state();
2126 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2127 _session->commit_reversible_command ();
2132 Editor::clear_locations ()
2134 _session->begin_reversible_command (_("clear locations"));
2135 XMLNode &before = _session->locations()->get_state();
2136 _session->locations()->clear ();
2137 XMLNode &after = _session->locations()->get_state();
2138 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2139 _session->commit_reversible_command ();
2140 _session->locations()->clear ();
2144 Editor::unhide_markers ()
2146 for (LocationMarkerMap::iterator i = location_markers.begin(); i != location_markers.end(); ++i) {
2147 Location *l = (*i).first;
2148 if (l->is_hidden() && l->is_mark()) {
2149 l->set_hidden(false, this);
2155 Editor::unhide_ranges ()
2157 for (LocationMarkerMap::iterator i = location_markers.begin(); i != location_markers.end(); ++i) {
2158 Location *l = (*i).first;
2159 if (l->is_hidden() && l->is_range_marker()) {
2160 l->set_hidden(false, this);
2165 /* INSERT/REPLACE */
2168 Editor::insert_region_list_selection (float times)
2170 RouteTimeAxisView *tv = 0;
2171 boost::shared_ptr<Playlist> playlist;
2173 if (clicked_routeview != 0) {
2174 tv = clicked_routeview;
2175 } else if (!selection->tracks.empty()) {
2176 if ((tv = dynamic_cast<RouteTimeAxisView*>(selection->tracks.front())) == 0) {
2179 } else if (entered_track != 0) {
2180 if ((tv = dynamic_cast<RouteTimeAxisView*>(entered_track)) == 0) {
2187 if ((playlist = tv->playlist()) == 0) {
2191 boost::shared_ptr<Region> region = _regions->get_single_selection ();
2196 begin_reversible_command (_("insert region"));
2197 playlist->clear_changes ();
2198 playlist->add_region ((RegionFactory::create (region, true)), get_preferred_edit_position(), times);
2199 if (Config->get_edit_mode() == Ripple)
2200 playlist->ripple (get_preferred_edit_position(), region->length() * times, boost::shared_ptr<Region>());
2202 _session->add_command(new StatefulDiffCommand (playlist));
2203 commit_reversible_command ();
2206 /* BUILT-IN EFFECTS */
2209 Editor::reverse_selection ()
2214 /* GAIN ENVELOPE EDITING */
2217 Editor::edit_envelope ()
2224 Editor::transition_to_rolling (bool fwd)
2230 if (_session->config.get_external_sync()) {
2231 switch (Config->get_sync_source()) {
2235 /* transport controlled by the master */
2240 if (_session->is_auditioning()) {
2241 _session->cancel_audition ();
2245 _session->request_transport_speed (fwd ? 1.0f : -1.0f);
2249 Editor::play_from_start ()
2251 _session->request_locate (_session->current_start_frame(), true);
2255 Editor::play_from_edit_point ()
2257 _session->request_locate (get_preferred_edit_position(), true);
2261 Editor::play_from_edit_point_and_return ()
2263 framepos_t start_frame;
2264 framepos_t return_frame;
2266 start_frame = get_preferred_edit_position (true);
2268 if (_session->transport_rolling()) {
2269 _session->request_locate (start_frame, false);
2273 /* don't reset the return frame if its already set */
2275 if ((return_frame = _session->requested_return_frame()) < 0) {
2276 return_frame = _session->audible_frame();
2279 if (start_frame >= 0) {
2280 _session->request_roll_at_and_return (start_frame, return_frame);
2285 Editor::play_selection ()
2287 if (selection->time.empty()) {
2291 _session->request_play_range (&selection->time, true);
2295 Editor::get_preroll ()
2297 return 1.0 /*Config->get_edit_preroll_seconds()*/ * _session->frame_rate();
2302 Editor::maybe_locate_with_edit_preroll ( framepos_t location )
2304 if ( _session->transport_rolling() || !Config->get_follow_edits() || _ignore_follow_edits )
2307 location -= get_preroll();
2309 //don't try to locate before the beginning of time
2313 //if follow_playhead is on, keep the playhead on the screen
2314 if ( _follow_playhead )
2315 if ( location < leftmost_frame )
2316 location = leftmost_frame;
2318 _session->request_locate( location );
2322 Editor::play_with_preroll ()
2324 if (selection->time.empty()) {
2327 framepos_t preroll = get_preroll();
2329 framepos_t start = 0;
2330 if (selection->time[clicked_selection].start > preroll)
2331 start = selection->time[clicked_selection].start - preroll;
2333 framepos_t end = selection->time[clicked_selection].end + preroll;
2335 AudioRange ar (start, end, 0);
2336 list<AudioRange> lar;
2339 _session->request_play_range (&lar, true);
2344 Editor::play_location (Location& location)
2346 if (location.start() <= location.end()) {
2350 _session->request_bounded_roll (location.start(), location.end());
2354 Editor::loop_location (Location& location)
2356 if (location.start() <= location.end()) {
2362 if ((tll = transport_loop_location()) != 0) {
2363 tll->set (location.start(), location.end());
2365 // enable looping, reposition and start rolling
2366 _session->request_locate (tll->start(), true);
2367 _session->request_play_loop (true);
2372 Editor::do_layer_operation (LayerOperation op)
2374 if (selection->regions.empty ()) {
2378 bool const multiple = selection->regions.size() > 1;
2382 begin_reversible_command (_("raise regions"));
2384 begin_reversible_command (_("raise region"));
2390 begin_reversible_command (_("raise regions to top"));
2392 begin_reversible_command (_("raise region to top"));
2398 begin_reversible_command (_("lower regions"));
2400 begin_reversible_command (_("lower region"));
2406 begin_reversible_command (_("lower regions to bottom"));
2408 begin_reversible_command (_("lower region"));
2413 set<boost::shared_ptr<Playlist> > playlists = selection->regions.playlists ();
2414 for (set<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
2415 (*i)->clear_owned_changes ();
2418 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
2419 boost::shared_ptr<Region> r = (*i)->region ();
2431 r->lower_to_bottom ();
2435 for (set<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
2436 vector<Command*> cmds;
2438 _session->add_commands (cmds);
2441 commit_reversible_command ();
2445 Editor::raise_region ()
2447 do_layer_operation (Raise);
2451 Editor::raise_region_to_top ()
2453 do_layer_operation (RaiseToTop);
2457 Editor::lower_region ()
2459 do_layer_operation (Lower);
2463 Editor::lower_region_to_bottom ()
2465 do_layer_operation (LowerToBottom);
2468 /** Show the region editor for the selected regions */
2470 Editor::show_region_properties ()
2472 selection->foreach_regionview (&RegionView::show_region_editor);
2475 /** Show the midi list editor for the selected MIDI regions */
2477 Editor::show_midi_list_editor ()
2479 selection->foreach_midi_regionview (&MidiRegionView::show_list_editor);
2483 Editor::rename_region ()
2485 RegionSelection rs = get_regions_from_selection_and_entered ();
2491 ArdourDialog d (*this, _("Rename Region"), true, false);
2493 Label label (_("New name:"));
2496 hbox.set_spacing (6);
2497 hbox.pack_start (label, false, false);
2498 hbox.pack_start (entry, true, true);
2500 d.get_vbox()->set_border_width (12);
2501 d.get_vbox()->pack_start (hbox, false, false);
2503 d.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
2504 d.add_button(Gtk::Stock::OK, Gtk::RESPONSE_OK);
2506 d.set_size_request (300, -1);
2508 entry.set_text (rs.front()->region()->name());
2509 entry.select_region (0, -1);
2511 entry.signal_activate().connect (sigc::bind (sigc::mem_fun (d, &Dialog::response), RESPONSE_OK));
2517 int const ret = d.run();
2521 if (ret != RESPONSE_OK) {
2525 std::string str = entry.get_text();
2526 strip_whitespace_edges (str);
2528 rs.front()->region()->set_name (str);
2529 _regions->redisplay ();
2534 Editor::audition_playlist_region_via_route (boost::shared_ptr<Region> region, Route& route)
2536 if (_session->is_auditioning()) {
2537 _session->cancel_audition ();
2540 // note: some potential for creativity here, because region doesn't
2541 // have to belong to the playlist that Route is handling
2543 // bool was_soloed = route.soloed();
2545 route.set_solo (true, this);
2547 _session->request_bounded_roll (region->position(), region->position() + region->length());
2549 /* XXX how to unset the solo state ? */
2552 /** Start an audition of the first selected region */
2554 Editor::play_edit_range ()
2556 framepos_t start, end;
2558 if (get_edit_op_range (start, end)) {
2559 _session->request_bounded_roll (start, end);
2564 Editor::play_selected_region ()
2566 framepos_t start = max_framepos;
2569 RegionSelection rs = get_regions_from_selection_and_entered ();
2575 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
2576 if ((*i)->region()->position() < start) {
2577 start = (*i)->region()->position();
2579 if ((*i)->region()->last_frame() + 1 > end) {
2580 end = (*i)->region()->last_frame() + 1;
2584 _session->request_bounded_roll (start, end);
2588 Editor::audition_playlist_region_standalone (boost::shared_ptr<Region> region)
2590 _session->audition_region (region);
2594 Editor::region_from_selection ()
2596 if (clicked_axisview == 0) {
2600 if (selection->time.empty()) {
2604 framepos_t start = selection->time[clicked_selection].start;
2605 framepos_t end = selection->time[clicked_selection].end;
2607 TrackViewList tracks = get_tracks_for_range_action ();
2609 framepos_t selection_cnt = end - start + 1;
2611 for (TrackSelection::iterator i = tracks.begin(); i != tracks.end(); ++i) {
2612 boost::shared_ptr<Region> current;
2613 boost::shared_ptr<Playlist> pl;
2614 framepos_t internal_start;
2617 if ((pl = (*i)->playlist()) == 0) {
2621 if ((current = pl->top_region_at (start)) == 0) {
2625 internal_start = start - current->position();
2626 RegionFactory::region_name (new_name, current->name(), true);
2630 plist.add (ARDOUR::Properties::start, current->start() + internal_start);
2631 plist.add (ARDOUR::Properties::length, selection_cnt);
2632 plist.add (ARDOUR::Properties::name, new_name);
2633 plist.add (ARDOUR::Properties::layer, 0);
2635 boost::shared_ptr<Region> region (RegionFactory::create (current, plist));
2640 Editor::create_region_from_selection (vector<boost::shared_ptr<Region> >& new_regions)
2642 if (selection->time.empty() || selection->tracks.empty()) {
2646 framepos_t start = selection->time[clicked_selection].start;
2647 framepos_t end = selection->time[clicked_selection].end;
2649 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
2650 sort_track_selection (ts);
2652 for (TrackSelection::iterator i = ts.begin(); i != ts.end(); ++i) {
2653 boost::shared_ptr<Region> current;
2654 boost::shared_ptr<Playlist> playlist;
2655 framepos_t internal_start;
2658 if ((playlist = (*i)->playlist()) == 0) {
2662 if ((current = playlist->top_region_at(start)) == 0) {
2666 internal_start = start - current->position();
2667 RegionFactory::region_name (new_name, current->name(), true);
2671 plist.add (ARDOUR::Properties::start, current->start() + internal_start);
2672 plist.add (ARDOUR::Properties::length, end - start + 1);
2673 plist.add (ARDOUR::Properties::name, new_name);
2675 new_regions.push_back (RegionFactory::create (current, plist));
2680 Editor::split_multichannel_region ()
2682 RegionSelection rs = get_regions_from_selection_and_entered ();
2688 vector< boost::shared_ptr<Region> > v;
2690 for (list<RegionView*>::iterator x = rs.begin(); x != rs.end(); ++x) {
2691 (*x)->region()->separate_by_channel (*_session, v);
2696 Editor::new_region_from_selection ()
2698 region_from_selection ();
2699 cancel_selection ();
2703 add_if_covered (RegionView* rv, const AudioRange* ar, RegionSelection* rs)
2705 switch (rv->region()->coverage (ar->start, ar->end - 1)) {
2706 case Evoral::OverlapNone:
2714 * - selected tracks, or if there are none...
2715 * - tracks containing selected regions, or if there are none...
2720 Editor::get_tracks_for_range_action () const
2724 if (selection->tracks.empty()) {
2726 /* use tracks with selected regions */
2728 RegionSelection rs = selection->regions;
2730 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
2731 TimeAxisView* tv = &(*i)->get_time_axis_view();
2733 if (!t.contains (tv)) {
2739 /* no regions and no tracks: use all tracks */
2745 t = selection->tracks;
2748 return t.filter_to_unique_playlists();
2752 Editor::separate_regions_between (const TimeSelection& ts)
2754 bool in_command = false;
2755 boost::shared_ptr<Playlist> playlist;
2756 RegionSelection new_selection;
2758 TrackViewList tmptracks = get_tracks_for_range_action ();
2759 sort_track_selection (tmptracks);
2761 for (TrackSelection::iterator i = tmptracks.begin(); i != tmptracks.end(); ++i) {
2763 RouteTimeAxisView* rtv;
2765 if ((rtv = dynamic_cast<RouteTimeAxisView*> ((*i))) != 0) {
2767 if (rtv->is_track()) {
2769 /* no edits to destructive tracks */
2771 if (rtv->track()->destructive()) {
2775 if ((playlist = rtv->playlist()) != 0) {
2777 playlist->clear_changes ();
2779 /* XXX need to consider musical time selections here at some point */
2781 double speed = rtv->track()->speed();
2784 for (list<AudioRange>::const_iterator t = ts.begin(); t != ts.end(); ++t) {
2786 sigc::connection c = rtv->view()->RegionViewAdded.connect (
2787 sigc::mem_fun(*this, &Editor::collect_new_region_view));
2789 latest_regionviews.clear ();
2791 playlist->partition ((framepos_t)((*t).start * speed),
2792 (framepos_t)((*t).end * speed), false);
2796 if (!latest_regionviews.empty()) {
2798 rtv->view()->foreach_regionview (sigc::bind (
2799 sigc::ptr_fun (add_if_covered),
2800 &(*t), &new_selection));
2803 begin_reversible_command (_("separate"));
2807 /* pick up changes to existing regions */
2809 vector<Command*> cmds;
2810 playlist->rdiff (cmds);
2811 _session->add_commands (cmds);
2813 /* pick up changes to the playlist itself (adds/removes)
2816 _session->add_command(new StatefulDiffCommand (playlist));
2825 // selection->set (new_selection);
2827 commit_reversible_command ();
2831 struct PlaylistState {
2832 boost::shared_ptr<Playlist> playlist;
2836 /** Take tracks from get_tracks_for_range_action and cut any regions
2837 * on those tracks so that the tracks are empty over the time
2841 Editor::separate_region_from_selection ()
2843 /* preferentially use *all* ranges in the time selection if we're in range mode
2844 to allow discontiguous operation, since get_edit_op_range() currently
2845 returns a single range.
2848 if (!selection->time.empty()) {
2850 separate_regions_between (selection->time);
2857 if (get_edit_op_range (start, end)) {
2859 AudioRange ar (start, end, 1);
2863 separate_regions_between (ts);
2869 Editor::separate_region_from_punch ()
2871 Location* loc = _session->locations()->auto_punch_location();
2873 separate_regions_using_location (*loc);
2878 Editor::separate_region_from_loop ()
2880 Location* loc = _session->locations()->auto_loop_location();
2882 separate_regions_using_location (*loc);
2887 Editor::separate_regions_using_location (Location& loc)
2889 if (loc.is_mark()) {
2893 AudioRange ar (loc.start(), loc.end(), 1);
2898 separate_regions_between (ts);
2901 /** Separate regions under the selected region */
2903 Editor::separate_under_selected_regions ()
2905 vector<PlaylistState> playlists;
2909 rs = get_regions_from_selection_and_entered();
2911 if (!_session || rs.empty()) {
2915 begin_reversible_command (_("separate region under"));
2917 list<boost::shared_ptr<Region> > regions_to_remove;
2919 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
2920 // we can't just remove the region(s) in this loop because
2921 // this removes them from the RegionSelection, and they thus
2922 // disappear from underneath the iterator, and the ++i above
2923 // SEGVs in a puzzling fashion.
2925 // so, first iterate over the regions to be removed from rs and
2926 // add them to the regions_to_remove list, and then
2927 // iterate over the list to actually remove them.
2929 regions_to_remove.push_back ((*i)->region());
2932 for (list<boost::shared_ptr<Region> >::iterator rl = regions_to_remove.begin(); rl != regions_to_remove.end(); ++rl) {
2934 boost::shared_ptr<Playlist> playlist = (*rl)->playlist();
2937 // is this check necessary?
2941 vector<PlaylistState>::iterator i;
2943 //only take state if this is a new playlist.
2944 for (i = playlists.begin(); i != playlists.end(); ++i) {
2945 if ((*i).playlist == playlist) {
2950 if (i == playlists.end()) {
2952 PlaylistState before;
2953 before.playlist = playlist;
2954 before.before = &playlist->get_state();
2956 playlist->freeze ();
2957 playlists.push_back(before);
2960 //Partition on the region bounds
2961 playlist->partition ((*rl)->first_frame() - 1, (*rl)->last_frame() + 1, true);
2963 //Re-add region that was just removed due to the partition operation
2964 playlist->add_region( (*rl), (*rl)->first_frame() );
2967 vector<PlaylistState>::iterator pl;
2969 for (pl = playlists.begin(); pl != playlists.end(); ++pl) {
2970 (*pl).playlist->thaw ();
2971 _session->add_command(new MementoCommand<Playlist>(*(*pl).playlist, (*pl).before, &(*pl).playlist->get_state()));
2974 commit_reversible_command ();
2978 Editor::crop_region_to_selection ()
2980 if (!selection->time.empty()) {
2982 crop_region_to (selection->time.start(), selection->time.end_frame());
2989 if (get_edit_op_range (start, end)) {
2990 crop_region_to (start, end);
2997 Editor::crop_region_to (framepos_t start, framepos_t end)
2999 vector<boost::shared_ptr<Playlist> > playlists;
3000 boost::shared_ptr<Playlist> playlist;
3003 if (selection->tracks.empty()) {
3004 ts = track_views.filter_to_unique_playlists();
3006 ts = selection->tracks.filter_to_unique_playlists ();
3009 sort_track_selection (ts);
3011 for (TrackSelection::iterator i = ts.begin(); i != ts.end(); ++i) {
3013 RouteTimeAxisView* rtv;
3015 if ((rtv = dynamic_cast<RouteTimeAxisView*> ((*i))) != 0) {
3017 boost::shared_ptr<Track> t = rtv->track();
3019 if (t != 0 && ! t->destructive()) {
3021 if ((playlist = rtv->playlist()) != 0) {
3022 playlists.push_back (playlist);
3028 if (playlists.empty()) {
3032 framepos_t the_start;
3036 begin_reversible_command (_("trim to selection"));
3038 for (vector<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
3040 boost::shared_ptr<Region> region;
3044 if ((region = (*i)->top_region_at(the_start)) == 0) {
3048 /* now adjust lengths to that we do the right thing
3049 if the selection extends beyond the region
3052 the_start = max (the_start, (framepos_t) region->position());
3053 if (max_framepos - the_start < region->length()) {
3054 the_end = the_start + region->length() - 1;
3056 the_end = max_framepos;
3058 the_end = min (end, the_end);
3059 cnt = the_end - the_start + 1;
3061 region->clear_changes ();
3062 region->trim_to (the_start, cnt);
3063 _session->add_command (new StatefulDiffCommand (region));
3066 commit_reversible_command ();
3070 Editor::region_fill_track ()
3072 RegionSelection rs = get_regions_from_selection_and_entered ();
3074 if (!_session || rs.empty()) {
3078 framepos_t const end = _session->current_end_frame ();
3080 begin_reversible_command (Operations::region_fill);
3082 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3084 boost::shared_ptr<Region> region ((*i)->region());
3086 boost::shared_ptr<Playlist> pl = region->playlist();
3088 if (end <= region->last_frame()) {
3092 double times = (double) (end - region->last_frame()) / (double) region->length();
3098 pl->clear_changes ();
3099 pl->add_region (RegionFactory::create (region, true), region->last_frame(), times);
3100 _session->add_command (new StatefulDiffCommand (pl));
3103 commit_reversible_command ();
3107 Editor::region_fill_selection ()
3109 if (clicked_routeview == 0 || !clicked_routeview->is_audio_track()) {
3113 if (selection->time.empty()) {
3117 boost::shared_ptr<Region> region = _regions->get_single_selection ();
3122 framepos_t start = selection->time[clicked_selection].start;
3123 framepos_t end = selection->time[clicked_selection].end;
3125 boost::shared_ptr<Playlist> playlist;
3127 if (selection->tracks.empty()) {
3131 framepos_t selection_length = end - start;
3132 float times = (float)selection_length / region->length();
3134 begin_reversible_command (Operations::fill_selection);
3136 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
3138 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
3140 if ((playlist = (*i)->playlist()) == 0) {
3144 playlist->clear_changes ();
3145 playlist->add_region (RegionFactory::create (region, true), start, times);
3146 _session->add_command (new StatefulDiffCommand (playlist));
3149 commit_reversible_command ();
3153 Editor::set_region_sync_position ()
3155 set_sync_point (get_preferred_edit_position (), get_regions_from_selection_and_edit_point ());
3159 Editor::set_sync_point (framepos_t where, const RegionSelection& rs)
3161 bool in_command = false;
3163 for (RegionSelection::const_iterator r = rs.begin(); r != rs.end(); ++r) {
3165 if (!(*r)->region()->covers (where)) {
3169 boost::shared_ptr<Region> region ((*r)->region());
3172 begin_reversible_command (_("set sync point"));
3176 region->clear_changes ();
3177 region->set_sync_position (where);
3178 _session->add_command(new StatefulDiffCommand (region));
3182 commit_reversible_command ();
3186 /** Remove the sync positions of the selection */
3188 Editor::remove_region_sync ()
3190 RegionSelection rs = get_regions_from_selection_and_entered ();
3196 begin_reversible_command (_("remove region sync"));
3198 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3200 (*i)->region()->clear_changes ();
3201 (*i)->region()->clear_sync_position ();
3202 _session->add_command(new StatefulDiffCommand ((*i)->region()));
3205 commit_reversible_command ();
3209 Editor::naturalize_region ()
3211 RegionSelection rs = get_regions_from_selection_and_entered ();
3217 if (rs.size() > 1) {
3218 begin_reversible_command (_("move regions to original position"));
3220 begin_reversible_command (_("move region to original position"));
3223 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3224 (*i)->region()->clear_changes ();
3225 (*i)->region()->move_to_natural_position ();
3226 _session->add_command (new StatefulDiffCommand ((*i)->region()));
3229 commit_reversible_command ();
3233 Editor::align_regions (RegionPoint what)
3235 RegionSelection const rs = get_regions_from_selection_and_edit_point ();
3241 begin_reversible_command (_("align selection"));
3243 framepos_t const position = get_preferred_edit_position ();
3245 for (RegionSelection::const_iterator i = rs.begin(); i != rs.end(); ++i) {
3246 align_region_internal ((*i)->region(), what, position);
3249 commit_reversible_command ();
3252 struct RegionSortByTime {
3253 bool operator() (const RegionView* a, const RegionView* b) {
3254 return a->region()->position() < b->region()->position();
3259 Editor::align_regions_relative (RegionPoint point)
3261 RegionSelection const rs = get_regions_from_selection_and_edit_point ();
3267 framepos_t const position = get_preferred_edit_position ();
3269 framepos_t distance = 0;
3273 list<RegionView*> sorted;
3274 rs.by_position (sorted);
3276 boost::shared_ptr<Region> r ((*sorted.begin())->region());
3281 if (position > r->position()) {
3282 distance = position - r->position();
3284 distance = r->position() - position;
3290 if (position > r->last_frame()) {
3291 distance = position - r->last_frame();
3292 pos = r->position() + distance;
3294 distance = r->last_frame() - position;
3295 pos = r->position() - distance;
3301 pos = r->adjust_to_sync (position);
3302 if (pos > r->position()) {
3303 distance = pos - r->position();
3305 distance = r->position() - pos;
3311 if (pos == r->position()) {
3315 begin_reversible_command (_("align selection (relative)"));
3317 /* move first one specially */
3319 r->clear_changes ();
3320 r->set_position (pos);
3321 _session->add_command(new StatefulDiffCommand (r));
3323 /* move rest by the same amount */
3327 for (list<RegionView*>::iterator i = sorted.begin(); i != sorted.end(); ++i) {
3329 boost::shared_ptr<Region> region ((*i)->region());
3331 region->clear_changes ();
3334 region->set_position (region->position() + distance);
3336 region->set_position (region->position() - distance);
3339 _session->add_command(new StatefulDiffCommand (region));
3343 commit_reversible_command ();
3347 Editor::align_region (boost::shared_ptr<Region> region, RegionPoint point, framepos_t position)
3349 begin_reversible_command (_("align region"));
3350 align_region_internal (region, point, position);
3351 commit_reversible_command ();
3355 Editor::align_region_internal (boost::shared_ptr<Region> region, RegionPoint point, framepos_t position)
3357 region->clear_changes ();
3361 region->set_position (region->adjust_to_sync (position));
3365 if (position > region->length()) {
3366 region->set_position (position - region->length());
3371 region->set_position (position);
3375 _session->add_command(new StatefulDiffCommand (region));
3379 Editor::trim_region_front ()
3385 Editor::trim_region_back ()
3387 trim_region (false);
3391 Editor::trim_region (bool front)
3393 framepos_t where = get_preferred_edit_position();
3394 RegionSelection rs = get_regions_from_selection_and_edit_point ();
3400 begin_reversible_command (front ? _("trim front") : _("trim back"));
3402 for (list<RegionView*>::const_iterator i = rs.by_layer().begin(); i != rs.by_layer().end(); ++i) {
3403 if (!(*i)->region()->locked()) {
3405 (*i)->region()->clear_changes ();
3408 (*i)->region()->trim_front (where);
3409 maybe_locate_with_edit_preroll ( where );
3411 (*i)->region()->trim_end (where);
3412 maybe_locate_with_edit_preroll ( where );
3415 _session->add_command (new StatefulDiffCommand ((*i)->region()));
3419 commit_reversible_command ();
3422 /** Trim the end of the selected regions to the position of the edit cursor */
3424 Editor::trim_region_to_loop ()
3426 Location* loc = _session->locations()->auto_loop_location();
3430 trim_region_to_location (*loc, _("trim to loop"));
3434 Editor::trim_region_to_punch ()
3436 Location* loc = _session->locations()->auto_punch_location();
3440 trim_region_to_location (*loc, _("trim to punch"));
3444 Editor::trim_region_to_location (const Location& loc, const char* str)
3446 RegionSelection rs = get_regions_from_selection_and_entered ();
3448 begin_reversible_command (str);
3450 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
3451 RegionView* rv = (*x);
3453 /* require region to span proposed trim */
3454 switch (rv->region()->coverage (loc.start(), loc.end())) {
3455 case Evoral::OverlapInternal:
3461 RouteTimeAxisView* tav = dynamic_cast<RouteTimeAxisView*> (&rv->get_time_axis_view());
3470 if (tav->track() != 0) {
3471 speed = tav->track()->speed();
3474 start = session_frame_to_track_frame (loc.start(), speed);
3475 end = session_frame_to_track_frame (loc.end(), speed);
3477 rv->region()->clear_changes ();
3478 rv->region()->trim_to (start, (end - start));
3479 _session->add_command(new StatefulDiffCommand (rv->region()));
3482 commit_reversible_command ();
3486 Editor::trim_region_to_previous_region_end ()
3488 return trim_to_region(false);
3492 Editor::trim_region_to_next_region_start ()
3494 return trim_to_region(true);
3498 Editor::trim_to_region(bool forward)
3500 RegionSelection rs = get_regions_from_selection_and_entered ();
3502 begin_reversible_command (_("trim to region"));
3504 boost::shared_ptr<Region> next_region;
3506 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
3508 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*x);
3514 AudioTimeAxisView* atav = dynamic_cast<AudioTimeAxisView*> (&arv->get_time_axis_view());
3522 if (atav->track() != 0) {
3523 speed = atav->track()->speed();
3527 boost::shared_ptr<Region> region = arv->region();
3528 boost::shared_ptr<Playlist> playlist (region->playlist());
3530 region->clear_changes ();
3534 next_region = playlist->find_next_region (region->first_frame(), Start, 1);
3540 region->trim_end((framepos_t) ( (next_region->first_frame() - 1) * speed));
3541 arv->region_changed (PropertyChange (ARDOUR::Properties::length));
3545 next_region = playlist->find_next_region (region->first_frame(), Start, 0);
3551 region->trim_front((framepos_t) ((next_region->last_frame() + 1) * speed));
3553 arv->region_changed (ARDOUR::bounds_change);
3556 _session->add_command(new StatefulDiffCommand (region));
3559 commit_reversible_command ();
3563 Editor::unfreeze_route ()
3565 if (clicked_routeview == 0 || !clicked_routeview->is_track()) {
3569 clicked_routeview->track()->unfreeze ();
3573 Editor::_freeze_thread (void* arg)
3575 return static_cast<Editor*>(arg)->freeze_thread ();
3579 Editor::freeze_thread ()
3581 /* create event pool because we may need to talk to the session */
3582 SessionEvent::create_per_thread_pool ("freeze events", 64);
3583 /* create per-thread buffers for process() tree to use */
3584 clicked_routeview->audio_track()->freeze_me (*current_interthread_info);
3585 current_interthread_info->done = true;
3590 Editor::freeze_route ()
3596 /* stop transport before we start. this is important */
3598 _session->request_transport_speed (0.0);
3600 /* wait for just a little while, because the above call is asynchronous */
3602 Glib::usleep (250000);
3604 if (clicked_routeview == 0 || !clicked_routeview->is_audio_track()) {
3608 if (!clicked_routeview->track()->bounceable (clicked_routeview->track()->main_outs(), true)) {
3610 _("This track/bus cannot be frozen because the signal adds or loses channels before reaching the outputs.\n"
3611 "This is typically caused by plugins that generate stereo output from mono input or vice versa.")
3613 d.set_title (_("Cannot freeze"));
3618 if (clicked_routeview->track()->has_external_redirects()) {
3619 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"
3620 "Freezing will only process the signal as far as the first send/insert/return."),
3621 clicked_routeview->track()->name()), true, MESSAGE_INFO, BUTTONS_NONE, true);
3623 d.add_button (_("Freeze anyway"), Gtk::RESPONSE_OK);
3624 d.add_button (_("Don't freeze"), Gtk::RESPONSE_CANCEL);
3625 d.set_title (_("Freeze Limits"));
3627 int response = d.run ();
3630 case Gtk::RESPONSE_CANCEL:
3637 InterThreadInfo itt;
3638 current_interthread_info = &itt;
3640 InterthreadProgressWindow ipw (current_interthread_info, _("Freeze"), _("Cancel Freeze"));
3642 pthread_create_and_store (X_("freezer"), &itt.thread, _freeze_thread, this);
3644 set_canvas_cursor (_cursors->wait);
3646 while (!itt.done && !itt.cancel) {
3647 gtk_main_iteration ();
3650 current_interthread_info = 0;
3651 set_canvas_cursor (current_canvas_cursor);
3655 Editor::bounce_range_selection (bool replace, bool enable_processing)
3657 if (selection->time.empty()) {
3661 TrackSelection views = selection->tracks;
3663 for (TrackViewList::iterator i = views.begin(); i != views.end(); ++i) {
3665 if (enable_processing) {
3667 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*i);
3669 if (rtv && rtv->track() && replace && enable_processing && !rtv->track()->bounceable (rtv->track()->main_outs(), false)) {
3671 _("You can't perform this operation because the processing of the signal "
3672 "will cause one or more of the tracks to end up with a region with more channels than this track has inputs.\n\n"
3673 "You can do this without processing, which is a different operation.")
3675 d.set_title (_("Cannot bounce"));
3682 framepos_t start = selection->time[clicked_selection].start;
3683 framepos_t end = selection->time[clicked_selection].end;
3684 framepos_t cnt = end - start + 1;
3686 begin_reversible_command (_("bounce range"));
3688 for (TrackViewList::iterator i = views.begin(); i != views.end(); ++i) {
3690 RouteTimeAxisView* rtv;
3692 if ((rtv = dynamic_cast<RouteTimeAxisView*> (*i)) == 0) {
3696 boost::shared_ptr<Playlist> playlist;
3698 if ((playlist = rtv->playlist()) == 0) {
3702 InterThreadInfo itt;
3704 playlist->clear_changes ();
3705 playlist->clear_owned_changes ();
3707 boost::shared_ptr<Region> r;
3709 if (enable_processing) {
3710 r = rtv->track()->bounce_range (start, start+cnt, itt, rtv->track()->main_outs(), false);
3712 r = rtv->track()->bounce_range (start, start+cnt, itt, boost::shared_ptr<Processor>(), false);
3720 list<AudioRange> ranges;
3721 ranges.push_back (AudioRange (start, start+cnt, 0));
3722 playlist->cut (ranges); // discard result
3723 playlist->add_region (r, start);
3726 vector<Command*> cmds;
3727 playlist->rdiff (cmds);
3728 _session->add_commands (cmds);
3730 _session->add_command (new StatefulDiffCommand (playlist));
3733 commit_reversible_command ();
3736 /** Delete selected regions, automation points or a time range */
3740 //special case: if the user is pointing in the editor/mixer strip, they may be trying to delete a plugin.
3741 //we need this because the editor-mixer strip is in the editor window, so it doesn't get the bindings from the mix window
3742 bool deleted = false;
3743 if ( current_mixer_strip && current_mixer_strip == MixerStrip::entered_mixer_strip() )
3744 deleted = current_mixer_strip->delete_processors ();
3750 /** Cut selected regions, automation points or a time range */
3757 /** Copy selected regions, automation points or a time range */
3765 /** @return true if a Cut, Copy or Clear is possible */
3767 Editor::can_cut_copy () const
3769 if (!selection->time.empty() || !selection->regions.empty() || !selection->points.empty())
3776 /** Cut, copy or clear selected regions, automation points or a time range.
3777 * @param op Operation (Delete, Cut, Copy or Clear)
3780 Editor::cut_copy (CutCopyOp op)
3782 /* only cancel selection if cut/copy is successful.*/
3788 opname = _("delete");
3797 opname = _("clear");
3801 /* if we're deleting something, and the mouse is still pressed,
3802 the thing we started a drag for will be gone when we release
3803 the mouse button(s). avoid this. see part 2 at the end of
3807 if (op == Delete || op == Cut || op == Clear) {
3808 if (_drags->active ()) {
3813 if ( op != Delete ) //"Delete" doesn't change copy/paste buf
3814 cut_buffer->clear ();
3816 if (entered_marker) {
3818 /* cut/delete op while pointing at a marker */
3821 Location* loc = find_location_from_marker (entered_marker, ignored);
3823 if (_session && loc) {
3824 Glib::signal_idle().connect (sigc::bind (sigc::mem_fun(*this, &Editor::really_remove_marker), loc));
3831 if (internal_editing()) {
3833 switch (effective_mouse_mode()) {
3836 begin_reversible_command (opname + ' ' + X_("MIDI"));
3838 commit_reversible_command ();
3847 bool did_edit = false;
3849 if (!selection->regions.empty() || !selection->points.empty()) {
3850 begin_reversible_command (opname + ' ' + _("objects"));
3853 if (!selection->regions.empty()) {
3854 cut_copy_regions (op, selection->regions);
3856 if (op == Cut || op == Delete) {
3857 selection->clear_regions ();
3861 if (!selection->points.empty()) {
3862 cut_copy_points (op);
3864 if (op == Cut || op == Delete) {
3865 selection->clear_points ();
3868 } else if (selection->time.empty()) {
3869 framepos_t start, end;
3870 /* no time selection, see if we can get an edit range
3873 if (get_edit_op_range (start, end)) {
3874 selection->set (start, end);
3876 } else if (!selection->time.empty()) {
3877 begin_reversible_command (opname + ' ' + _("range"));
3880 cut_copy_ranges (op);
3882 if (op == Cut || op == Delete) {
3883 selection->clear_time ();
3888 /* reset repeated paste state */
3891 commit_reversible_command ();
3894 if (op == Delete || op == Cut || op == Clear) {
3899 struct AutomationRecord {
3900 AutomationRecord () : state (0) , line(NULL) {}
3901 AutomationRecord (XMLNode* s, const AutomationLine* l) : state (s) , line (l) {}
3903 XMLNode* state; ///< state before any operation
3904 const AutomationLine* line; ///< line this came from
3905 boost::shared_ptr<Evoral::ControlList> copy; ///< copied events for the cut buffer
3908 /** Cut, copy or clear selected automation points.
3909 * @param op Operation (Cut, Copy or Clear)
3912 Editor::cut_copy_points (CutCopyOp op)
3914 if (selection->points.empty ()) {
3918 /* XXX: not ideal, as there may be more than one track involved in the point selection */
3919 _last_cut_copy_source_track = &selection->points.front()->line().trackview;
3921 /* Keep a record of the AutomationLists that we end up using in this operation */
3922 typedef std::map<boost::shared_ptr<AutomationList>, AutomationRecord> Lists;
3925 /* Go through all selected points, making an AutomationRecord for each distinct AutomationList */
3926 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
3927 const AutomationLine& line = (*i)->line();
3928 const boost::shared_ptr<AutomationList> al = line.the_list();
3929 if (lists.find (al) == lists.end ()) {
3930 /* We haven't seen this list yet, so make a record for it. This includes
3931 taking a copy of its current state, in case this is needed for undo later.
3933 lists[al] = AutomationRecord (&al->get_state (), &line);
3937 if (op == Cut || op == Copy) {
3938 /* This operation will involve putting things in the cut buffer, so create an empty
3939 ControlList for each of our source lists to put the cut buffer data in.
3941 framepos_t start = std::numeric_limits<framepos_t>::max();
3942 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
3943 i->second.copy = i->first->create (i->first->parameter ());
3945 /* Calculate earliest start position of any point in selection. */
3946 start = std::min(start, i->second.line->session_position(i->first->begin()));
3949 /* Add all selected points to the relevant copy ControlLists */
3950 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
3951 boost::shared_ptr<AutomationList> al = (*i)->line().the_list();
3952 AutomationList::const_iterator j = (*i)->model ();
3953 lists[al].copy->fast_simple_add ((*j)->when, (*j)->value);
3956 /* Snap start time backwards, so copy/paste is snap aligned. */
3957 snap_to(start, RoundDownMaybe);
3959 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
3960 /* Correct this copy list so that it is relative to the earliest
3961 start time, so relative ordering between points is preserved
3962 when copying from several lists. */
3963 const AutomationLine* line = i->second.line;
3964 const double line_offset = line->time_converter().from(start);
3966 for (AutomationList::iterator j = i->second.copy->begin(); j != i->second.copy->end(); ++j) {
3967 (*j)->when -= line_offset;
3970 /* And add it to the cut buffer */
3971 cut_buffer->add (i->second.copy);
3975 if (op == Delete || op == Cut) {
3976 /* This operation needs to remove things from the main AutomationList, so do that now */
3978 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
3979 i->first->freeze ();
3982 /* Remove each selected point from its AutomationList */
3983 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
3984 boost::shared_ptr<AutomationList> al = (*i)->line().the_list();
3985 al->erase ((*i)->model ());
3988 /* Thaw the lists and add undo records for them */
3989 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
3990 boost::shared_ptr<AutomationList> al = i->first;
3992 _session->add_command (new MementoCommand<AutomationList> (*al.get(), i->second.state, &(al->get_state ())));
3997 /** Cut, copy or clear selected automation points.
3998 * @param op Operation (Cut, Copy or Clear)
4001 Editor::cut_copy_midi (CutCopyOp op)
4003 for (MidiRegionSelection::iterator i = selection->midi_regions.begin(); i != selection->midi_regions.end(); ++i) {
4004 MidiRegionView* mrv = dynamic_cast<MidiRegionView*>(*i);
4006 mrv->cut_copy_clear (op);
4008 /* XXX: not ideal, as there may be more than one track involved in the selection */
4009 _last_cut_copy_source_track = &mrv->get_time_axis_view();
4014 struct lt_playlist {
4015 bool operator () (const PlaylistState& a, const PlaylistState& b) {
4016 return a.playlist < b.playlist;
4020 struct PlaylistMapping {
4022 boost::shared_ptr<Playlist> pl;
4024 PlaylistMapping (TimeAxisView* tvp) : tv (tvp) {}
4027 /** Remove `clicked_regionview' */
4029 Editor::remove_clicked_region ()
4031 if (clicked_routeview == 0 || clicked_regionview == 0) {
4035 boost::shared_ptr<Playlist> playlist = clicked_routeview->playlist();
4037 playlist->clear_changes ();
4038 playlist->clear_owned_changes ();
4039 playlist->remove_region (clicked_regionview->region());
4040 if (Config->get_edit_mode() == Ripple)
4041 playlist->ripple (clicked_regionview->region()->position(), -clicked_regionview->region()->length(), boost::shared_ptr<Region>());
4043 /* We might have removed regions, which alters other regions' layering_index,
4044 so we need to do a recursive diff here.
4046 vector<Command*> cmds;
4047 playlist->rdiff (cmds);
4048 _session->add_commands (cmds);
4050 _session->add_command(new StatefulDiffCommand (playlist));
4051 commit_reversible_command ();
4055 /** Remove the selected regions */
4057 Editor::remove_selected_regions ()
4059 RegionSelection rs = get_regions_from_selection_and_entered ();
4061 if (!_session || rs.empty()) {
4065 begin_reversible_command (_("remove region"));
4067 list<boost::shared_ptr<Region> > regions_to_remove;
4069 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
4070 // we can't just remove the region(s) in this loop because
4071 // this removes them from the RegionSelection, and they thus
4072 // disappear from underneath the iterator, and the ++i above
4073 // SEGVs in a puzzling fashion.
4075 // so, first iterate over the regions to be removed from rs and
4076 // add them to the regions_to_remove list, and then
4077 // iterate over the list to actually remove them.
4079 regions_to_remove.push_back ((*i)->region());
4082 vector<boost::shared_ptr<Playlist> > playlists;
4084 for (list<boost::shared_ptr<Region> >::iterator rl = regions_to_remove.begin(); rl != regions_to_remove.end(); ++rl) {
4086 boost::shared_ptr<Playlist> playlist = (*rl)->playlist();
4089 // is this check necessary?
4093 /* get_regions_from_selection_and_entered() guarantees that
4094 the playlists involved are unique, so there is no need
4098 playlists.push_back (playlist);
4100 playlist->clear_changes ();
4101 playlist->clear_owned_changes ();
4102 playlist->freeze ();
4103 playlist->remove_region (*rl);
4104 if (Config->get_edit_mode() == Ripple)
4105 playlist->ripple ((*rl)->position(), -(*rl)->length(), boost::shared_ptr<Region>());
4109 vector<boost::shared_ptr<Playlist> >::iterator pl;
4111 for (pl = playlists.begin(); pl != playlists.end(); ++pl) {
4114 /* We might have removed regions, which alters other regions' layering_index,
4115 so we need to do a recursive diff here.
4117 vector<Command*> cmds;
4118 (*pl)->rdiff (cmds);
4119 _session->add_commands (cmds);
4121 _session->add_command(new StatefulDiffCommand (*pl));
4124 commit_reversible_command ();
4127 /** Cut, copy or clear selected regions.
4128 * @param op Operation (Cut, Copy or Clear)
4131 Editor::cut_copy_regions (CutCopyOp op, RegionSelection& rs)
4133 /* we can't use a std::map here because the ordering is important, and we can't trivially sort
4134 a map when we want ordered access to both elements. i think.
4137 vector<PlaylistMapping> pmap;
4139 framepos_t first_position = max_framepos;
4141 typedef set<boost::shared_ptr<Playlist> > FreezeList;
4142 FreezeList freezelist;
4144 /* get ordering correct before we cut/copy */
4146 rs.sort_by_position_and_track ();
4148 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
4150 first_position = min ((framepos_t) (*x)->region()->position(), first_position);
4152 if (op == Cut || op == Clear || op == Delete) {
4153 boost::shared_ptr<Playlist> pl = (*x)->region()->playlist();
4156 FreezeList::iterator fl;
4158 // only take state if this is a new playlist.
4159 for (fl = freezelist.begin(); fl != freezelist.end(); ++fl) {
4165 if (fl == freezelist.end()) {
4166 pl->clear_changes();
4167 pl->clear_owned_changes ();
4169 freezelist.insert (pl);
4174 TimeAxisView* tv = &(*x)->get_time_axis_view();
4175 vector<PlaylistMapping>::iterator z;
4177 for (z = pmap.begin(); z != pmap.end(); ++z) {
4178 if ((*z).tv == tv) {
4183 if (z == pmap.end()) {
4184 pmap.push_back (PlaylistMapping (tv));
4188 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ) {
4190 boost::shared_ptr<Playlist> pl = (*x)->region()->playlist();
4193 /* region not yet associated with a playlist (e.g. unfinished
4200 TimeAxisView& tv = (*x)->get_time_axis_view();
4201 boost::shared_ptr<Playlist> npl;
4202 RegionSelection::iterator tmp;
4209 vector<PlaylistMapping>::iterator z;
4211 for (z = pmap.begin(); z != pmap.end(); ++z) {
4212 if ((*z).tv == &tv) {
4217 assert (z != pmap.end());
4220 npl = PlaylistFactory::create (pl->data_type(), *_session, "cutlist", true);
4228 boost::shared_ptr<Region> r = (*x)->region();
4229 boost::shared_ptr<Region> _xx;
4235 pl->remove_region (r);
4236 if (Config->get_edit_mode() == Ripple)
4237 pl->ripple (r->position(), -r->length(), boost::shared_ptr<Region>());
4241 _xx = RegionFactory::create (r);
4242 npl->add_region (_xx, r->position() - first_position);
4243 pl->remove_region (r);
4244 if (Config->get_edit_mode() == Ripple)
4245 pl->ripple (r->position(), -r->length(), boost::shared_ptr<Region>());
4249 /* copy region before adding, so we're not putting same object into two different playlists */
4250 npl->add_region (RegionFactory::create (r), r->position() - first_position);
4254 pl->remove_region (r);
4255 if (Config->get_edit_mode() == Ripple)
4256 pl->ripple (r->position(), -r->length(), boost::shared_ptr<Region>());
4265 list<boost::shared_ptr<Playlist> > foo;
4267 /* the pmap is in the same order as the tracks in which selected regions occured */
4269 for (vector<PlaylistMapping>::iterator i = pmap.begin(); i != pmap.end(); ++i) {
4272 foo.push_back ((*i).pl);
4277 cut_buffer->set (foo);
4281 _last_cut_copy_source_track = 0;
4283 _last_cut_copy_source_track = pmap.front().tv;
4287 for (FreezeList::iterator pl = freezelist.begin(); pl != freezelist.end(); ++pl) {
4290 /* We might have removed regions, which alters other regions' layering_index,
4291 so we need to do a recursive diff here.
4293 vector<Command*> cmds;
4294 (*pl)->rdiff (cmds);
4295 _session->add_commands (cmds);
4297 _session->add_command (new StatefulDiffCommand (*pl));
4302 Editor::cut_copy_ranges (CutCopyOp op)
4304 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4306 /* Sort the track selection now, so that it if is used, the playlists
4307 selected by the calls below to cut_copy_clear are in the order that
4308 their tracks appear in the editor. This makes things like paste
4309 of ranges work properly.
4312 sort_track_selection (ts);
4315 if (!entered_track) {
4318 ts.push_back (entered_track);
4321 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4322 (*i)->cut_copy_clear (*selection, op);
4327 Editor::paste (float times, bool from_context)
4329 DEBUG_TRACE (DEBUG::CutNPaste, "paste to preferred edit pos\n");
4331 paste_internal (get_preferred_edit_position (false, from_context), times);
4335 Editor::mouse_paste ()
4340 if (!mouse_frame (where, ignored)) {
4345 paste_internal (where, 1);
4349 Editor::paste_internal (framepos_t position, float times)
4351 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("apparent paste position is %1\n", position));
4353 if (cut_buffer->empty(internal_editing())) {
4357 if (position == max_framepos) {
4358 position = get_preferred_edit_position();
4359 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("preferred edit position is %1\n", position));
4362 if (position == last_paste_pos) {
4363 /* repeated paste in the same position */
4366 /* paste in new location, reset repeated paste state */
4368 last_paste_pos = position;
4371 /* get everything in the correct order */
4374 if (!selection->tracks.empty()) {
4375 /* If there is a track selection, paste into exactly those tracks and
4376 only those tracks. This allows the user to be explicit and override
4377 the below "do the reasonable thing" logic. */
4378 ts = selection->tracks.filter_to_unique_playlists ();
4379 sort_track_selection (ts);
4381 /* Figure out which track to base the paste at. */
4382 TimeAxisView* base_track;
4383 if (_edit_point == Editing::EditAtMouse && entered_track) {
4384 /* With the mouse edit point, paste onto the track under the mouse. */
4385 base_track = entered_track;
4386 } else if (_edit_point == Editing::EditAtMouse && entered_regionview) {
4387 /* With the mouse edit point, paste onto the track of the region under the mouse. */
4388 base_track = &entered_regionview->get_time_axis_view();
4389 } else if (_last_cut_copy_source_track) {
4390 /* Paste to the track that the cut/copy came from (see mantis #333). */
4391 base_track = _last_cut_copy_source_track;
4394 /* Walk up to parent if necessary, so base track is a route. */
4395 while (base_track->get_parent()) {
4396 base_track = base_track->get_parent();
4399 /* Add base track and all tracks below it. The paste logic will select
4400 the appropriate object types from the cut buffer in relative order. */
4401 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4402 if ((*i)->order() >= base_track->order()) {
4407 /* Sort tracks so the nth track of type T will pick the nth object of type T. */
4408 sort_track_selection (ts);
4410 /* Add automation children of each track in order, for pasting several lines. */
4411 for (TrackViewList::iterator i = ts.begin(); i != ts.end();) {
4412 /* Add any automation children for pasting several lines */
4413 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*i++);
4418 typedef RouteTimeAxisView::AutomationTracks ATracks;
4419 const ATracks& atracks = rtv->automation_tracks();
4420 for (ATracks::const_iterator a = atracks.begin(); a != atracks.end(); ++a) {
4421 i = ts.insert(i, a->second.get());
4426 /* We now have a list of trackviews starting at base_track, including
4427 automation children, in the order shown in the editor, e.g. R1,
4428 R1.A1, R1.A2, R2, R2.A1, ... */
4431 if (internal_editing ()) {
4433 /* undo/redo is handled by individual tracks/regions */
4436 RegionSelection::iterator r;
4437 MidiNoteSelection::iterator cb;
4439 get_regions_at (rs, position, ts);
4441 for (cb = cut_buffer->midi_notes.begin(), r = rs.begin();
4442 cb != cut_buffer->midi_notes.end() && r != rs.end(); ++r) {
4443 MidiRegionView* mrv = dynamic_cast<MidiRegionView*> (*r);
4445 mrv->paste (position, paste_count, times, **cb);
4452 /* we do redo (do you do voodoo?) */
4454 begin_reversible_command (Operations::paste);
4457 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4458 (*i)->paste (position, paste_count, times, *cut_buffer, counts);
4461 commit_reversible_command ();
4466 Editor::duplicate_some_regions (RegionSelection& regions, float times)
4468 boost::shared_ptr<Playlist> playlist;
4469 RegionSelection sel = regions; // clear (below) may clear the argument list if its the current region selection
4470 RegionSelection foo;
4472 framepos_t const start_frame = regions.start ();
4473 framepos_t const end_frame = regions.end_frame ();
4475 begin_reversible_command (Operations::duplicate_region);
4477 selection->clear_regions ();
4479 for (RegionSelection::iterator i = sel.begin(); i != sel.end(); ++i) {
4481 boost::shared_ptr<Region> r ((*i)->region());
4483 TimeAxisView& tv = (*i)->get_time_axis_view();
4484 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (&tv);
4485 latest_regionviews.clear ();
4486 sigc::connection c = rtv->view()->RegionViewAdded.connect (sigc::mem_fun(*this, &Editor::collect_new_region_view));
4488 playlist = (*i)->region()->playlist();
4489 playlist->clear_changes ();
4490 playlist->duplicate (r, end_frame + (r->first_frame() - start_frame), times);
4491 _session->add_command(new StatefulDiffCommand (playlist));
4495 foo.insert (foo.end(), latest_regionviews.begin(), latest_regionviews.end());
4498 commit_reversible_command ();
4501 selection->set (foo);
4506 Editor::duplicate_selection (float times)
4508 if (selection->time.empty() || selection->tracks.empty()) {
4512 boost::shared_ptr<Playlist> playlist;
4513 vector<boost::shared_ptr<Region> > new_regions;
4514 vector<boost::shared_ptr<Region> >::iterator ri;
4516 create_region_from_selection (new_regions);
4518 if (new_regions.empty()) {
4522 begin_reversible_command (_("duplicate selection"));
4524 ri = new_regions.begin();
4526 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4528 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4529 if ((playlist = (*i)->playlist()) == 0) {
4532 playlist->clear_changes ();
4533 playlist->duplicate (*ri, selection->time[clicked_selection].end, times);
4534 _session->add_command (new StatefulDiffCommand (playlist));
4537 if (ri == new_regions.end()) {
4542 commit_reversible_command ();
4545 /** Reset all selected points to the relevant default value */
4547 Editor::reset_point_selection ()
4549 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
4550 ARDOUR::AutomationList::iterator j = (*i)->model ();
4551 (*j)->value = (*i)->line().the_list()->default_value ();
4556 Editor::center_playhead ()
4558 float const page = _visible_canvas_width * samples_per_pixel;
4559 center_screen_internal (playhead_cursor->current_frame (), page);
4563 Editor::center_edit_point ()
4565 float const page = _visible_canvas_width * samples_per_pixel;
4566 center_screen_internal (get_preferred_edit_position(), page);
4569 /** Caller must begin and commit a reversible command */
4571 Editor::clear_playlist (boost::shared_ptr<Playlist> playlist)
4573 playlist->clear_changes ();
4575 _session->add_command (new StatefulDiffCommand (playlist));
4579 Editor::nudge_track (bool use_edit, bool forwards)
4581 boost::shared_ptr<Playlist> playlist;
4582 framepos_t distance;
4583 framepos_t next_distance;
4587 start = get_preferred_edit_position();
4592 if ((distance = get_nudge_distance (start, next_distance)) == 0) {
4596 if (selection->tracks.empty()) {
4600 begin_reversible_command (_("nudge track"));
4602 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4604 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4606 if ((playlist = (*i)->playlist()) == 0) {
4610 playlist->clear_changes ();
4611 playlist->clear_owned_changes ();
4613 playlist->nudge_after (start, distance, forwards);
4615 vector<Command*> cmds;
4617 playlist->rdiff (cmds);
4618 _session->add_commands (cmds);
4620 _session->add_command (new StatefulDiffCommand (playlist));
4623 commit_reversible_command ();
4627 Editor::remove_last_capture ()
4629 vector<string> choices;
4636 if (Config->get_verify_remove_last_capture()) {
4637 prompt = _("Do you really want to destroy the last capture?"
4638 "\n(This is destructive and cannot be undone)");
4640 choices.push_back (_("No, do nothing."));
4641 choices.push_back (_("Yes, destroy it."));
4643 Gtkmm2ext::Choice prompter (_("Destroy last capture"), prompt, choices);
4645 if (prompter.run () == 1) {
4646 _session->remove_last_capture ();
4647 _regions->redisplay ();
4651 _session->remove_last_capture();
4652 _regions->redisplay ();
4657 Editor::normalize_region ()
4663 RegionSelection rs = get_regions_from_selection_and_entered ();
4669 NormalizeDialog dialog (rs.size() > 1);
4671 if (dialog.run () == RESPONSE_CANCEL) {
4675 set_canvas_cursor (_cursors->wait);
4678 /* XXX: should really only count audio regions here */
4679 int const regions = rs.size ();
4681 /* Make a list of the selected audio regions' maximum amplitudes, and also
4682 obtain the maximum amplitude of them all.
4684 list<double> max_amps;
4686 for (RegionSelection::const_iterator i = rs.begin(); i != rs.end(); ++i) {
4687 AudioRegionView const * arv = dynamic_cast<AudioRegionView const *> (*i);
4689 dialog.descend (1.0 / regions);
4690 double const a = arv->audio_region()->maximum_amplitude (&dialog);
4693 /* the user cancelled the operation */
4694 set_canvas_cursor (current_canvas_cursor);
4698 max_amps.push_back (a);
4699 max_amp = max (max_amp, a);
4704 begin_reversible_command (_("normalize"));
4706 list<double>::const_iterator a = max_amps.begin ();
4708 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
4709 AudioRegionView* const arv = dynamic_cast<AudioRegionView*> (*r);
4714 arv->region()->clear_changes ();
4716 double const amp = dialog.normalize_individually() ? *a : max_amp;
4718 arv->audio_region()->normalize (amp, dialog.target ());
4719 _session->add_command (new StatefulDiffCommand (arv->region()));
4724 commit_reversible_command ();
4725 set_canvas_cursor (current_canvas_cursor);
4730 Editor::reset_region_scale_amplitude ()
4736 RegionSelection rs = get_regions_from_selection_and_entered ();
4742 begin_reversible_command ("reset gain");
4744 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
4745 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
4748 arv->region()->clear_changes ();
4749 arv->audio_region()->set_scale_amplitude (1.0f);
4750 _session->add_command (new StatefulDiffCommand (arv->region()));
4753 commit_reversible_command ();
4757 Editor::adjust_region_gain (bool up)
4759 RegionSelection rs = get_regions_from_selection_and_entered ();
4761 if (!_session || rs.empty()) {
4765 begin_reversible_command ("adjust region gain");
4767 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
4768 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
4773 arv->region()->clear_changes ();
4775 double dB = accurate_coefficient_to_dB (arv->audio_region()->scale_amplitude ());
4783 arv->audio_region()->set_scale_amplitude (dB_to_coefficient (dB));
4784 _session->add_command (new StatefulDiffCommand (arv->region()));
4787 commit_reversible_command ();
4792 Editor::reverse_region ()
4798 Reverse rev (*_session);
4799 apply_filter (rev, _("reverse regions"));
4803 Editor::strip_region_silence ()
4809 RegionSelection rs = get_regions_from_selection_and_entered ();
4815 std::list<RegionView*> audio_only;
4817 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
4818 AudioRegionView* const arv = dynamic_cast<AudioRegionView*> (*i);
4820 audio_only.push_back (arv);
4824 StripSilenceDialog d (_session, audio_only);
4825 int const r = d.run ();
4829 if (r == Gtk::RESPONSE_OK) {
4830 ARDOUR::AudioIntervalMap silences;
4831 d.silences (silences);
4832 StripSilence s (*_session, silences, d.fade_length());
4833 apply_filter (s, _("strip silence"), &d);
4838 Editor::apply_midi_note_edit_op_to_region (MidiOperator& op, MidiRegionView& mrv)
4840 Evoral::Sequence<Evoral::MusicalTime>::Notes selected;
4841 mrv.selection_as_notelist (selected, true);
4843 vector<Evoral::Sequence<Evoral::MusicalTime>::Notes> v;
4844 v.push_back (selected);
4846 framepos_t pos_frames = mrv.midi_region()->position() - mrv.midi_region()->start();
4847 double pos_beats = _session->tempo_map().framewalk_to_beats(0, pos_frames);
4849 return op (mrv.midi_region()->model(), pos_beats, v);
4853 Editor::apply_midi_note_edit_op (MidiOperator& op)
4857 RegionSelection rs = get_regions_from_selection_and_entered ();
4863 begin_reversible_command (op.name ());
4865 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
4866 RegionSelection::iterator tmp = r;
4869 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*r);
4872 cmd = apply_midi_note_edit_op_to_region (op, *mrv);
4875 _session->add_command (cmd);
4882 commit_reversible_command ();
4886 Editor::fork_region ()
4888 RegionSelection rs = get_regions_from_selection_and_entered ();
4894 begin_reversible_command (_("Fork Region(s)"));
4896 set_canvas_cursor (_cursors->wait);
4899 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
4900 RegionSelection::iterator tmp = r;
4903 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*>(*r);
4907 boost::shared_ptr<Playlist> playlist = mrv->region()->playlist();
4908 boost::shared_ptr<MidiSource> new_source = _session->create_midi_source_by_stealing_name (mrv->midi_view()->track());
4909 boost::shared_ptr<MidiRegion> newregion = mrv->midi_region()->clone (new_source);
4911 playlist->clear_changes ();
4912 playlist->replace_region (mrv->region(), newregion, mrv->region()->position());
4913 _session->add_command(new StatefulDiffCommand (playlist));
4915 error << string_compose (_("Could not unlink %1"), mrv->region()->name()) << endmsg;
4922 commit_reversible_command ();
4924 set_canvas_cursor (current_canvas_cursor);
4928 Editor::quantize_region ()
4930 int selected_midi_region_cnt = 0;
4936 RegionSelection rs = get_regions_from_selection_and_entered ();
4942 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
4943 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*r);
4945 selected_midi_region_cnt++;
4949 if (selected_midi_region_cnt == 0) {
4953 QuantizeDialog* qd = new QuantizeDialog (*this);
4956 const int r = qd->run ();
4959 if (r == Gtk::RESPONSE_OK) {
4960 Quantize quant (*_session, qd->snap_start(), qd->snap_end(),
4961 qd->start_grid_size(), qd->end_grid_size(),
4962 qd->strength(), qd->swing(), qd->threshold());
4964 apply_midi_note_edit_op (quant);
4969 Editor::insert_patch_change (bool from_context)
4971 RegionSelection rs = get_regions_from_selection_and_entered ();
4977 const framepos_t p = get_preferred_edit_position (false, from_context);
4979 /* XXX: bit of a hack; use the MIDNAM from the first selected region;
4980 there may be more than one, but the PatchChangeDialog can only offer
4981 one set of patch menus.
4983 MidiRegionView* first = dynamic_cast<MidiRegionView*> (rs.front ());
4985 Evoral::PatchChange<Evoral::MusicalTime> empty (0, 0, 0, 0);
4986 PatchChangeDialog d (0, _session, empty, first->instrument_info(), Gtk::Stock::ADD);
4988 if (d.run() == RESPONSE_CANCEL) {
4992 for (RegionSelection::iterator i = rs.begin (); i != rs.end(); ++i) {
4993 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*i);
4995 if (p >= mrv->region()->first_frame() && p <= mrv->region()->last_frame()) {
4996 mrv->add_patch_change (p - mrv->region()->position(), d.patch ());
5003 Editor::apply_filter (Filter& filter, string command, ProgressReporter* progress)
5005 RegionSelection rs = get_regions_from_selection_and_entered ();
5011 begin_reversible_command (command);
5013 set_canvas_cursor (_cursors->wait);
5017 int const N = rs.size ();
5019 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
5020 RegionSelection::iterator tmp = r;
5023 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
5025 boost::shared_ptr<Playlist> playlist = arv->region()->playlist();
5028 progress->descend (1.0 / N);
5031 if (arv->audio_region()->apply (filter, progress) == 0) {
5033 playlist->clear_changes ();
5034 playlist->clear_owned_changes ();
5036 if (filter.results.empty ()) {
5038 /* no regions returned; remove the old one */
5039 playlist->remove_region (arv->region ());
5043 std::vector<boost::shared_ptr<Region> >::iterator res = filter.results.begin ();
5045 /* first region replaces the old one */
5046 playlist->replace_region (arv->region(), *res, (*res)->position());
5050 while (res != filter.results.end()) {
5051 playlist->add_region (*res, (*res)->position());
5057 /* We might have removed regions, which alters other regions' layering_index,
5058 so we need to do a recursive diff here.
5060 vector<Command*> cmds;
5061 playlist->rdiff (cmds);
5062 _session->add_commands (cmds);
5064 _session->add_command(new StatefulDiffCommand (playlist));
5070 progress->ascend ();
5078 commit_reversible_command ();
5081 set_canvas_cursor (current_canvas_cursor);
5085 Editor::external_edit_region ()
5091 Editor::reset_region_gain_envelopes ()
5093 RegionSelection rs = get_regions_from_selection_and_entered ();
5095 if (!_session || rs.empty()) {
5099 _session->begin_reversible_command (_("reset region gain"));
5101 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5102 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
5104 boost::shared_ptr<AutomationList> alist (arv->audio_region()->envelope());
5105 XMLNode& before (alist->get_state());
5107 arv->audio_region()->set_default_envelope ();
5108 _session->add_command (new MementoCommand<AutomationList>(*arv->audio_region()->envelope().get(), &before, &alist->get_state()));
5112 _session->commit_reversible_command ();
5116 Editor::set_region_gain_visibility (RegionView* rv)
5118 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (rv);
5120 arv->update_envelope_visibility();
5125 Editor::set_gain_envelope_visibility ()
5131 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5132 AudioTimeAxisView* v = dynamic_cast<AudioTimeAxisView*>(*i);
5134 v->audio_view()->foreach_regionview (sigc::mem_fun (this, &Editor::set_region_gain_visibility));
5140 Editor::toggle_gain_envelope_active ()
5142 if (_ignore_region_action) {
5146 RegionSelection rs = get_regions_from_selection_and_entered ();
5148 if (!_session || rs.empty()) {
5152 _session->begin_reversible_command (_("region gain envelope active"));
5154 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5155 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
5157 arv->region()->clear_changes ();
5158 arv->audio_region()->set_envelope_active (!arv->audio_region()->envelope_active());
5159 _session->add_command (new StatefulDiffCommand (arv->region()));
5163 _session->commit_reversible_command ();
5167 Editor::toggle_region_lock ()
5169 if (_ignore_region_action) {
5173 RegionSelection rs = get_regions_from_selection_and_entered ();
5175 if (!_session || rs.empty()) {
5179 _session->begin_reversible_command (_("toggle region lock"));
5181 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5182 (*i)->region()->clear_changes ();
5183 (*i)->region()->set_locked (!(*i)->region()->locked());
5184 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5187 _session->commit_reversible_command ();
5191 Editor::toggle_region_video_lock ()
5193 if (_ignore_region_action) {
5197 RegionSelection rs = get_regions_from_selection_and_entered ();
5199 if (!_session || rs.empty()) {
5203 _session->begin_reversible_command (_("Toggle Video Lock"));
5205 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5206 (*i)->region()->clear_changes ();
5207 (*i)->region()->set_video_locked (!(*i)->region()->video_locked());
5208 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5211 _session->commit_reversible_command ();
5215 Editor::toggle_region_lock_style ()
5217 if (_ignore_region_action) {
5221 RegionSelection rs = get_regions_from_selection_and_entered ();
5223 if (!_session || rs.empty()) {
5227 _session->begin_reversible_command (_("region lock style"));
5229 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5230 (*i)->region()->clear_changes ();
5231 PositionLockStyle const ns = (*i)->region()->position_lock_style() == AudioTime ? MusicTime : AudioTime;
5232 (*i)->region()->set_position_lock_style (ns);
5233 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5236 _session->commit_reversible_command ();
5240 Editor::toggle_opaque_region ()
5242 if (_ignore_region_action) {
5246 RegionSelection rs = get_regions_from_selection_and_entered ();
5248 if (!_session || rs.empty()) {
5252 _session->begin_reversible_command (_("change region opacity"));
5254 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5255 (*i)->region()->clear_changes ();
5256 (*i)->region()->set_opaque (!(*i)->region()->opaque());
5257 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5260 _session->commit_reversible_command ();
5264 Editor::toggle_record_enable ()
5266 bool new_state = false;
5268 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5269 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5272 if (!rtav->is_track())
5276 new_state = !rtav->track()->record_enabled();
5280 rtav->track()->set_record_enabled (new_state, this);
5285 Editor::toggle_solo ()
5287 bool new_state = false;
5289 boost::shared_ptr<RouteList> rl (new RouteList);
5291 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5292 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5299 new_state = !rtav->route()->soloed ();
5303 rl->push_back (rtav->route());
5306 _session->set_solo (rl, new_state, Session::rt_cleanup, true);
5310 Editor::toggle_mute ()
5312 bool new_state = false;
5314 boost::shared_ptr<RouteList> rl (new RouteList);
5316 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5317 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5324 new_state = !rtav->route()->muted();
5328 rl->push_back (rtav->route());
5331 _session->set_mute (rl, new_state, Session::rt_cleanup, true);
5335 Editor::toggle_solo_isolate ()
5341 Editor::fade_range ()
5343 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
5345 begin_reversible_command (_("fade range"));
5347 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
5348 (*i)->fade_range (selection->time);
5351 commit_reversible_command ();
5356 Editor::set_fade_length (bool in)
5358 RegionSelection rs = get_regions_from_selection_and_entered ();
5364 /* we need a region to measure the offset from the start */
5366 RegionView* rv = rs.front ();
5368 framepos_t pos = get_preferred_edit_position();
5372 if (pos > rv->region()->last_frame() || pos < rv->region()->first_frame()) {
5373 /* edit point is outside the relevant region */
5378 if (pos <= rv->region()->position()) {
5382 len = pos - rv->region()->position();
5383 cmd = _("set fade in length");
5385 if (pos >= rv->region()->last_frame()) {
5389 len = rv->region()->last_frame() - pos;
5390 cmd = _("set fade out length");
5393 begin_reversible_command (cmd);
5395 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5396 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5402 boost::shared_ptr<AutomationList> alist;
5404 alist = tmp->audio_region()->fade_in();
5406 alist = tmp->audio_region()->fade_out();
5409 XMLNode &before = alist->get_state();
5412 tmp->audio_region()->set_fade_in_length (len);
5413 tmp->audio_region()->set_fade_in_active (true);
5415 tmp->audio_region()->set_fade_out_length (len);
5416 tmp->audio_region()->set_fade_out_active (true);
5419 XMLNode &after = alist->get_state();
5420 _session->add_command(new MementoCommand<AutomationList>(*alist, &before, &after));
5423 commit_reversible_command ();
5427 Editor::set_fade_in_shape (FadeShape shape)
5429 RegionSelection rs = get_regions_from_selection_and_entered ();
5435 begin_reversible_command (_("set fade in shape"));
5437 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5438 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5444 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_in();
5445 XMLNode &before = alist->get_state();
5447 tmp->audio_region()->set_fade_in_shape (shape);
5449 XMLNode &after = alist->get_state();
5450 _session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
5453 commit_reversible_command ();
5458 Editor::set_fade_out_shape (FadeShape shape)
5460 RegionSelection rs = get_regions_from_selection_and_entered ();
5466 begin_reversible_command (_("set fade out shape"));
5468 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5469 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5475 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_out();
5476 XMLNode &before = alist->get_state();
5478 tmp->audio_region()->set_fade_out_shape (shape);
5480 XMLNode &after = alist->get_state();
5481 _session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
5484 commit_reversible_command ();
5488 Editor::set_fade_in_active (bool yn)
5490 RegionSelection rs = get_regions_from_selection_and_entered ();
5496 begin_reversible_command (_("set fade in active"));
5498 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5499 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5506 boost::shared_ptr<AudioRegion> ar (tmp->audio_region());
5508 ar->clear_changes ();
5509 ar->set_fade_in_active (yn);
5510 _session->add_command (new StatefulDiffCommand (ar));
5513 commit_reversible_command ();
5517 Editor::set_fade_out_active (bool yn)
5519 RegionSelection rs = get_regions_from_selection_and_entered ();
5525 begin_reversible_command (_("set fade out active"));
5527 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5528 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5534 boost::shared_ptr<AudioRegion> ar (tmp->audio_region());
5536 ar->clear_changes ();
5537 ar->set_fade_out_active (yn);
5538 _session->add_command(new StatefulDiffCommand (ar));
5541 commit_reversible_command ();
5545 Editor::toggle_region_fades (int dir)
5547 if (_ignore_region_action) {
5551 boost::shared_ptr<AudioRegion> ar;
5554 RegionSelection rs = get_regions_from_selection_and_entered ();
5560 RegionSelection::iterator i;
5561 for (i = rs.begin(); i != rs.end(); ++i) {
5562 if ((ar = boost::dynamic_pointer_cast<AudioRegion>((*i)->region())) != 0) {
5564 yn = ar->fade_out_active ();
5566 yn = ar->fade_in_active ();
5572 if (i == rs.end()) {
5576 /* XXX should this undo-able? */
5578 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5579 if ((ar = boost::dynamic_pointer_cast<AudioRegion>((*i)->region())) == 0) {
5582 if (dir == 1 || dir == 0) {
5583 ar->set_fade_in_active (!yn);
5586 if (dir == -1 || dir == 0) {
5587 ar->set_fade_out_active (!yn);
5593 /** Update region fade visibility after its configuration has been changed */
5595 Editor::update_region_fade_visibility ()
5597 bool _fade_visibility = _session->config.get_show_region_fades ();
5599 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5600 AudioTimeAxisView* v = dynamic_cast<AudioTimeAxisView*>(*i);
5602 if (_fade_visibility) {
5603 v->audio_view()->show_all_fades ();
5605 v->audio_view()->hide_all_fades ();
5612 Editor::set_edit_point ()
5617 if (!mouse_frame (where, ignored)) {
5623 if (selection->markers.empty()) {
5625 mouse_add_new_marker (where);
5630 Location* loc = find_location_from_marker (selection->markers.front(), ignored);
5633 loc->move_to (where);
5639 Editor::set_playhead_cursor ()
5641 if (entered_marker) {
5642 _session->request_locate (entered_marker->position(), _session->transport_rolling());
5647 if (!mouse_frame (where, ignored)) {
5654 _session->request_locate (where, _session->transport_rolling());
5658 if ( Config->get_follow_edits() )
5659 cancel_time_selection();
5663 Editor::split_region ()
5665 if ( !selection->time.empty()) {
5666 separate_regions_between (selection->time);
5670 RegionSelection rs = get_regions_from_selection_and_edit_point ();
5672 framepos_t where = get_preferred_edit_position ();
5678 split_regions_at (where, rs);
5681 struct EditorOrderRouteSorter {
5682 bool operator() (boost::shared_ptr<Route> a, boost::shared_ptr<Route> b) {
5683 return a->order_key () < b->order_key ();
5688 Editor::select_next_route()
5690 if (selection->tracks.empty()) {
5691 selection->set (track_views.front());
5695 TimeAxisView* current = selection->tracks.front();
5699 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5700 if (*i == current) {
5702 if (i != track_views.end()) {
5705 current = (*(track_views.begin()));
5706 //selection->set (*(track_views.begin()));
5711 rui = dynamic_cast<RouteUI *>(current);
5712 } while ( current->hidden() || (rui != NULL && !rui->route()->active()));
5714 selection->set(current);
5716 ensure_time_axis_view_is_visible (*current, false);
5720 Editor::select_prev_route()
5722 if (selection->tracks.empty()) {
5723 selection->set (track_views.front());
5727 TimeAxisView* current = selection->tracks.front();
5731 for (TrackViewList::reverse_iterator i = track_views.rbegin(); i != track_views.rend(); ++i) {
5732 if (*i == current) {
5734 if (i != track_views.rend()) {
5737 current = *(track_views.rbegin());
5742 rui = dynamic_cast<RouteUI *>(current);
5743 } while ( current->hidden() || (rui != NULL && !rui->route()->active()));
5745 selection->set (current);
5747 ensure_time_axis_view_is_visible (*current, false);
5751 Editor::set_loop_from_selection (bool play)
5753 if (_session == 0 || selection->time.empty()) {
5757 framepos_t start = selection->time[clicked_selection].start;
5758 framepos_t end = selection->time[clicked_selection].end;
5760 set_loop_range (start, end, _("set loop range from selection"));
5763 _session->request_locate (start, true);
5764 _session->request_play_loop (true);
5769 Editor::set_loop_from_edit_range (bool play)
5771 if (_session == 0) {
5778 if (!get_edit_op_range (start, end)) {
5782 set_loop_range (start, end, _("set loop range from edit range"));
5785 _session->request_locate (start, true);
5786 _session->request_play_loop (true);
5791 Editor::set_loop_from_region (bool play)
5793 framepos_t start = max_framepos;
5796 RegionSelection rs = get_regions_from_selection_and_entered ();
5802 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5803 if ((*i)->region()->position() < start) {
5804 start = (*i)->region()->position();
5806 if ((*i)->region()->last_frame() + 1 > end) {
5807 end = (*i)->region()->last_frame() + 1;
5811 set_loop_range (start, end, _("set loop range from region"));
5814 _session->request_locate (start, true);
5815 _session->request_play_loop (true);
5820 Editor::set_punch_from_selection ()
5822 if (_session == 0 || selection->time.empty()) {
5826 framepos_t start = selection->time[clicked_selection].start;
5827 framepos_t end = selection->time[clicked_selection].end;
5829 set_punch_range (start, end, _("set punch range from selection"));
5833 Editor::set_punch_from_edit_range ()
5835 if (_session == 0) {
5842 if (!get_edit_op_range (start, end)) {
5846 set_punch_range (start, end, _("set punch range from edit range"));
5850 Editor::set_punch_from_region ()
5852 framepos_t start = max_framepos;
5855 RegionSelection rs = get_regions_from_selection_and_entered ();
5861 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5862 if ((*i)->region()->position() < start) {
5863 start = (*i)->region()->position();
5865 if ((*i)->region()->last_frame() + 1 > end) {
5866 end = (*i)->region()->last_frame() + 1;
5870 set_punch_range (start, end, _("set punch range from region"));
5874 Editor::pitch_shift_region ()
5876 RegionSelection rs = get_regions_from_selection_and_entered ();
5878 RegionSelection audio_rs;
5879 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5880 if (dynamic_cast<AudioRegionView*> (*i)) {
5881 audio_rs.push_back (*i);
5885 if (audio_rs.empty()) {
5889 pitch_shift (audio_rs, 1.2);
5893 Editor::transpose_region ()
5895 RegionSelection rs = get_regions_from_selection_and_entered ();
5897 list<MidiRegionView*> midi_region_views;
5898 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5899 MidiRegionView* mrv = dynamic_cast<MidiRegionView*> (*i);
5901 midi_region_views.push_back (mrv);
5906 int const r = d.run ();
5907 if (r != RESPONSE_ACCEPT) {
5911 for (list<MidiRegionView*>::iterator i = midi_region_views.begin(); i != midi_region_views.end(); ++i) {
5912 (*i)->midi_region()->transpose (d.semitones ());
5917 Editor::set_tempo_from_region ()
5919 RegionSelection rs = get_regions_from_selection_and_entered ();
5921 if (!_session || rs.empty()) {
5925 RegionView* rv = rs.front();
5927 define_one_bar (rv->region()->position(), rv->region()->last_frame() + 1);
5931 Editor::use_range_as_bar ()
5933 framepos_t start, end;
5934 if (get_edit_op_range (start, end)) {
5935 define_one_bar (start, end);
5940 Editor::define_one_bar (framepos_t start, framepos_t end)
5942 framepos_t length = end - start;
5944 const Meter& m (_session->tempo_map().meter_at (start));
5946 /* length = 1 bar */
5948 /* now we want frames per beat.
5949 we have frames per bar, and beats per bar, so ...
5952 /* XXXX METER MATH */
5954 double frames_per_beat = length / m.divisions_per_bar();
5956 /* beats per minute = */
5958 double beats_per_minute = (_session->frame_rate() * 60.0) / frames_per_beat;
5960 /* now decide whether to:
5962 (a) set global tempo
5963 (b) add a new tempo marker
5967 const TempoSection& t (_session->tempo_map().tempo_section_at (start));
5969 bool do_global = false;
5971 if ((_session->tempo_map().n_tempos() == 1) && (_session->tempo_map().n_meters() == 1)) {
5973 /* only 1 tempo & 1 meter: ask if the user wants to set the tempo
5974 at the start, or create a new marker
5977 vector<string> options;
5978 options.push_back (_("Cancel"));
5979 options.push_back (_("Add new marker"));
5980 options.push_back (_("Set global tempo"));
5983 _("Define one bar"),
5984 _("Do you want to set the global tempo or add a new tempo marker?"),
5988 c.set_default_response (2);
6004 /* more than 1 tempo and/or meter section already, go ahead do the "usual":
6005 if the marker is at the region starter, change it, otherwise add
6010 begin_reversible_command (_("set tempo from region"));
6011 XMLNode& before (_session->tempo_map().get_state());
6014 _session->tempo_map().change_initial_tempo (beats_per_minute, t.note_type());
6015 } else if (t.frame() == start) {
6016 _session->tempo_map().change_existing_tempo_at (start, beats_per_minute, t.note_type());
6018 Timecode::BBT_Time bbt;
6019 _session->tempo_map().bbt_time (start, bbt);
6020 _session->tempo_map().add_tempo (Tempo (beats_per_minute, t.note_type()), bbt);
6023 XMLNode& after (_session->tempo_map().get_state());
6025 _session->add_command (new MementoCommand<TempoMap>(_session->tempo_map(), &before, &after));
6026 commit_reversible_command ();
6030 Editor::split_region_at_transients ()
6032 AnalysisFeatureList positions;
6034 RegionSelection rs = get_regions_from_selection_and_entered ();
6036 if (!_session || rs.empty()) {
6040 _session->begin_reversible_command (_("split regions"));
6042 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ) {
6044 RegionSelection::iterator tmp;
6049 boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion> ((*i)->region());
6051 if (ar && (ar->get_transients (positions) == 0)) {
6052 split_region_at_points ((*i)->region(), positions, true);
6059 _session->commit_reversible_command ();
6064 Editor::split_region_at_points (boost::shared_ptr<Region> r, AnalysisFeatureList& positions, bool can_ferret, bool select_new)
6066 bool use_rhythmic_rodent = false;
6068 boost::shared_ptr<Playlist> pl = r->playlist();
6070 list<boost::shared_ptr<Region> > new_regions;
6076 if (positions.empty()) {
6081 if (positions.size() > 20 && can_ferret) {
6082 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);
6083 MessageDialog msg (msgstr,
6086 Gtk::BUTTONS_OK_CANCEL);
6089 msg.add_button (_("Call for the Ferret!"), RESPONSE_APPLY);
6090 msg.set_secondary_text (_("Press OK to continue with this split operation\nor ask the Ferret dialog to tune the analysis"));
6092 msg.set_secondary_text (_("Press OK to continue with this split operation"));
6095 msg.set_title (_("Excessive split?"));
6098 int response = msg.run();
6104 case RESPONSE_APPLY:
6105 use_rhythmic_rodent = true;
6112 if (use_rhythmic_rodent) {
6113 show_rhythm_ferret ();
6117 AnalysisFeatureList::const_iterator x;
6119 pl->clear_changes ();
6120 pl->clear_owned_changes ();
6122 x = positions.begin();
6124 if (x == positions.end()) {
6129 pl->remove_region (r);
6133 while (x != positions.end()) {
6135 /* deal with positons that are out of scope of present region bounds */
6136 if (*x <= 0 || *x > r->length()) {
6141 /* file start = original start + how far we from the initial position ?
6144 framepos_t file_start = r->start() + pos;
6146 /* length = next position - current position
6149 framepos_t len = (*x) - pos;
6151 /* XXX we do we really want to allow even single-sample regions?
6152 shouldn't we have some kind of lower limit on region size?
6161 if (RegionFactory::region_name (new_name, r->name())) {
6165 /* do NOT announce new regions 1 by one, just wait till they are all done */
6169 plist.add (ARDOUR::Properties::start, file_start);
6170 plist.add (ARDOUR::Properties::length, len);
6171 plist.add (ARDOUR::Properties::name, new_name);
6172 plist.add (ARDOUR::Properties::layer, 0);
6174 boost::shared_ptr<Region> nr = RegionFactory::create (r->sources(), plist, false);
6175 /* because we set annouce to false, manually add the new region to the
6178 RegionFactory::map_add (nr);
6180 pl->add_region (nr, r->position() + pos);
6183 new_regions.push_front(nr);
6192 RegionFactory::region_name (new_name, r->name());
6194 /* Add the final region */
6197 plist.add (ARDOUR::Properties::start, r->start() + pos);
6198 plist.add (ARDOUR::Properties::length, r->last_frame() - (r->position() + pos) + 1);
6199 plist.add (ARDOUR::Properties::name, new_name);
6200 plist.add (ARDOUR::Properties::layer, 0);
6202 boost::shared_ptr<Region> nr = RegionFactory::create (r->sources(), plist, false);
6203 /* because we set annouce to false, manually add the new region to the
6206 RegionFactory::map_add (nr);
6207 pl->add_region (nr, r->position() + pos);
6210 new_regions.push_front(nr);
6215 /* We might have removed regions, which alters other regions' layering_index,
6216 so we need to do a recursive diff here.
6218 vector<Command*> cmds;
6220 _session->add_commands (cmds);
6222 _session->add_command (new StatefulDiffCommand (pl));
6226 for (list<boost::shared_ptr<Region> >::iterator i = new_regions.begin(); i != new_regions.end(); ++i){
6227 set_selected_regionview_from_region_list ((*i), Selection::Add);
6233 Editor::place_transient()
6239 RegionSelection rs = get_regions_from_selection_and_edit_point ();
6245 framepos_t where = get_preferred_edit_position();
6247 _session->begin_reversible_command (_("place transient"));
6249 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6250 framepos_t position = (*r)->region()->position();
6251 (*r)->region()->add_transient(where - position);
6254 _session->commit_reversible_command ();
6258 Editor::remove_transient(ArdourCanvas::Item* item)
6264 ArdourCanvas::Line* _line = reinterpret_cast<ArdourCanvas::Line*> (item);
6267 AudioRegionView* _arv = reinterpret_cast<AudioRegionView*> (item->get_data ("regionview"));
6268 _arv->remove_transient (*(float*) _line->get_data ("position"));
6272 Editor::snap_regions_to_grid ()
6274 list <boost::shared_ptr<Playlist > > used_playlists;
6276 RegionSelection rs = get_regions_from_selection_and_entered ();
6278 if (!_session || rs.empty()) {
6282 _session->begin_reversible_command (_("snap regions to grid"));
6284 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6286 boost::shared_ptr<Playlist> pl = (*r)->region()->playlist();
6288 if (!pl->frozen()) {
6289 /* we haven't seen this playlist before */
6291 /* remember used playlists so we can thaw them later */
6292 used_playlists.push_back(pl);
6296 framepos_t start_frame = (*r)->region()->first_frame ();
6297 snap_to (start_frame);
6298 (*r)->region()->set_position (start_frame);
6301 while (used_playlists.size() > 0) {
6302 list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
6304 used_playlists.pop_front();
6307 _session->commit_reversible_command ();
6311 Editor::close_region_gaps ()
6313 list <boost::shared_ptr<Playlist > > used_playlists;
6315 RegionSelection rs = get_regions_from_selection_and_entered ();
6317 if (!_session || rs.empty()) {
6321 Dialog dialog (_("Close Region Gaps"));
6324 table.set_spacings (12);
6325 table.set_border_width (12);
6326 Label* l = manage (left_aligned_label (_("Crossfade length")));
6327 table.attach (*l, 0, 1, 0, 1);
6329 SpinButton spin_crossfade (1, 0);
6330 spin_crossfade.set_range (0, 15);
6331 spin_crossfade.set_increments (1, 1);
6332 spin_crossfade.set_value (5);
6333 table.attach (spin_crossfade, 1, 2, 0, 1);
6335 table.attach (*manage (new Label (_("ms"))), 2, 3, 0, 1);
6337 l = manage (left_aligned_label (_("Pull-back length")));
6338 table.attach (*l, 0, 1, 1, 2);
6340 SpinButton spin_pullback (1, 0);
6341 spin_pullback.set_range (0, 100);
6342 spin_pullback.set_increments (1, 1);
6343 spin_pullback.set_value(30);
6344 table.attach (spin_pullback, 1, 2, 1, 2);
6346 table.attach (*manage (new Label (_("ms"))), 2, 3, 1, 2);
6348 dialog.get_vbox()->pack_start (table);
6349 dialog.add_button (Stock::CANCEL, RESPONSE_CANCEL);
6350 dialog.add_button (_("Ok"), RESPONSE_ACCEPT);
6353 if (dialog.run () == RESPONSE_CANCEL) {
6357 framepos_t crossfade_len = spin_crossfade.get_value();
6358 framepos_t pull_back_frames = spin_pullback.get_value();
6360 crossfade_len = lrintf (crossfade_len * _session->frame_rate()/1000);
6361 pull_back_frames = lrintf (pull_back_frames * _session->frame_rate()/1000);
6363 /* Iterate over the region list and make adjacent regions overlap by crossfade_len_ms */
6365 _session->begin_reversible_command (_("close region gaps"));
6368 boost::shared_ptr<Region> last_region;
6370 rs.sort_by_position_and_track();
6372 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6374 boost::shared_ptr<Playlist> pl = (*r)->region()->playlist();
6376 if (!pl->frozen()) {
6377 /* we haven't seen this playlist before */
6379 /* remember used playlists so we can thaw them later */
6380 used_playlists.push_back(pl);
6384 framepos_t position = (*r)->region()->position();
6386 if (idx == 0 || position < last_region->position()){
6387 last_region = (*r)->region();
6392 (*r)->region()->trim_front( (position - pull_back_frames));
6393 last_region->trim_end( (position - pull_back_frames + crossfade_len));
6395 last_region = (*r)->region();
6400 while (used_playlists.size() > 0) {
6401 list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
6403 used_playlists.pop_front();
6406 _session->commit_reversible_command ();
6410 Editor::tab_to_transient (bool forward)
6412 AnalysisFeatureList positions;
6414 RegionSelection rs = get_regions_from_selection_and_entered ();
6420 framepos_t pos = _session->audible_frame ();
6422 if (!selection->tracks.empty()) {
6424 /* don't waste time searching for transients in duplicate playlists.
6427 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
6429 for (TrackViewList::iterator t = ts.begin(); t != ts.end(); ++t) {
6431 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*t);
6434 boost::shared_ptr<Track> tr = rtv->track();
6436 boost::shared_ptr<Playlist> pl = tr->playlist ();
6438 framepos_t result = pl->find_next_transient (pos, forward ? 1 : -1);
6441 positions.push_back (result);
6454 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6455 (*r)->region()->get_transients (positions);
6459 TransientDetector::cleanup_transients (positions, _session->frame_rate(), 3.0);
6462 AnalysisFeatureList::iterator x;
6464 for (x = positions.begin(); x != positions.end(); ++x) {
6470 if (x != positions.end ()) {
6471 _session->request_locate (*x);
6475 AnalysisFeatureList::reverse_iterator x;
6477 for (x = positions.rbegin(); x != positions.rend(); ++x) {
6483 if (x != positions.rend ()) {
6484 _session->request_locate (*x);
6490 Editor::playhead_forward_to_grid ()
6496 framepos_t pos = playhead_cursor->current_frame ();
6497 if (pos < max_framepos - 1) {
6499 snap_to_internal (pos, RoundUpAlways, false);
6500 _session->request_locate (pos);
6506 Editor::playhead_backward_to_grid ()
6512 framepos_t pos = playhead_cursor->current_frame ();
6515 snap_to_internal (pos, RoundDownAlways, false);
6516 _session->request_locate (pos);
6521 Editor::set_track_height (Height h)
6523 TrackSelection& ts (selection->tracks);
6525 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
6526 (*x)->set_height_enum (h);
6531 Editor::toggle_tracks_active ()
6533 TrackSelection& ts (selection->tracks);
6535 bool target = false;
6541 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
6542 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*x);
6546 target = !rtv->_route->active();
6549 rtv->_route->set_active (target, this);
6555 Editor::remove_tracks ()
6557 TrackSelection& ts (selection->tracks);
6563 vector<string> choices;
6567 const char* trackstr;
6569 vector<boost::shared_ptr<Route> > routes;
6570 bool special_bus = false;
6572 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
6573 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*x);
6577 if (rtv->is_track()) {
6582 routes.push_back (rtv->_route);
6584 if (rtv->route()->is_master() || rtv->route()->is_monitor()) {
6589 if (special_bus && !Config->get_allow_special_bus_removal()) {
6590 MessageDialog msg (_("That would be bad news ...."),
6594 msg.set_secondary_text (string_compose (_(
6595 "Removing the master or monitor bus is such a bad idea\n\
6596 that %1 is not going to allow it.\n\
6598 If you really want to do this sort of thing\n\
6599 edit your ardour.rc file to set the\n\
6600 \"allow-special-bus-removal\" option to be \"yes\""), PROGRAM_NAME));
6607 if (ntracks + nbusses == 0) {
6611 // XXX should be using gettext plural forms, maybe?
6613 trackstr = _("tracks");
6615 trackstr = _("track");
6619 busstr = _("busses");
6626 prompt = string_compose (_("Do you really want to remove %1 %2 and %3 %4?\n"
6627 "(You may also lose the playlists associated with the %2)\n\n"
6628 "This action cannot be undone, and the session file will be overwritten!"),
6629 ntracks, trackstr, nbusses, busstr);
6631 prompt = string_compose (_("Do you really want to remove %1 %2?\n"
6632 "(You may also lose the playlists associated with the %2)\n\n"
6633 "This action cannot be undone, and the session file will be overwritten!"),
6636 } else if (nbusses) {
6637 prompt = string_compose (_("Do you really want to remove %1 %2?\n\n"
6638 "This action cannot be undone, and the session file will be overwritten"),
6642 choices.push_back (_("No, do nothing."));
6643 if (ntracks + nbusses > 1) {
6644 choices.push_back (_("Yes, remove them."));
6646 choices.push_back (_("Yes, remove it."));
6651 title = string_compose (_("Remove %1"), trackstr);
6653 title = string_compose (_("Remove %1"), busstr);
6656 Choice prompter (title, prompt, choices);
6658 if (prompter.run () != 1) {
6663 Session::StateProtector sp (_session);
6664 DisplaySuspender ds;
6665 for (vector<boost::shared_ptr<Route> >::iterator x = routes.begin(); x != routes.end(); ++x) {
6666 _session->remove_route (*x);
6672 Editor::do_insert_time ()
6674 if (selection->tracks.empty()) {
6678 InsertTimeDialog d (*this);
6679 int response = d.run ();
6681 if (response != RESPONSE_OK) {
6685 if (d.distance() == 0) {
6689 InsertTimeOption opt = d.intersected_region_action ();
6692 get_preferred_edit_position(),
6698 d.move_glued_markers(),
6699 d.move_locked_markers(),
6705 Editor::insert_time (
6706 framepos_t pos, framecnt_t frames, InsertTimeOption opt,
6707 bool all_playlists, bool ignore_music_glue, bool markers_too, bool glued_markers_too, bool locked_markers_too, bool tempo_too
6710 bool commit = false;
6712 if (Config->get_edit_mode() == Lock) {
6716 begin_reversible_command (_("insert time"));
6718 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
6720 for (TrackViewList::iterator x = ts.begin(); x != ts.end(); ++x) {
6724 /* don't operate on any playlist more than once, which could
6725 * happen if "all playlists" is enabled, but there is more
6726 * than 1 track using playlists "from" a given track.
6729 set<boost::shared_ptr<Playlist> > pl;
6731 if (all_playlists) {
6732 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*x);
6734 vector<boost::shared_ptr<Playlist> > all = _session->playlists->playlists_for_track (rtav->track ());
6735 for (vector<boost::shared_ptr<Playlist> >::iterator p = all.begin(); p != all.end(); ++p) {
6740 if ((*x)->playlist ()) {
6741 pl.insert ((*x)->playlist ());
6745 for (set<boost::shared_ptr<Playlist> >::iterator i = pl.begin(); i != pl.end(); ++i) {
6747 (*i)->clear_changes ();
6748 (*i)->clear_owned_changes ();
6750 if (opt == SplitIntersected) {
6754 (*i)->shift (pos, frames, (opt == MoveIntersected), ignore_music_glue);
6756 vector<Command*> cmds;
6758 _session->add_commands (cmds);
6760 _session->add_command (new StatefulDiffCommand (*i));
6765 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*x);
6767 rtav->route ()->shift (pos, frames);
6775 XMLNode& before (_session->locations()->get_state());
6776 Locations::LocationList copy (_session->locations()->list());
6778 for (Locations::LocationList::iterator i = copy.begin(); i != copy.end(); ++i) {
6780 Locations::LocationList::const_iterator tmp;
6782 bool const was_locked = (*i)->locked ();
6783 if (locked_markers_too) {
6787 if ((*i)->position_lock_style() == AudioTime || glued_markers_too) {
6789 if ((*i)->start() >= pos) {
6790 (*i)->set_start ((*i)->start() + frames);
6791 if (!(*i)->is_mark()) {
6792 (*i)->set_end ((*i)->end() + frames);
6805 XMLNode& after (_session->locations()->get_state());
6806 _session->add_command (new MementoCommand<Locations>(*_session->locations(), &before, &after));
6811 _session->tempo_map().insert_time (pos, frames);
6815 commit_reversible_command ();
6820 Editor::fit_selected_tracks ()
6822 if (!selection->tracks.empty()) {
6823 fit_tracks (selection->tracks);
6827 /* no selected tracks - use tracks with selected regions */
6829 if (!selection->regions.empty()) {
6830 for (RegionSelection::iterator r = selection->regions.begin(); r != selection->regions.end(); ++r) {
6831 tvl.push_back (&(*r)->get_time_axis_view ());
6837 } else if (internal_editing()) {
6838 /* no selected tracks, or regions, but in internal edit mode, so follow the mouse and use
6841 if (entered_track) {
6842 tvl.push_back (entered_track);
6851 Editor::fit_tracks (TrackViewList & tracks)
6853 if (tracks.empty()) {
6857 uint32_t child_heights = 0;
6858 int visible_tracks = 0;
6860 for (TrackSelection::iterator t = tracks.begin(); t != tracks.end(); ++t) {
6862 if (!(*t)->marked_for_display()) {
6866 child_heights += (*t)->effective_height() - (*t)->current_height();
6870 /* compute the per-track height from:
6872 total canvas visible height -
6873 height that will be taken by visible children of selected
6874 tracks - height of the ruler/hscroll area
6876 uint32_t h = (uint32_t) floor ((trackviews_height() - child_heights) / visible_tracks);
6877 double first_y_pos = DBL_MAX;
6879 if (h < TimeAxisView::preset_height (HeightSmall)) {
6880 MessageDialog msg (*this, _("There are too many tracks to fit in the current window"));
6881 /* too small to be displayed */
6885 undo_visual_stack.push_back (current_visual_state (true));
6886 no_save_visual = true;
6888 /* build a list of all tracks, including children */
6891 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
6893 TimeAxisView::Children c = (*i)->get_child_list ();
6894 for (TimeAxisView::Children::iterator j = c.begin(); j != c.end(); ++j) {
6895 all.push_back (j->get());
6899 bool prev_was_selected = false;
6900 bool is_selected = tracks.contains (all.front());
6901 bool next_is_selected;
6903 for (TrackViewList::iterator t = all.begin(); t != all.end(); ++t) {
6905 TrackViewList::iterator next;
6910 if (next != all.end()) {
6911 next_is_selected = tracks.contains (*next);
6913 next_is_selected = false;
6916 if ((*t)->marked_for_display ()) {
6918 (*t)->set_height (h);
6919 first_y_pos = std::min ((*t)->y_position (), first_y_pos);
6921 if (prev_was_selected && next_is_selected) {
6922 hide_track_in_display (*t);
6927 prev_was_selected = is_selected;
6928 is_selected = next_is_selected;
6932 set the controls_layout height now, because waiting for its size
6933 request signal handler will cause the vertical adjustment setting to fail
6936 controls_layout.property_height () = _full_canvas_height;
6937 vertical_adjustment.set_value (first_y_pos);
6939 redo_visual_stack.push_back (current_visual_state (true));
6941 visible_tracks_selector.set_text (_("Sel"));
6945 Editor::save_visual_state (uint32_t n)
6947 while (visual_states.size() <= n) {
6948 visual_states.push_back (0);
6951 if (visual_states[n] != 0) {
6952 delete visual_states[n];
6955 visual_states[n] = current_visual_state (true);
6960 Editor::goto_visual_state (uint32_t n)
6962 if (visual_states.size() <= n) {
6966 if (visual_states[n] == 0) {
6970 use_visual_state (*visual_states[n]);
6974 Editor::start_visual_state_op (uint32_t n)
6976 save_visual_state (n);
6978 PopUp* pup = new PopUp (WIN_POS_MOUSE, 1000, true);
6980 snprintf (buf, sizeof (buf), _("Saved view %u"), n+1);
6981 pup->set_text (buf);
6986 Editor::cancel_visual_state_op (uint32_t n)
6988 goto_visual_state (n);
6992 Editor::toggle_region_mute ()
6994 if (_ignore_region_action) {
6998 RegionSelection rs = get_regions_from_selection_and_entered ();
7004 if (rs.size() > 1) {
7005 begin_reversible_command (_("mute regions"));
7007 begin_reversible_command (_("mute region"));
7010 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
7012 (*i)->region()->playlist()->clear_changes ();
7013 (*i)->region()->set_muted (!(*i)->region()->muted ());
7014 _session->add_command (new StatefulDiffCommand ((*i)->region()->playlist()));
7018 commit_reversible_command ();
7022 Editor::combine_regions ()
7024 /* foreach track with selected regions, take all selected regions
7025 and join them into a new region containing the subregions (as a
7029 typedef set<RouteTimeAxisView*> RTVS;
7032 if (selection->regions.empty()) {
7036 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
7037 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(&(*i)->get_time_axis_view());
7040 tracks.insert (rtv);
7044 begin_reversible_command (_("combine regions"));
7046 vector<RegionView*> new_selection;
7048 for (RTVS::iterator i = tracks.begin(); i != tracks.end(); ++i) {
7051 if ((rv = (*i)->combine_regions ()) != 0) {
7052 new_selection.push_back (rv);
7056 selection->clear_regions ();
7057 for (vector<RegionView*>::iterator i = new_selection.begin(); i != new_selection.end(); ++i) {
7058 selection->add (*i);
7061 commit_reversible_command ();
7065 Editor::uncombine_regions ()
7067 typedef set<RouteTimeAxisView*> RTVS;
7070 if (selection->regions.empty()) {
7074 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
7075 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(&(*i)->get_time_axis_view());
7078 tracks.insert (rtv);
7082 begin_reversible_command (_("uncombine regions"));
7084 for (RTVS::iterator i = tracks.begin(); i != tracks.end(); ++i) {
7085 (*i)->uncombine_regions ();
7088 commit_reversible_command ();
7092 Editor::toggle_midi_input_active (bool flip_others)
7095 boost::shared_ptr<RouteList> rl (new RouteList);
7097 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
7098 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
7104 boost::shared_ptr<MidiTrack> mt = rtav->midi_track();
7107 rl->push_back (rtav->route());
7108 onoff = !mt->input_active();
7112 _session->set_exclusive_input_active (rl, onoff, flip_others);
7119 lock_dialog = new Gtk::Dialog (string_compose (_("%1: Locked"), PROGRAM_NAME), true);
7121 Gtk::Image* padlock = manage (new Gtk::Image (ARDOUR_UI_UTILS::get_icon ("padlock_closed")));
7122 lock_dialog->get_vbox()->pack_start (*padlock);
7124 ArdourButton* b = manage (new ArdourButton);
7125 b->set_name ("lock button");
7126 b->set_text (_("Click to unlock"));
7127 b->signal_clicked.connect (sigc::mem_fun (*this, &Editor::unlock));
7128 lock_dialog->get_vbox()->pack_start (*b);
7130 lock_dialog->get_vbox()->show_all ();
7131 lock_dialog->set_size_request (200, 200);
7135 /* The global menu bar continues to be accessible to applications
7136 with modal dialogs, which means that we need to desensitize
7137 all items in the menu bar. Since those items are really just
7138 proxies for actions, that means disabling all actions.
7140 ActionManager::disable_all_actions ();
7142 lock_dialog->present ();
7148 lock_dialog->hide ();
7151 ActionManager::pop_action_state ();
7154 if (ARDOUR_UI::config()->get_lock_gui_after_seconds()) {
7155 start_lock_event_timing ();
7160 Editor::bring_in_callback (Gtk::Label* label, uint32_t n, uint32_t total, string name)
7162 Gtkmm2ext::UI::instance()->call_slot (invalidator (*this), boost::bind (&Editor::update_bring_in_message, this, label, n, total, name));
7166 Editor::update_bring_in_message (Gtk::Label* label, uint32_t n, uint32_t total, string name)
7168 label->set_text (string_compose ("Copying %1, %2 of %3", name, n, total));
7169 Gtkmm2ext::UI::instance()->flush_pending ();
7173 Editor::bring_all_sources_into_session ()
7180 ArdourDialog w (_("Moving embedded files into session folder"));
7181 w.get_vbox()->pack_start (msg);
7184 /* flush all pending GUI events because we're about to start copying
7188 Gtkmm2ext::UI::instance()->flush_pending ();
7192 _session->bring_all_sources_into_session (boost::bind (&Editor::bring_in_callback, this, &msg, _1, _2, _3));