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, nfpp);
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 // n.b. -1 because AudioRange::end is one past the end, but coverage expects inclusive ranges
2707 case Evoral::OverlapNone:
2715 * - selected tracks, or if there are none...
2716 * - tracks containing selected regions, or if there are none...
2721 Editor::get_tracks_for_range_action () const
2725 if (selection->tracks.empty()) {
2727 /* use tracks with selected regions */
2729 RegionSelection rs = selection->regions;
2731 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
2732 TimeAxisView* tv = &(*i)->get_time_axis_view();
2734 if (!t.contains (tv)) {
2740 /* no regions and no tracks: use all tracks */
2746 t = selection->tracks;
2749 return t.filter_to_unique_playlists();
2753 Editor::separate_regions_between (const TimeSelection& ts)
2755 bool in_command = false;
2756 boost::shared_ptr<Playlist> playlist;
2757 RegionSelection new_selection;
2759 TrackViewList tmptracks = get_tracks_for_range_action ();
2760 sort_track_selection (tmptracks);
2762 for (TrackSelection::iterator i = tmptracks.begin(); i != tmptracks.end(); ++i) {
2764 RouteTimeAxisView* rtv;
2766 if ((rtv = dynamic_cast<RouteTimeAxisView*> ((*i))) != 0) {
2768 if (rtv->is_track()) {
2770 /* no edits to destructive tracks */
2772 if (rtv->track()->destructive()) {
2776 if ((playlist = rtv->playlist()) != 0) {
2778 playlist->clear_changes ();
2780 /* XXX need to consider musical time selections here at some point */
2782 double speed = rtv->track()->speed();
2785 for (list<AudioRange>::const_iterator t = ts.begin(); t != ts.end(); ++t) {
2787 sigc::connection c = rtv->view()->RegionViewAdded.connect (
2788 sigc::mem_fun(*this, &Editor::collect_new_region_view));
2790 latest_regionviews.clear ();
2792 playlist->partition ((framepos_t)((*t).start * speed),
2793 (framepos_t)((*t).end * speed), false);
2797 if (!latest_regionviews.empty()) {
2799 rtv->view()->foreach_regionview (sigc::bind (
2800 sigc::ptr_fun (add_if_covered),
2801 &(*t), &new_selection));
2804 begin_reversible_command (_("separate"));
2808 /* pick up changes to existing regions */
2810 vector<Command*> cmds;
2811 playlist->rdiff (cmds);
2812 _session->add_commands (cmds);
2814 /* pick up changes to the playlist itself (adds/removes)
2817 _session->add_command(new StatefulDiffCommand (playlist));
2826 // selection->set (new_selection);
2828 commit_reversible_command ();
2832 struct PlaylistState {
2833 boost::shared_ptr<Playlist> playlist;
2837 /** Take tracks from get_tracks_for_range_action and cut any regions
2838 * on those tracks so that the tracks are empty over the time
2842 Editor::separate_region_from_selection ()
2844 /* preferentially use *all* ranges in the time selection if we're in range mode
2845 to allow discontiguous operation, since get_edit_op_range() currently
2846 returns a single range.
2849 if (!selection->time.empty()) {
2851 separate_regions_between (selection->time);
2858 if (get_edit_op_range (start, end)) {
2860 AudioRange ar (start, end, 1);
2864 separate_regions_between (ts);
2870 Editor::separate_region_from_punch ()
2872 Location* loc = _session->locations()->auto_punch_location();
2874 separate_regions_using_location (*loc);
2879 Editor::separate_region_from_loop ()
2881 Location* loc = _session->locations()->auto_loop_location();
2883 separate_regions_using_location (*loc);
2888 Editor::separate_regions_using_location (Location& loc)
2890 if (loc.is_mark()) {
2894 AudioRange ar (loc.start(), loc.end(), 1);
2899 separate_regions_between (ts);
2902 /** Separate regions under the selected region */
2904 Editor::separate_under_selected_regions ()
2906 vector<PlaylistState> playlists;
2910 rs = get_regions_from_selection_and_entered();
2912 if (!_session || rs.empty()) {
2916 begin_reversible_command (_("separate region under"));
2918 list<boost::shared_ptr<Region> > regions_to_remove;
2920 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
2921 // we can't just remove the region(s) in this loop because
2922 // this removes them from the RegionSelection, and they thus
2923 // disappear from underneath the iterator, and the ++i above
2924 // SEGVs in a puzzling fashion.
2926 // so, first iterate over the regions to be removed from rs and
2927 // add them to the regions_to_remove list, and then
2928 // iterate over the list to actually remove them.
2930 regions_to_remove.push_back ((*i)->region());
2933 for (list<boost::shared_ptr<Region> >::iterator rl = regions_to_remove.begin(); rl != regions_to_remove.end(); ++rl) {
2935 boost::shared_ptr<Playlist> playlist = (*rl)->playlist();
2938 // is this check necessary?
2942 vector<PlaylistState>::iterator i;
2944 //only take state if this is a new playlist.
2945 for (i = playlists.begin(); i != playlists.end(); ++i) {
2946 if ((*i).playlist == playlist) {
2951 if (i == playlists.end()) {
2953 PlaylistState before;
2954 before.playlist = playlist;
2955 before.before = &playlist->get_state();
2957 playlist->freeze ();
2958 playlists.push_back(before);
2961 //Partition on the region bounds
2962 playlist->partition ((*rl)->first_frame() - 1, (*rl)->last_frame() + 1, true);
2964 //Re-add region that was just removed due to the partition operation
2965 playlist->add_region( (*rl), (*rl)->first_frame() );
2968 vector<PlaylistState>::iterator pl;
2970 for (pl = playlists.begin(); pl != playlists.end(); ++pl) {
2971 (*pl).playlist->thaw ();
2972 _session->add_command(new MementoCommand<Playlist>(*(*pl).playlist, (*pl).before, &(*pl).playlist->get_state()));
2975 commit_reversible_command ();
2979 Editor::crop_region_to_selection ()
2981 if (!selection->time.empty()) {
2983 crop_region_to (selection->time.start(), selection->time.end_frame());
2990 if (get_edit_op_range (start, end)) {
2991 crop_region_to (start, end);
2998 Editor::crop_region_to (framepos_t start, framepos_t end)
3000 vector<boost::shared_ptr<Playlist> > playlists;
3001 boost::shared_ptr<Playlist> playlist;
3004 if (selection->tracks.empty()) {
3005 ts = track_views.filter_to_unique_playlists();
3007 ts = selection->tracks.filter_to_unique_playlists ();
3010 sort_track_selection (ts);
3012 for (TrackSelection::iterator i = ts.begin(); i != ts.end(); ++i) {
3014 RouteTimeAxisView* rtv;
3016 if ((rtv = dynamic_cast<RouteTimeAxisView*> ((*i))) != 0) {
3018 boost::shared_ptr<Track> t = rtv->track();
3020 if (t != 0 && ! t->destructive()) {
3022 if ((playlist = rtv->playlist()) != 0) {
3023 playlists.push_back (playlist);
3029 if (playlists.empty()) {
3033 framepos_t the_start;
3037 begin_reversible_command (_("trim to selection"));
3039 for (vector<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
3041 boost::shared_ptr<Region> region;
3045 if ((region = (*i)->top_region_at(the_start)) == 0) {
3049 /* now adjust lengths to that we do the right thing
3050 if the selection extends beyond the region
3053 the_start = max (the_start, (framepos_t) region->position());
3054 if (max_framepos - the_start < region->length()) {
3055 the_end = the_start + region->length() - 1;
3057 the_end = max_framepos;
3059 the_end = min (end, the_end);
3060 cnt = the_end - the_start + 1;
3062 region->clear_changes ();
3063 region->trim_to (the_start, cnt);
3064 _session->add_command (new StatefulDiffCommand (region));
3067 commit_reversible_command ();
3071 Editor::region_fill_track ()
3073 RegionSelection rs = get_regions_from_selection_and_entered ();
3075 if (!_session || rs.empty()) {
3079 framepos_t const end = _session->current_end_frame ();
3081 begin_reversible_command (Operations::region_fill);
3083 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3085 boost::shared_ptr<Region> region ((*i)->region());
3087 boost::shared_ptr<Playlist> pl = region->playlist();
3089 if (end <= region->last_frame()) {
3093 double times = (double) (end - region->last_frame()) / (double) region->length();
3099 pl->clear_changes ();
3100 pl->add_region (RegionFactory::create (region, true), region->last_frame(), times);
3101 _session->add_command (new StatefulDiffCommand (pl));
3104 commit_reversible_command ();
3108 Editor::region_fill_selection ()
3110 if (clicked_routeview == 0 || !clicked_routeview->is_audio_track()) {
3114 if (selection->time.empty()) {
3118 boost::shared_ptr<Region> region = _regions->get_single_selection ();
3123 framepos_t start = selection->time[clicked_selection].start;
3124 framepos_t end = selection->time[clicked_selection].end;
3126 boost::shared_ptr<Playlist> playlist;
3128 if (selection->tracks.empty()) {
3132 framepos_t selection_length = end - start;
3133 float times = (float)selection_length / region->length();
3135 begin_reversible_command (Operations::fill_selection);
3137 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
3139 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
3141 if ((playlist = (*i)->playlist()) == 0) {
3145 playlist->clear_changes ();
3146 playlist->add_region (RegionFactory::create (region, true), start, times);
3147 _session->add_command (new StatefulDiffCommand (playlist));
3150 commit_reversible_command ();
3154 Editor::set_region_sync_position ()
3156 set_sync_point (get_preferred_edit_position (), get_regions_from_selection_and_edit_point ());
3160 Editor::set_sync_point (framepos_t where, const RegionSelection& rs)
3162 bool in_command = false;
3164 for (RegionSelection::const_iterator r = rs.begin(); r != rs.end(); ++r) {
3166 if (!(*r)->region()->covers (where)) {
3170 boost::shared_ptr<Region> region ((*r)->region());
3173 begin_reversible_command (_("set sync point"));
3177 region->clear_changes ();
3178 region->set_sync_position (where);
3179 _session->add_command(new StatefulDiffCommand (region));
3183 commit_reversible_command ();
3187 /** Remove the sync positions of the selection */
3189 Editor::remove_region_sync ()
3191 RegionSelection rs = get_regions_from_selection_and_entered ();
3197 begin_reversible_command (_("remove region sync"));
3199 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3201 (*i)->region()->clear_changes ();
3202 (*i)->region()->clear_sync_position ();
3203 _session->add_command(new StatefulDiffCommand ((*i)->region()));
3206 commit_reversible_command ();
3210 Editor::naturalize_region ()
3212 RegionSelection rs = get_regions_from_selection_and_entered ();
3218 if (rs.size() > 1) {
3219 begin_reversible_command (_("move regions to original position"));
3221 begin_reversible_command (_("move region to original position"));
3224 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3225 (*i)->region()->clear_changes ();
3226 (*i)->region()->move_to_natural_position ();
3227 _session->add_command (new StatefulDiffCommand ((*i)->region()));
3230 commit_reversible_command ();
3234 Editor::align_regions (RegionPoint what)
3236 RegionSelection const rs = get_regions_from_selection_and_edit_point ();
3242 begin_reversible_command (_("align selection"));
3244 framepos_t const position = get_preferred_edit_position ();
3246 for (RegionSelection::const_iterator i = rs.begin(); i != rs.end(); ++i) {
3247 align_region_internal ((*i)->region(), what, position);
3250 commit_reversible_command ();
3253 struct RegionSortByTime {
3254 bool operator() (const RegionView* a, const RegionView* b) {
3255 return a->region()->position() < b->region()->position();
3260 Editor::align_regions_relative (RegionPoint point)
3262 RegionSelection const rs = get_regions_from_selection_and_edit_point ();
3268 framepos_t const position = get_preferred_edit_position ();
3270 framepos_t distance = 0;
3274 list<RegionView*> sorted;
3275 rs.by_position (sorted);
3277 boost::shared_ptr<Region> r ((*sorted.begin())->region());
3282 if (position > r->position()) {
3283 distance = position - r->position();
3285 distance = r->position() - position;
3291 if (position > r->last_frame()) {
3292 distance = position - r->last_frame();
3293 pos = r->position() + distance;
3295 distance = r->last_frame() - position;
3296 pos = r->position() - distance;
3302 pos = r->adjust_to_sync (position);
3303 if (pos > r->position()) {
3304 distance = pos - r->position();
3306 distance = r->position() - pos;
3312 if (pos == r->position()) {
3316 begin_reversible_command (_("align selection (relative)"));
3318 /* move first one specially */
3320 r->clear_changes ();
3321 r->set_position (pos);
3322 _session->add_command(new StatefulDiffCommand (r));
3324 /* move rest by the same amount */
3328 for (list<RegionView*>::iterator i = sorted.begin(); i != sorted.end(); ++i) {
3330 boost::shared_ptr<Region> region ((*i)->region());
3332 region->clear_changes ();
3335 region->set_position (region->position() + distance);
3337 region->set_position (region->position() - distance);
3340 _session->add_command(new StatefulDiffCommand (region));
3344 commit_reversible_command ();
3348 Editor::align_region (boost::shared_ptr<Region> region, RegionPoint point, framepos_t position)
3350 begin_reversible_command (_("align region"));
3351 align_region_internal (region, point, position);
3352 commit_reversible_command ();
3356 Editor::align_region_internal (boost::shared_ptr<Region> region, RegionPoint point, framepos_t position)
3358 region->clear_changes ();
3362 region->set_position (region->adjust_to_sync (position));
3366 if (position > region->length()) {
3367 region->set_position (position - region->length());
3372 region->set_position (position);
3376 _session->add_command(new StatefulDiffCommand (region));
3380 Editor::trim_region_front ()
3386 Editor::trim_region_back ()
3388 trim_region (false);
3392 Editor::trim_region (bool front)
3394 framepos_t where = get_preferred_edit_position();
3395 RegionSelection rs = get_regions_from_selection_and_edit_point ();
3401 begin_reversible_command (front ? _("trim front") : _("trim back"));
3403 for (list<RegionView*>::const_iterator i = rs.by_layer().begin(); i != rs.by_layer().end(); ++i) {
3404 if (!(*i)->region()->locked()) {
3406 (*i)->region()->clear_changes ();
3409 (*i)->region()->trim_front (where);
3410 maybe_locate_with_edit_preroll ( where );
3412 (*i)->region()->trim_end (where);
3413 maybe_locate_with_edit_preroll ( where );
3416 _session->add_command (new StatefulDiffCommand ((*i)->region()));
3420 commit_reversible_command ();
3423 /** Trim the end of the selected regions to the position of the edit cursor */
3425 Editor::trim_region_to_loop ()
3427 Location* loc = _session->locations()->auto_loop_location();
3431 trim_region_to_location (*loc, _("trim to loop"));
3435 Editor::trim_region_to_punch ()
3437 Location* loc = _session->locations()->auto_punch_location();
3441 trim_region_to_location (*loc, _("trim to punch"));
3445 Editor::trim_region_to_location (const Location& loc, const char* str)
3447 RegionSelection rs = get_regions_from_selection_and_entered ();
3449 begin_reversible_command (str);
3451 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
3452 RegionView* rv = (*x);
3454 /* require region to span proposed trim */
3455 switch (rv->region()->coverage (loc.start(), loc.end())) {
3456 case Evoral::OverlapInternal:
3462 RouteTimeAxisView* tav = dynamic_cast<RouteTimeAxisView*> (&rv->get_time_axis_view());
3471 if (tav->track() != 0) {
3472 speed = tav->track()->speed();
3475 start = session_frame_to_track_frame (loc.start(), speed);
3476 end = session_frame_to_track_frame (loc.end(), speed);
3478 rv->region()->clear_changes ();
3479 rv->region()->trim_to (start, (end - start));
3480 _session->add_command(new StatefulDiffCommand (rv->region()));
3483 commit_reversible_command ();
3487 Editor::trim_region_to_previous_region_end ()
3489 return trim_to_region(false);
3493 Editor::trim_region_to_next_region_start ()
3495 return trim_to_region(true);
3499 Editor::trim_to_region(bool forward)
3501 RegionSelection rs = get_regions_from_selection_and_entered ();
3503 begin_reversible_command (_("trim to region"));
3505 boost::shared_ptr<Region> next_region;
3507 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
3509 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*x);
3515 AudioTimeAxisView* atav = dynamic_cast<AudioTimeAxisView*> (&arv->get_time_axis_view());
3523 if (atav->track() != 0) {
3524 speed = atav->track()->speed();
3528 boost::shared_ptr<Region> region = arv->region();
3529 boost::shared_ptr<Playlist> playlist (region->playlist());
3531 region->clear_changes ();
3535 next_region = playlist->find_next_region (region->first_frame(), Start, 1);
3541 region->trim_end((framepos_t) ( (next_region->first_frame() - 1) * speed));
3542 arv->region_changed (PropertyChange (ARDOUR::Properties::length));
3546 next_region = playlist->find_next_region (region->first_frame(), Start, 0);
3552 region->trim_front((framepos_t) ((next_region->last_frame() + 1) * speed));
3554 arv->region_changed (ARDOUR::bounds_change);
3557 _session->add_command(new StatefulDiffCommand (region));
3560 commit_reversible_command ();
3564 Editor::unfreeze_route ()
3566 if (clicked_routeview == 0 || !clicked_routeview->is_track()) {
3570 clicked_routeview->track()->unfreeze ();
3574 Editor::_freeze_thread (void* arg)
3576 return static_cast<Editor*>(arg)->freeze_thread ();
3580 Editor::freeze_thread ()
3582 /* create event pool because we may need to talk to the session */
3583 SessionEvent::create_per_thread_pool ("freeze events", 64);
3584 /* create per-thread buffers for process() tree to use */
3585 clicked_routeview->audio_track()->freeze_me (*current_interthread_info);
3586 current_interthread_info->done = true;
3591 Editor::freeze_route ()
3597 /* stop transport before we start. this is important */
3599 _session->request_transport_speed (0.0);
3601 /* wait for just a little while, because the above call is asynchronous */
3603 Glib::usleep (250000);
3605 if (clicked_routeview == 0 || !clicked_routeview->is_audio_track()) {
3609 if (!clicked_routeview->track()->bounceable (clicked_routeview->track()->main_outs(), true)) {
3611 _("This track/bus cannot be frozen because the signal adds or loses channels before reaching the outputs.\n"
3612 "This is typically caused by plugins that generate stereo output from mono input or vice versa.")
3614 d.set_title (_("Cannot freeze"));
3619 if (clicked_routeview->track()->has_external_redirects()) {
3620 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"
3621 "Freezing will only process the signal as far as the first send/insert/return."),
3622 clicked_routeview->track()->name()), true, MESSAGE_INFO, BUTTONS_NONE, true);
3624 d.add_button (_("Freeze anyway"), Gtk::RESPONSE_OK);
3625 d.add_button (_("Don't freeze"), Gtk::RESPONSE_CANCEL);
3626 d.set_title (_("Freeze Limits"));
3628 int response = d.run ();
3631 case Gtk::RESPONSE_CANCEL:
3638 InterThreadInfo itt;
3639 current_interthread_info = &itt;
3641 InterthreadProgressWindow ipw (current_interthread_info, _("Freeze"), _("Cancel Freeze"));
3643 pthread_create_and_store (X_("freezer"), &itt.thread, _freeze_thread, this);
3645 set_canvas_cursor (_cursors->wait);
3647 while (!itt.done && !itt.cancel) {
3648 gtk_main_iteration ();
3651 current_interthread_info = 0;
3652 set_canvas_cursor (current_canvas_cursor);
3656 Editor::bounce_range_selection (bool replace, bool enable_processing)
3658 if (selection->time.empty()) {
3662 TrackSelection views = selection->tracks;
3664 for (TrackViewList::iterator i = views.begin(); i != views.end(); ++i) {
3666 if (enable_processing) {
3668 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*i);
3670 if (rtv && rtv->track() && replace && enable_processing && !rtv->track()->bounceable (rtv->track()->main_outs(), false)) {
3672 _("You can't perform this operation because the processing of the signal "
3673 "will cause one or more of the tracks to end up with a region with more channels than this track has inputs.\n\n"
3674 "You can do this without processing, which is a different operation.")
3676 d.set_title (_("Cannot bounce"));
3683 framepos_t start = selection->time[clicked_selection].start;
3684 framepos_t end = selection->time[clicked_selection].end;
3685 framepos_t cnt = end - start + 1;
3687 begin_reversible_command (_("bounce range"));
3689 for (TrackViewList::iterator i = views.begin(); i != views.end(); ++i) {
3691 RouteTimeAxisView* rtv;
3693 if ((rtv = dynamic_cast<RouteTimeAxisView*> (*i)) == 0) {
3697 boost::shared_ptr<Playlist> playlist;
3699 if ((playlist = rtv->playlist()) == 0) {
3703 InterThreadInfo itt;
3705 playlist->clear_changes ();
3706 playlist->clear_owned_changes ();
3708 boost::shared_ptr<Region> r;
3710 if (enable_processing) {
3711 r = rtv->track()->bounce_range (start, start+cnt, itt, rtv->track()->main_outs(), false);
3713 r = rtv->track()->bounce_range (start, start+cnt, itt, boost::shared_ptr<Processor>(), false);
3721 list<AudioRange> ranges;
3722 ranges.push_back (AudioRange (start, start+cnt, 0));
3723 playlist->cut (ranges); // discard result
3724 playlist->add_region (r, start);
3727 vector<Command*> cmds;
3728 playlist->rdiff (cmds);
3729 _session->add_commands (cmds);
3731 _session->add_command (new StatefulDiffCommand (playlist));
3734 commit_reversible_command ();
3737 /** Delete selected regions, automation points or a time range */
3741 //special case: if the user is pointing in the editor/mixer strip, they may be trying to delete a plugin.
3742 //we need this because the editor-mixer strip is in the editor window, so it doesn't get the bindings from the mix window
3743 bool deleted = false;
3744 if ( current_mixer_strip && current_mixer_strip == MixerStrip::entered_mixer_strip() )
3745 deleted = current_mixer_strip->delete_processors ();
3751 /** Cut selected regions, automation points or a time range */
3758 /** Copy selected regions, automation points or a time range */
3766 /** @return true if a Cut, Copy or Clear is possible */
3768 Editor::can_cut_copy () const
3770 if (!selection->time.empty() || !selection->regions.empty() || !selection->points.empty())
3777 /** Cut, copy or clear selected regions, automation points or a time range.
3778 * @param op Operation (Delete, Cut, Copy or Clear)
3781 Editor::cut_copy (CutCopyOp op)
3783 /* only cancel selection if cut/copy is successful.*/
3789 opname = _("delete");
3798 opname = _("clear");
3802 /* if we're deleting something, and the mouse is still pressed,
3803 the thing we started a drag for will be gone when we release
3804 the mouse button(s). avoid this. see part 2 at the end of
3808 if (op == Delete || op == Cut || op == Clear) {
3809 if (_drags->active ()) {
3814 if ( op != Delete ) //"Delete" doesn't change copy/paste buf
3815 cut_buffer->clear ();
3817 if (entered_marker) {
3819 /* cut/delete op while pointing at a marker */
3822 Location* loc = find_location_from_marker (entered_marker, ignored);
3824 if (_session && loc) {
3825 Glib::signal_idle().connect (sigc::bind (sigc::mem_fun(*this, &Editor::really_remove_marker), loc));
3832 if (internal_editing()) {
3834 switch (effective_mouse_mode()) {
3837 begin_reversible_command (opname + ' ' + X_("MIDI"));
3839 commit_reversible_command ();
3848 bool did_edit = false;
3850 if (!selection->regions.empty() || !selection->points.empty()) {
3851 begin_reversible_command (opname + ' ' + _("objects"));
3854 if (!selection->regions.empty()) {
3855 cut_copy_regions (op, selection->regions);
3857 if (op == Cut || op == Delete) {
3858 selection->clear_regions ();
3862 if (!selection->points.empty()) {
3863 cut_copy_points (op);
3865 if (op == Cut || op == Delete) {
3866 selection->clear_points ();
3869 } else if (selection->time.empty()) {
3870 framepos_t start, end;
3871 /* no time selection, see if we can get an edit range
3874 if (get_edit_op_range (start, end)) {
3875 selection->set (start, end);
3877 } else if (!selection->time.empty()) {
3878 begin_reversible_command (opname + ' ' + _("range"));
3881 cut_copy_ranges (op);
3883 if (op == Cut || op == Delete) {
3884 selection->clear_time ();
3889 /* reset repeated paste state */
3892 commit_reversible_command ();
3895 if (op == Delete || op == Cut || op == Clear) {
3900 struct AutomationRecord {
3901 AutomationRecord () : state (0) , line(NULL) {}
3902 AutomationRecord (XMLNode* s, const AutomationLine* l) : state (s) , line (l) {}
3904 XMLNode* state; ///< state before any operation
3905 const AutomationLine* line; ///< line this came from
3906 boost::shared_ptr<Evoral::ControlList> copy; ///< copied events for the cut buffer
3909 /** Cut, copy or clear selected automation points.
3910 * @param op Operation (Cut, Copy or Clear)
3913 Editor::cut_copy_points (CutCopyOp op)
3915 if (selection->points.empty ()) {
3919 /* XXX: not ideal, as there may be more than one track involved in the point selection */
3920 _last_cut_copy_source_track = &selection->points.front()->line().trackview;
3922 /* Keep a record of the AutomationLists that we end up using in this operation */
3923 typedef std::map<boost::shared_ptr<AutomationList>, AutomationRecord> Lists;
3926 /* Go through all selected points, making an AutomationRecord for each distinct AutomationList */
3927 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
3928 const AutomationLine& line = (*i)->line();
3929 const boost::shared_ptr<AutomationList> al = line.the_list();
3930 if (lists.find (al) == lists.end ()) {
3931 /* We haven't seen this list yet, so make a record for it. This includes
3932 taking a copy of its current state, in case this is needed for undo later.
3934 lists[al] = AutomationRecord (&al->get_state (), &line);
3938 if (op == Cut || op == Copy) {
3939 /* This operation will involve putting things in the cut buffer, so create an empty
3940 ControlList for each of our source lists to put the cut buffer data in.
3942 framepos_t start = std::numeric_limits<framepos_t>::max();
3943 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
3944 i->second.copy = i->first->create (i->first->parameter (), i->first->descriptor());
3946 /* Calculate earliest start position of any point in selection. */
3947 start = std::min(start, i->second.line->session_position(i->first->begin()));
3950 /* Add all selected points to the relevant copy ControlLists */
3951 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
3952 boost::shared_ptr<AutomationList> al = (*i)->line().the_list();
3953 AutomationList::const_iterator j = (*i)->model ();
3954 lists[al].copy->fast_simple_add ((*j)->when, (*j)->value);
3957 /* Snap start time backwards, so copy/paste is snap aligned. */
3958 snap_to(start, RoundDownMaybe);
3960 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
3961 /* Correct this copy list so that it is relative to the earliest
3962 start time, so relative ordering between points is preserved
3963 when copying from several lists. */
3964 const AutomationLine* line = i->second.line;
3965 const double line_offset = line->time_converter().from(start);
3967 for (AutomationList::iterator j = i->second.copy->begin(); j != i->second.copy->end(); ++j) {
3968 (*j)->when -= line_offset;
3971 /* And add it to the cut buffer */
3972 cut_buffer->add (i->second.copy);
3976 if (op == Delete || op == Cut) {
3977 /* This operation needs to remove things from the main AutomationList, so do that now */
3979 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
3980 i->first->freeze ();
3983 /* Remove each selected point from its AutomationList */
3984 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
3985 boost::shared_ptr<AutomationList> al = (*i)->line().the_list();
3986 al->erase ((*i)->model ());
3989 /* Thaw the lists and add undo records for them */
3990 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
3991 boost::shared_ptr<AutomationList> al = i->first;
3993 _session->add_command (new MementoCommand<AutomationList> (*al.get(), i->second.state, &(al->get_state ())));
3998 /** Cut, copy or clear selected automation points.
3999 * @param op Operation (Cut, Copy or Clear)
4002 Editor::cut_copy_midi (CutCopyOp op)
4004 for (MidiRegionSelection::iterator i = selection->midi_regions.begin(); i != selection->midi_regions.end(); ++i) {
4005 MidiRegionView* mrv = dynamic_cast<MidiRegionView*>(*i);
4007 mrv->cut_copy_clear (op);
4009 /* XXX: not ideal, as there may be more than one track involved in the selection */
4010 _last_cut_copy_source_track = &mrv->get_time_axis_view();
4014 if (!selection->points.empty()) {
4015 cut_copy_points (op);
4016 if (op == Cut || op == Delete) {
4017 selection->clear_points ();
4022 struct lt_playlist {
4023 bool operator () (const PlaylistState& a, const PlaylistState& b) {
4024 return a.playlist < b.playlist;
4028 struct PlaylistMapping {
4030 boost::shared_ptr<Playlist> pl;
4032 PlaylistMapping (TimeAxisView* tvp) : tv (tvp) {}
4035 /** Remove `clicked_regionview' */
4037 Editor::remove_clicked_region ()
4039 if (clicked_routeview == 0 || clicked_regionview == 0) {
4043 boost::shared_ptr<Playlist> playlist = clicked_routeview->playlist();
4045 playlist->clear_changes ();
4046 playlist->clear_owned_changes ();
4047 playlist->remove_region (clicked_regionview->region());
4048 if (Config->get_edit_mode() == Ripple)
4049 playlist->ripple (clicked_regionview->region()->position(), -clicked_regionview->region()->length(), boost::shared_ptr<Region>());
4051 /* We might have removed regions, which alters other regions' layering_index,
4052 so we need to do a recursive diff here.
4054 vector<Command*> cmds;
4055 playlist->rdiff (cmds);
4056 _session->add_commands (cmds);
4058 _session->add_command(new StatefulDiffCommand (playlist));
4059 commit_reversible_command ();
4063 /** Remove the selected regions */
4065 Editor::remove_selected_regions ()
4067 RegionSelection rs = get_regions_from_selection_and_entered ();
4069 if (!_session || rs.empty()) {
4073 begin_reversible_command (_("remove region"));
4075 list<boost::shared_ptr<Region> > regions_to_remove;
4077 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
4078 // we can't just remove the region(s) in this loop because
4079 // this removes them from the RegionSelection, and they thus
4080 // disappear from underneath the iterator, and the ++i above
4081 // SEGVs in a puzzling fashion.
4083 // so, first iterate over the regions to be removed from rs and
4084 // add them to the regions_to_remove list, and then
4085 // iterate over the list to actually remove them.
4087 regions_to_remove.push_back ((*i)->region());
4090 vector<boost::shared_ptr<Playlist> > playlists;
4092 for (list<boost::shared_ptr<Region> >::iterator rl = regions_to_remove.begin(); rl != regions_to_remove.end(); ++rl) {
4094 boost::shared_ptr<Playlist> playlist = (*rl)->playlist();
4097 // is this check necessary?
4101 /* get_regions_from_selection_and_entered() guarantees that
4102 the playlists involved are unique, so there is no need
4106 playlists.push_back (playlist);
4108 playlist->clear_changes ();
4109 playlist->clear_owned_changes ();
4110 playlist->freeze ();
4111 playlist->remove_region (*rl);
4112 if (Config->get_edit_mode() == Ripple)
4113 playlist->ripple ((*rl)->position(), -(*rl)->length(), boost::shared_ptr<Region>());
4117 vector<boost::shared_ptr<Playlist> >::iterator pl;
4119 for (pl = playlists.begin(); pl != playlists.end(); ++pl) {
4122 /* We might have removed regions, which alters other regions' layering_index,
4123 so we need to do a recursive diff here.
4125 vector<Command*> cmds;
4126 (*pl)->rdiff (cmds);
4127 _session->add_commands (cmds);
4129 _session->add_command(new StatefulDiffCommand (*pl));
4132 commit_reversible_command ();
4135 /** Cut, copy or clear selected regions.
4136 * @param op Operation (Cut, Copy or Clear)
4139 Editor::cut_copy_regions (CutCopyOp op, RegionSelection& rs)
4141 /* we can't use a std::map here because the ordering is important, and we can't trivially sort
4142 a map when we want ordered access to both elements. i think.
4145 vector<PlaylistMapping> pmap;
4147 framepos_t first_position = max_framepos;
4149 typedef set<boost::shared_ptr<Playlist> > FreezeList;
4150 FreezeList freezelist;
4152 /* get ordering correct before we cut/copy */
4154 rs.sort_by_position_and_track ();
4156 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
4158 first_position = min ((framepos_t) (*x)->region()->position(), first_position);
4160 if (op == Cut || op == Clear || op == Delete) {
4161 boost::shared_ptr<Playlist> pl = (*x)->region()->playlist();
4164 FreezeList::iterator fl;
4166 // only take state if this is a new playlist.
4167 for (fl = freezelist.begin(); fl != freezelist.end(); ++fl) {
4173 if (fl == freezelist.end()) {
4174 pl->clear_changes();
4175 pl->clear_owned_changes ();
4177 freezelist.insert (pl);
4182 TimeAxisView* tv = &(*x)->get_time_axis_view();
4183 vector<PlaylistMapping>::iterator z;
4185 for (z = pmap.begin(); z != pmap.end(); ++z) {
4186 if ((*z).tv == tv) {
4191 if (z == pmap.end()) {
4192 pmap.push_back (PlaylistMapping (tv));
4196 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ) {
4198 boost::shared_ptr<Playlist> pl = (*x)->region()->playlist();
4201 /* region not yet associated with a playlist (e.g. unfinished
4208 TimeAxisView& tv = (*x)->get_time_axis_view();
4209 boost::shared_ptr<Playlist> npl;
4210 RegionSelection::iterator tmp;
4217 vector<PlaylistMapping>::iterator z;
4219 for (z = pmap.begin(); z != pmap.end(); ++z) {
4220 if ((*z).tv == &tv) {
4225 assert (z != pmap.end());
4228 npl = PlaylistFactory::create (pl->data_type(), *_session, "cutlist", true);
4236 boost::shared_ptr<Region> r = (*x)->region();
4237 boost::shared_ptr<Region> _xx;
4243 pl->remove_region (r);
4244 if (Config->get_edit_mode() == Ripple)
4245 pl->ripple (r->position(), -r->length(), boost::shared_ptr<Region>());
4249 _xx = RegionFactory::create (r);
4250 npl->add_region (_xx, r->position() - first_position);
4251 pl->remove_region (r);
4252 if (Config->get_edit_mode() == Ripple)
4253 pl->ripple (r->position(), -r->length(), boost::shared_ptr<Region>());
4257 /* copy region before adding, so we're not putting same object into two different playlists */
4258 npl->add_region (RegionFactory::create (r), r->position() - first_position);
4262 pl->remove_region (r);
4263 if (Config->get_edit_mode() == Ripple)
4264 pl->ripple (r->position(), -r->length(), boost::shared_ptr<Region>());
4273 list<boost::shared_ptr<Playlist> > foo;
4275 /* the pmap is in the same order as the tracks in which selected regions occured */
4277 for (vector<PlaylistMapping>::iterator i = pmap.begin(); i != pmap.end(); ++i) {
4280 foo.push_back ((*i).pl);
4285 cut_buffer->set (foo);
4289 _last_cut_copy_source_track = 0;
4291 _last_cut_copy_source_track = pmap.front().tv;
4295 for (FreezeList::iterator pl = freezelist.begin(); pl != freezelist.end(); ++pl) {
4298 /* We might have removed regions, which alters other regions' layering_index,
4299 so we need to do a recursive diff here.
4301 vector<Command*> cmds;
4302 (*pl)->rdiff (cmds);
4303 _session->add_commands (cmds);
4305 _session->add_command (new StatefulDiffCommand (*pl));
4310 Editor::cut_copy_ranges (CutCopyOp op)
4312 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4314 /* Sort the track selection now, so that it if is used, the playlists
4315 selected by the calls below to cut_copy_clear are in the order that
4316 their tracks appear in the editor. This makes things like paste
4317 of ranges work properly.
4320 sort_track_selection (ts);
4323 if (!entered_track) {
4326 ts.push_back (entered_track);
4329 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4330 (*i)->cut_copy_clear (*selection, op);
4335 Editor::paste (float times, bool from_context)
4337 DEBUG_TRACE (DEBUG::CutNPaste, "paste to preferred edit pos\n");
4339 paste_internal (get_preferred_edit_position (false, from_context), times);
4343 Editor::mouse_paste ()
4348 if (!mouse_frame (where, ignored)) {
4353 paste_internal (where, 1);
4357 Editor::paste_internal (framepos_t position, float times)
4359 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("apparent paste position is %1\n", position));
4361 if (cut_buffer->empty(internal_editing())) {
4365 if (position == max_framepos) {
4366 position = get_preferred_edit_position();
4367 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("preferred edit position is %1\n", position));
4370 if (position == last_paste_pos) {
4371 /* repeated paste in the same position */
4374 /* paste in new location, reset repeated paste state */
4376 last_paste_pos = position;
4379 /* get everything in the correct order */
4382 if (!selection->tracks.empty()) {
4383 /* If there is a track selection, paste into exactly those tracks and
4384 only those tracks. This allows the user to be explicit and override
4385 the below "do the reasonable thing" logic. */
4386 ts = selection->tracks.filter_to_unique_playlists ();
4387 sort_track_selection (ts);
4389 /* Figure out which track to base the paste at. */
4390 TimeAxisView* base_track = NULL;
4391 if (_edit_point == Editing::EditAtMouse && entered_track) {
4392 /* With the mouse edit point, paste onto the track under the mouse. */
4393 base_track = entered_track;
4394 } else if (_edit_point == Editing::EditAtMouse && entered_regionview) {
4395 /* With the mouse edit point, paste onto the track of the region under the mouse. */
4396 base_track = &entered_regionview->get_time_axis_view();
4397 } else if (_last_cut_copy_source_track) {
4398 /* Paste to the track that the cut/copy came from (see mantis #333). */
4399 base_track = _last_cut_copy_source_track;
4401 /* This is "impossible" since we've copied... well, do nothing. */
4405 /* Walk up to parent if necessary, so base track is a route. */
4406 while (base_track->get_parent()) {
4407 base_track = base_track->get_parent();
4410 /* Add base track and all tracks below it. The paste logic will select
4411 the appropriate object types from the cut buffer in relative order. */
4412 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4413 if ((*i)->order() >= base_track->order()) {
4418 /* Sort tracks so the nth track of type T will pick the nth object of type T. */
4419 sort_track_selection (ts);
4421 /* Add automation children of each track in order, for pasting several lines. */
4422 for (TrackViewList::iterator i = ts.begin(); i != ts.end();) {
4423 /* Add any automation children for pasting several lines */
4424 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*i++);
4429 typedef RouteTimeAxisView::AutomationTracks ATracks;
4430 const ATracks& atracks = rtv->automation_tracks();
4431 for (ATracks::const_iterator a = atracks.begin(); a != atracks.end(); ++a) {
4432 i = ts.insert(i, a->second.get());
4437 /* We now have a list of trackviews starting at base_track, including
4438 automation children, in the order shown in the editor, e.g. R1,
4439 R1.A1, R1.A2, R2, R2.A1, ... */
4442 if (internal_editing ()) {
4444 /* undo/redo is handled by individual tracks/regions */
4447 get_regions_at (rs, position, ts);
4450 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
4451 MidiRegionView* mrv = dynamic_cast<MidiRegionView*> (*r);
4453 mrv->paste (position, paste_count, times, *cut_buffer, counts);
4459 /* we do redo (do you do voodoo?) */
4461 begin_reversible_command (Operations::paste);
4464 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4465 (*i)->paste (position, paste_count, times, *cut_buffer, counts);
4468 commit_reversible_command ();
4473 Editor::duplicate_some_regions (RegionSelection& regions, float times)
4475 boost::shared_ptr<Playlist> playlist;
4476 RegionSelection sel = regions; // clear (below) may clear the argument list if its the current region selection
4477 RegionSelection foo;
4479 framepos_t const start_frame = regions.start ();
4480 framepos_t const end_frame = regions.end_frame ();
4482 begin_reversible_command (Operations::duplicate_region);
4484 selection->clear_regions ();
4486 for (RegionSelection::iterator i = sel.begin(); i != sel.end(); ++i) {
4488 boost::shared_ptr<Region> r ((*i)->region());
4490 TimeAxisView& tv = (*i)->get_time_axis_view();
4491 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (&tv);
4492 latest_regionviews.clear ();
4493 sigc::connection c = rtv->view()->RegionViewAdded.connect (sigc::mem_fun(*this, &Editor::collect_new_region_view));
4495 playlist = (*i)->region()->playlist();
4496 playlist->clear_changes ();
4497 playlist->duplicate (r, end_frame + (r->first_frame() - start_frame), times);
4498 _session->add_command(new StatefulDiffCommand (playlist));
4502 foo.insert (foo.end(), latest_regionviews.begin(), latest_regionviews.end());
4505 commit_reversible_command ();
4508 selection->set (foo);
4513 Editor::duplicate_selection (float times)
4515 if (selection->time.empty() || selection->tracks.empty()) {
4519 boost::shared_ptr<Playlist> playlist;
4520 vector<boost::shared_ptr<Region> > new_regions;
4521 vector<boost::shared_ptr<Region> >::iterator ri;
4523 create_region_from_selection (new_regions);
4525 if (new_regions.empty()) {
4529 begin_reversible_command (_("duplicate selection"));
4531 ri = new_regions.begin();
4533 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4535 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4536 if ((playlist = (*i)->playlist()) == 0) {
4539 playlist->clear_changes ();
4540 playlist->duplicate (*ri, selection->time[clicked_selection].end, times);
4541 _session->add_command (new StatefulDiffCommand (playlist));
4544 if (ri == new_regions.end()) {
4549 commit_reversible_command ();
4552 /** Reset all selected points to the relevant default value */
4554 Editor::reset_point_selection ()
4556 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
4557 ARDOUR::AutomationList::iterator j = (*i)->model ();
4558 (*j)->value = (*i)->line().the_list()->default_value ();
4563 Editor::center_playhead ()
4565 float const page = _visible_canvas_width * samples_per_pixel;
4566 center_screen_internal (playhead_cursor->current_frame (), page);
4570 Editor::center_edit_point ()
4572 float const page = _visible_canvas_width * samples_per_pixel;
4573 center_screen_internal (get_preferred_edit_position(), page);
4576 /** Caller must begin and commit a reversible command */
4578 Editor::clear_playlist (boost::shared_ptr<Playlist> playlist)
4580 playlist->clear_changes ();
4582 _session->add_command (new StatefulDiffCommand (playlist));
4586 Editor::nudge_track (bool use_edit, bool forwards)
4588 boost::shared_ptr<Playlist> playlist;
4589 framepos_t distance;
4590 framepos_t next_distance;
4594 start = get_preferred_edit_position();
4599 if ((distance = get_nudge_distance (start, next_distance)) == 0) {
4603 if (selection->tracks.empty()) {
4607 begin_reversible_command (_("nudge track"));
4609 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4611 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4613 if ((playlist = (*i)->playlist()) == 0) {
4617 playlist->clear_changes ();
4618 playlist->clear_owned_changes ();
4620 playlist->nudge_after (start, distance, forwards);
4622 vector<Command*> cmds;
4624 playlist->rdiff (cmds);
4625 _session->add_commands (cmds);
4627 _session->add_command (new StatefulDiffCommand (playlist));
4630 commit_reversible_command ();
4634 Editor::remove_last_capture ()
4636 vector<string> choices;
4643 if (Config->get_verify_remove_last_capture()) {
4644 prompt = _("Do you really want to destroy the last capture?"
4645 "\n(This is destructive and cannot be undone)");
4647 choices.push_back (_("No, do nothing."));
4648 choices.push_back (_("Yes, destroy it."));
4650 Gtkmm2ext::Choice prompter (_("Destroy last capture"), prompt, choices);
4652 if (prompter.run () == 1) {
4653 _session->remove_last_capture ();
4654 _regions->redisplay ();
4658 _session->remove_last_capture();
4659 _regions->redisplay ();
4664 Editor::normalize_region ()
4670 RegionSelection rs = get_regions_from_selection_and_entered ();
4676 NormalizeDialog dialog (rs.size() > 1);
4678 if (dialog.run () == RESPONSE_CANCEL) {
4682 set_canvas_cursor (_cursors->wait);
4685 /* XXX: should really only count audio regions here */
4686 int const regions = rs.size ();
4688 /* Make a list of the selected audio regions' maximum amplitudes, and also
4689 obtain the maximum amplitude of them all.
4691 list<double> max_amps;
4693 for (RegionSelection::const_iterator i = rs.begin(); i != rs.end(); ++i) {
4694 AudioRegionView const * arv = dynamic_cast<AudioRegionView const *> (*i);
4696 dialog.descend (1.0 / regions);
4697 double const a = arv->audio_region()->maximum_amplitude (&dialog);
4700 /* the user cancelled the operation */
4701 set_canvas_cursor (current_canvas_cursor);
4705 max_amps.push_back (a);
4706 max_amp = max (max_amp, a);
4711 begin_reversible_command (_("normalize"));
4713 list<double>::const_iterator a = max_amps.begin ();
4715 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
4716 AudioRegionView* const arv = dynamic_cast<AudioRegionView*> (*r);
4721 arv->region()->clear_changes ();
4723 double const amp = dialog.normalize_individually() ? *a : max_amp;
4725 arv->audio_region()->normalize (amp, dialog.target ());
4726 _session->add_command (new StatefulDiffCommand (arv->region()));
4731 commit_reversible_command ();
4732 set_canvas_cursor (current_canvas_cursor);
4737 Editor::reset_region_scale_amplitude ()
4743 RegionSelection rs = get_regions_from_selection_and_entered ();
4749 begin_reversible_command ("reset gain");
4751 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
4752 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
4755 arv->region()->clear_changes ();
4756 arv->audio_region()->set_scale_amplitude (1.0f);
4757 _session->add_command (new StatefulDiffCommand (arv->region()));
4760 commit_reversible_command ();
4764 Editor::adjust_region_gain (bool up)
4766 RegionSelection rs = get_regions_from_selection_and_entered ();
4768 if (!_session || rs.empty()) {
4772 begin_reversible_command ("adjust region gain");
4774 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
4775 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
4780 arv->region()->clear_changes ();
4782 double dB = accurate_coefficient_to_dB (arv->audio_region()->scale_amplitude ());
4790 arv->audio_region()->set_scale_amplitude (dB_to_coefficient (dB));
4791 _session->add_command (new StatefulDiffCommand (arv->region()));
4794 commit_reversible_command ();
4799 Editor::reverse_region ()
4805 Reverse rev (*_session);
4806 apply_filter (rev, _("reverse regions"));
4810 Editor::strip_region_silence ()
4816 RegionSelection rs = get_regions_from_selection_and_entered ();
4822 std::list<RegionView*> audio_only;
4824 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
4825 AudioRegionView* const arv = dynamic_cast<AudioRegionView*> (*i);
4827 audio_only.push_back (arv);
4831 StripSilenceDialog d (_session, audio_only);
4832 int const r = d.run ();
4836 if (r == Gtk::RESPONSE_OK) {
4837 ARDOUR::AudioIntervalMap silences;
4838 d.silences (silences);
4839 StripSilence s (*_session, silences, d.fade_length());
4840 apply_filter (s, _("strip silence"), &d);
4845 Editor::apply_midi_note_edit_op_to_region (MidiOperator& op, MidiRegionView& mrv)
4847 Evoral::Sequence<Evoral::MusicalTime>::Notes selected;
4848 mrv.selection_as_notelist (selected, true);
4850 vector<Evoral::Sequence<Evoral::MusicalTime>::Notes> v;
4851 v.push_back (selected);
4853 framepos_t pos_frames = mrv.midi_region()->position() - mrv.midi_region()->start();
4854 Evoral::MusicalTime pos_beats = _session->tempo_map().framewalk_to_beats(0, pos_frames);
4856 return op (mrv.midi_region()->model(), pos_beats, v);
4860 Editor::apply_midi_note_edit_op (MidiOperator& op)
4864 RegionSelection rs = get_regions_from_selection_and_entered ();
4870 begin_reversible_command (op.name ());
4872 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
4873 RegionSelection::iterator tmp = r;
4876 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*r);
4879 cmd = apply_midi_note_edit_op_to_region (op, *mrv);
4882 _session->add_command (cmd);
4889 commit_reversible_command ();
4893 Editor::fork_region ()
4895 RegionSelection rs = get_regions_from_selection_and_entered ();
4901 begin_reversible_command (_("Fork Region(s)"));
4903 set_canvas_cursor (_cursors->wait);
4906 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
4907 RegionSelection::iterator tmp = r;
4910 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*>(*r);
4914 boost::shared_ptr<Playlist> playlist = mrv->region()->playlist();
4915 boost::shared_ptr<MidiSource> new_source = _session->create_midi_source_by_stealing_name (mrv->midi_view()->track());
4916 boost::shared_ptr<MidiRegion> newregion = mrv->midi_region()->clone (new_source);
4918 playlist->clear_changes ();
4919 playlist->replace_region (mrv->region(), newregion, mrv->region()->position());
4920 _session->add_command(new StatefulDiffCommand (playlist));
4922 error << string_compose (_("Could not unlink %1"), mrv->region()->name()) << endmsg;
4929 commit_reversible_command ();
4931 set_canvas_cursor (current_canvas_cursor);
4935 Editor::quantize_region ()
4937 int selected_midi_region_cnt = 0;
4943 RegionSelection rs = get_regions_from_selection_and_entered ();
4949 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
4950 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*r);
4952 selected_midi_region_cnt++;
4956 if (selected_midi_region_cnt == 0) {
4960 QuantizeDialog* qd = new QuantizeDialog (*this);
4963 const int r = qd->run ();
4966 if (r == Gtk::RESPONSE_OK) {
4967 Quantize quant (qd->snap_start(), qd->snap_end(),
4968 qd->start_grid_size(), qd->end_grid_size(),
4969 qd->strength(), qd->swing(), qd->threshold());
4971 apply_midi_note_edit_op (quant);
4976 Editor::insert_patch_change (bool from_context)
4978 RegionSelection rs = get_regions_from_selection_and_entered ();
4984 const framepos_t p = get_preferred_edit_position (false, from_context);
4986 /* XXX: bit of a hack; use the MIDNAM from the first selected region;
4987 there may be more than one, but the PatchChangeDialog can only offer
4988 one set of patch menus.
4990 MidiRegionView* first = dynamic_cast<MidiRegionView*> (rs.front ());
4992 Evoral::PatchChange<Evoral::MusicalTime> empty (Evoral::MusicalTime(), 0, 0, 0);
4993 PatchChangeDialog d (0, _session, empty, first->instrument_info(), Gtk::Stock::ADD);
4995 if (d.run() == RESPONSE_CANCEL) {
4999 for (RegionSelection::iterator i = rs.begin (); i != rs.end(); ++i) {
5000 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*i);
5002 if (p >= mrv->region()->first_frame() && p <= mrv->region()->last_frame()) {
5003 mrv->add_patch_change (p - mrv->region()->position(), d.patch ());
5010 Editor::apply_filter (Filter& filter, string command, ProgressReporter* progress)
5012 RegionSelection rs = get_regions_from_selection_and_entered ();
5018 begin_reversible_command (command);
5020 set_canvas_cursor (_cursors->wait);
5024 int const N = rs.size ();
5026 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
5027 RegionSelection::iterator tmp = r;
5030 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
5032 boost::shared_ptr<Playlist> playlist = arv->region()->playlist();
5035 progress->descend (1.0 / N);
5038 if (arv->audio_region()->apply (filter, progress) == 0) {
5040 playlist->clear_changes ();
5041 playlist->clear_owned_changes ();
5043 if (filter.results.empty ()) {
5045 /* no regions returned; remove the old one */
5046 playlist->remove_region (arv->region ());
5050 std::vector<boost::shared_ptr<Region> >::iterator res = filter.results.begin ();
5052 /* first region replaces the old one */
5053 playlist->replace_region (arv->region(), *res, (*res)->position());
5057 while (res != filter.results.end()) {
5058 playlist->add_region (*res, (*res)->position());
5064 /* We might have removed regions, which alters other regions' layering_index,
5065 so we need to do a recursive diff here.
5067 vector<Command*> cmds;
5068 playlist->rdiff (cmds);
5069 _session->add_commands (cmds);
5071 _session->add_command(new StatefulDiffCommand (playlist));
5077 progress->ascend ();
5085 commit_reversible_command ();
5088 set_canvas_cursor (current_canvas_cursor);
5092 Editor::external_edit_region ()
5098 Editor::reset_region_gain_envelopes ()
5100 RegionSelection rs = get_regions_from_selection_and_entered ();
5102 if (!_session || rs.empty()) {
5106 _session->begin_reversible_command (_("reset region gain"));
5108 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5109 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
5111 boost::shared_ptr<AutomationList> alist (arv->audio_region()->envelope());
5112 XMLNode& before (alist->get_state());
5114 arv->audio_region()->set_default_envelope ();
5115 _session->add_command (new MementoCommand<AutomationList>(*arv->audio_region()->envelope().get(), &before, &alist->get_state()));
5119 _session->commit_reversible_command ();
5123 Editor::set_region_gain_visibility (RegionView* rv)
5125 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (rv);
5127 arv->update_envelope_visibility();
5132 Editor::set_gain_envelope_visibility ()
5138 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5139 AudioTimeAxisView* v = dynamic_cast<AudioTimeAxisView*>(*i);
5141 v->audio_view()->foreach_regionview (sigc::mem_fun (this, &Editor::set_region_gain_visibility));
5147 Editor::toggle_gain_envelope_active ()
5149 if (_ignore_region_action) {
5153 RegionSelection rs = get_regions_from_selection_and_entered ();
5155 if (!_session || rs.empty()) {
5159 _session->begin_reversible_command (_("region gain envelope active"));
5161 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5162 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
5164 arv->region()->clear_changes ();
5165 arv->audio_region()->set_envelope_active (!arv->audio_region()->envelope_active());
5166 _session->add_command (new StatefulDiffCommand (arv->region()));
5170 _session->commit_reversible_command ();
5174 Editor::toggle_region_lock ()
5176 if (_ignore_region_action) {
5180 RegionSelection rs = get_regions_from_selection_and_entered ();
5182 if (!_session || rs.empty()) {
5186 _session->begin_reversible_command (_("toggle region lock"));
5188 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5189 (*i)->region()->clear_changes ();
5190 (*i)->region()->set_locked (!(*i)->region()->locked());
5191 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5194 _session->commit_reversible_command ();
5198 Editor::toggle_region_video_lock ()
5200 if (_ignore_region_action) {
5204 RegionSelection rs = get_regions_from_selection_and_entered ();
5206 if (!_session || rs.empty()) {
5210 _session->begin_reversible_command (_("Toggle Video Lock"));
5212 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5213 (*i)->region()->clear_changes ();
5214 (*i)->region()->set_video_locked (!(*i)->region()->video_locked());
5215 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5218 _session->commit_reversible_command ();
5222 Editor::toggle_region_lock_style ()
5224 if (_ignore_region_action) {
5228 RegionSelection rs = get_regions_from_selection_and_entered ();
5230 if (!_session || rs.empty()) {
5234 _session->begin_reversible_command (_("region lock style"));
5236 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5237 (*i)->region()->clear_changes ();
5238 PositionLockStyle const ns = (*i)->region()->position_lock_style() == AudioTime ? MusicTime : AudioTime;
5239 (*i)->region()->set_position_lock_style (ns);
5240 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5243 _session->commit_reversible_command ();
5247 Editor::toggle_opaque_region ()
5249 if (_ignore_region_action) {
5253 RegionSelection rs = get_regions_from_selection_and_entered ();
5255 if (!_session || rs.empty()) {
5259 _session->begin_reversible_command (_("change region opacity"));
5261 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5262 (*i)->region()->clear_changes ();
5263 (*i)->region()->set_opaque (!(*i)->region()->opaque());
5264 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5267 _session->commit_reversible_command ();
5271 Editor::toggle_record_enable ()
5273 bool new_state = false;
5275 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5276 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5279 if (!rtav->is_track())
5283 new_state = !rtav->track()->record_enabled();
5287 rtav->track()->set_record_enabled (new_state, this);
5292 Editor::toggle_solo ()
5294 bool new_state = false;
5296 boost::shared_ptr<RouteList> rl (new RouteList);
5298 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5299 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5306 new_state = !rtav->route()->soloed ();
5310 rl->push_back (rtav->route());
5313 _session->set_solo (rl, new_state, Session::rt_cleanup, true);
5317 Editor::toggle_mute ()
5319 bool new_state = false;
5321 boost::shared_ptr<RouteList> rl (new RouteList);
5323 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5324 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5331 new_state = !rtav->route()->muted();
5335 rl->push_back (rtav->route());
5338 _session->set_mute (rl, new_state, Session::rt_cleanup, true);
5342 Editor::toggle_solo_isolate ()
5348 Editor::fade_range ()
5350 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
5352 begin_reversible_command (_("fade range"));
5354 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
5355 (*i)->fade_range (selection->time);
5358 commit_reversible_command ();
5363 Editor::set_fade_length (bool in)
5365 RegionSelection rs = get_regions_from_selection_and_entered ();
5371 /* we need a region to measure the offset from the start */
5373 RegionView* rv = rs.front ();
5375 framepos_t pos = get_preferred_edit_position();
5379 if (pos > rv->region()->last_frame() || pos < rv->region()->first_frame()) {
5380 /* edit point is outside the relevant region */
5385 if (pos <= rv->region()->position()) {
5389 len = pos - rv->region()->position();
5390 cmd = _("set fade in length");
5392 if (pos >= rv->region()->last_frame()) {
5396 len = rv->region()->last_frame() - pos;
5397 cmd = _("set fade out length");
5400 begin_reversible_command (cmd);
5402 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5403 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5409 boost::shared_ptr<AutomationList> alist;
5411 alist = tmp->audio_region()->fade_in();
5413 alist = tmp->audio_region()->fade_out();
5416 XMLNode &before = alist->get_state();
5419 tmp->audio_region()->set_fade_in_length (len);
5420 tmp->audio_region()->set_fade_in_active (true);
5422 tmp->audio_region()->set_fade_out_length (len);
5423 tmp->audio_region()->set_fade_out_active (true);
5426 XMLNode &after = alist->get_state();
5427 _session->add_command(new MementoCommand<AutomationList>(*alist, &before, &after));
5430 commit_reversible_command ();
5434 Editor::set_fade_in_shape (FadeShape shape)
5436 RegionSelection rs = get_regions_from_selection_and_entered ();
5442 begin_reversible_command (_("set fade in shape"));
5444 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5445 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5451 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_in();
5452 XMLNode &before = alist->get_state();
5454 tmp->audio_region()->set_fade_in_shape (shape);
5456 XMLNode &after = alist->get_state();
5457 _session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
5460 commit_reversible_command ();
5465 Editor::set_fade_out_shape (FadeShape shape)
5467 RegionSelection rs = get_regions_from_selection_and_entered ();
5473 begin_reversible_command (_("set fade out shape"));
5475 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5476 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5482 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_out();
5483 XMLNode &before = alist->get_state();
5485 tmp->audio_region()->set_fade_out_shape (shape);
5487 XMLNode &after = alist->get_state();
5488 _session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
5491 commit_reversible_command ();
5495 Editor::set_fade_in_active (bool yn)
5497 RegionSelection rs = get_regions_from_selection_and_entered ();
5503 begin_reversible_command (_("set fade in active"));
5505 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5506 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5513 boost::shared_ptr<AudioRegion> ar (tmp->audio_region());
5515 ar->clear_changes ();
5516 ar->set_fade_in_active (yn);
5517 _session->add_command (new StatefulDiffCommand (ar));
5520 commit_reversible_command ();
5524 Editor::set_fade_out_active (bool yn)
5526 RegionSelection rs = get_regions_from_selection_and_entered ();
5532 begin_reversible_command (_("set fade out active"));
5534 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5535 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5541 boost::shared_ptr<AudioRegion> ar (tmp->audio_region());
5543 ar->clear_changes ();
5544 ar->set_fade_out_active (yn);
5545 _session->add_command(new StatefulDiffCommand (ar));
5548 commit_reversible_command ();
5552 Editor::toggle_region_fades (int dir)
5554 if (_ignore_region_action) {
5558 boost::shared_ptr<AudioRegion> ar;
5561 RegionSelection rs = get_regions_from_selection_and_entered ();
5567 RegionSelection::iterator i;
5568 for (i = rs.begin(); i != rs.end(); ++i) {
5569 if ((ar = boost::dynamic_pointer_cast<AudioRegion>((*i)->region())) != 0) {
5571 yn = ar->fade_out_active ();
5573 yn = ar->fade_in_active ();
5579 if (i == rs.end()) {
5583 /* XXX should this undo-able? */
5585 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5586 if ((ar = boost::dynamic_pointer_cast<AudioRegion>((*i)->region())) == 0) {
5589 if (dir == 1 || dir == 0) {
5590 ar->set_fade_in_active (!yn);
5593 if (dir == -1 || dir == 0) {
5594 ar->set_fade_out_active (!yn);
5600 /** Update region fade visibility after its configuration has been changed */
5602 Editor::update_region_fade_visibility ()
5604 bool _fade_visibility = _session->config.get_show_region_fades ();
5606 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5607 AudioTimeAxisView* v = dynamic_cast<AudioTimeAxisView*>(*i);
5609 if (_fade_visibility) {
5610 v->audio_view()->show_all_fades ();
5612 v->audio_view()->hide_all_fades ();
5619 Editor::set_edit_point ()
5624 if (!mouse_frame (where, ignored)) {
5630 if (selection->markers.empty()) {
5632 mouse_add_new_marker (where);
5637 Location* loc = find_location_from_marker (selection->markers.front(), ignored);
5640 loc->move_to (where);
5646 Editor::set_playhead_cursor ()
5648 if (entered_marker) {
5649 _session->request_locate (entered_marker->position(), _session->transport_rolling());
5654 if (!mouse_frame (where, ignored)) {
5661 _session->request_locate (where, _session->transport_rolling());
5665 if ( Config->get_follow_edits() )
5666 cancel_time_selection();
5670 Editor::split_region ()
5672 if ( !selection->time.empty()) {
5673 separate_regions_between (selection->time);
5677 RegionSelection rs = get_regions_from_selection_and_edit_point ();
5679 framepos_t where = get_preferred_edit_position ();
5685 split_regions_at (where, rs);
5688 struct EditorOrderRouteSorter {
5689 bool operator() (boost::shared_ptr<Route> a, boost::shared_ptr<Route> b) {
5690 return a->order_key () < b->order_key ();
5695 Editor::select_next_route()
5697 if (selection->tracks.empty()) {
5698 selection->set (track_views.front());
5702 TimeAxisView* current = selection->tracks.front();
5706 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5707 if (*i == current) {
5709 if (i != track_views.end()) {
5712 current = (*(track_views.begin()));
5713 //selection->set (*(track_views.begin()));
5718 rui = dynamic_cast<RouteUI *>(current);
5719 } while ( current->hidden() || (rui != NULL && !rui->route()->active()));
5721 selection->set(current);
5723 ensure_time_axis_view_is_visible (*current, false);
5727 Editor::select_prev_route()
5729 if (selection->tracks.empty()) {
5730 selection->set (track_views.front());
5734 TimeAxisView* current = selection->tracks.front();
5738 for (TrackViewList::reverse_iterator i = track_views.rbegin(); i != track_views.rend(); ++i) {
5739 if (*i == current) {
5741 if (i != track_views.rend()) {
5744 current = *(track_views.rbegin());
5749 rui = dynamic_cast<RouteUI *>(current);
5750 } while ( current->hidden() || (rui != NULL && !rui->route()->active()));
5752 selection->set (current);
5754 ensure_time_axis_view_is_visible (*current, false);
5758 Editor::set_loop_from_selection (bool play)
5760 if (_session == 0 || selection->time.empty()) {
5764 framepos_t start = selection->time[clicked_selection].start;
5765 framepos_t end = selection->time[clicked_selection].end;
5767 set_loop_range (start, end, _("set loop range from selection"));
5770 _session->request_locate (start, true);
5771 _session->request_play_loop (true);
5776 Editor::set_loop_from_edit_range (bool play)
5778 if (_session == 0) {
5785 if (!get_edit_op_range (start, end)) {
5789 set_loop_range (start, end, _("set loop range from edit range"));
5792 _session->request_locate (start, true);
5793 _session->request_play_loop (true);
5798 Editor::set_loop_from_region (bool play)
5800 framepos_t start = max_framepos;
5803 RegionSelection rs = get_regions_from_selection_and_entered ();
5809 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5810 if ((*i)->region()->position() < start) {
5811 start = (*i)->region()->position();
5813 if ((*i)->region()->last_frame() + 1 > end) {
5814 end = (*i)->region()->last_frame() + 1;
5818 set_loop_range (start, end, _("set loop range from region"));
5821 _session->request_locate (start, true);
5822 _session->request_play_loop (true);
5827 Editor::set_punch_from_selection ()
5829 if (_session == 0 || selection->time.empty()) {
5833 framepos_t start = selection->time[clicked_selection].start;
5834 framepos_t end = selection->time[clicked_selection].end;
5836 set_punch_range (start, end, _("set punch range from selection"));
5840 Editor::set_punch_from_edit_range ()
5842 if (_session == 0) {
5849 if (!get_edit_op_range (start, end)) {
5853 set_punch_range (start, end, _("set punch range from edit range"));
5857 Editor::set_punch_from_region ()
5859 framepos_t start = max_framepos;
5862 RegionSelection rs = get_regions_from_selection_and_entered ();
5868 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5869 if ((*i)->region()->position() < start) {
5870 start = (*i)->region()->position();
5872 if ((*i)->region()->last_frame() + 1 > end) {
5873 end = (*i)->region()->last_frame() + 1;
5877 set_punch_range (start, end, _("set punch range from region"));
5881 Editor::pitch_shift_region ()
5883 RegionSelection rs = get_regions_from_selection_and_entered ();
5885 RegionSelection audio_rs;
5886 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5887 if (dynamic_cast<AudioRegionView*> (*i)) {
5888 audio_rs.push_back (*i);
5892 if (audio_rs.empty()) {
5896 pitch_shift (audio_rs, 1.2);
5900 Editor::transpose_region ()
5902 RegionSelection rs = get_regions_from_selection_and_entered ();
5904 list<MidiRegionView*> midi_region_views;
5905 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5906 MidiRegionView* mrv = dynamic_cast<MidiRegionView*> (*i);
5908 midi_region_views.push_back (mrv);
5913 int const r = d.run ();
5914 if (r != RESPONSE_ACCEPT) {
5918 for (list<MidiRegionView*>::iterator i = midi_region_views.begin(); i != midi_region_views.end(); ++i) {
5919 (*i)->midi_region()->transpose (d.semitones ());
5924 Editor::set_tempo_from_region ()
5926 RegionSelection rs = get_regions_from_selection_and_entered ();
5928 if (!_session || rs.empty()) {
5932 RegionView* rv = rs.front();
5934 define_one_bar (rv->region()->position(), rv->region()->last_frame() + 1);
5938 Editor::use_range_as_bar ()
5940 framepos_t start, end;
5941 if (get_edit_op_range (start, end)) {
5942 define_one_bar (start, end);
5947 Editor::define_one_bar (framepos_t start, framepos_t end)
5949 framepos_t length = end - start;
5951 const Meter& m (_session->tempo_map().meter_at (start));
5953 /* length = 1 bar */
5955 /* now we want frames per beat.
5956 we have frames per bar, and beats per bar, so ...
5959 /* XXXX METER MATH */
5961 double frames_per_beat = length / m.divisions_per_bar();
5963 /* beats per minute = */
5965 double beats_per_minute = (_session->frame_rate() * 60.0) / frames_per_beat;
5967 /* now decide whether to:
5969 (a) set global tempo
5970 (b) add a new tempo marker
5974 const TempoSection& t (_session->tempo_map().tempo_section_at (start));
5976 bool do_global = false;
5978 if ((_session->tempo_map().n_tempos() == 1) && (_session->tempo_map().n_meters() == 1)) {
5980 /* only 1 tempo & 1 meter: ask if the user wants to set the tempo
5981 at the start, or create a new marker
5984 vector<string> options;
5985 options.push_back (_("Cancel"));
5986 options.push_back (_("Add new marker"));
5987 options.push_back (_("Set global tempo"));
5990 _("Define one bar"),
5991 _("Do you want to set the global tempo or add a new tempo marker?"),
5995 c.set_default_response (2);
6011 /* more than 1 tempo and/or meter section already, go ahead do the "usual":
6012 if the marker is at the region starter, change it, otherwise add
6017 begin_reversible_command (_("set tempo from region"));
6018 XMLNode& before (_session->tempo_map().get_state());
6021 _session->tempo_map().change_initial_tempo (beats_per_minute, t.note_type());
6022 } else if (t.frame() == start) {
6023 _session->tempo_map().change_existing_tempo_at (start, beats_per_minute, t.note_type());
6025 Timecode::BBT_Time bbt;
6026 _session->tempo_map().bbt_time (start, bbt);
6027 _session->tempo_map().add_tempo (Tempo (beats_per_minute, t.note_type()), bbt);
6030 XMLNode& after (_session->tempo_map().get_state());
6032 _session->add_command (new MementoCommand<TempoMap>(_session->tempo_map(), &before, &after));
6033 commit_reversible_command ();
6037 Editor::split_region_at_transients ()
6039 AnalysisFeatureList positions;
6041 RegionSelection rs = get_regions_from_selection_and_entered ();
6043 if (!_session || rs.empty()) {
6047 _session->begin_reversible_command (_("split regions"));
6049 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ) {
6051 RegionSelection::iterator tmp;
6056 boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion> ((*i)->region());
6058 if (ar && (ar->get_transients (positions) == 0)) {
6059 split_region_at_points ((*i)->region(), positions, true);
6066 _session->commit_reversible_command ();
6071 Editor::split_region_at_points (boost::shared_ptr<Region> r, AnalysisFeatureList& positions, bool can_ferret, bool select_new)
6073 bool use_rhythmic_rodent = false;
6075 boost::shared_ptr<Playlist> pl = r->playlist();
6077 list<boost::shared_ptr<Region> > new_regions;
6083 if (positions.empty()) {
6088 if (positions.size() > 20 && can_ferret) {
6089 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);
6090 MessageDialog msg (msgstr,
6093 Gtk::BUTTONS_OK_CANCEL);
6096 msg.add_button (_("Call for the Ferret!"), RESPONSE_APPLY);
6097 msg.set_secondary_text (_("Press OK to continue with this split operation\nor ask the Ferret dialog to tune the analysis"));
6099 msg.set_secondary_text (_("Press OK to continue with this split operation"));
6102 msg.set_title (_("Excessive split?"));
6105 int response = msg.run();
6111 case RESPONSE_APPLY:
6112 use_rhythmic_rodent = true;
6119 if (use_rhythmic_rodent) {
6120 show_rhythm_ferret ();
6124 AnalysisFeatureList::const_iterator x;
6126 pl->clear_changes ();
6127 pl->clear_owned_changes ();
6129 x = positions.begin();
6131 if (x == positions.end()) {
6136 pl->remove_region (r);
6140 while (x != positions.end()) {
6142 /* deal with positons that are out of scope of present region bounds */
6143 if (*x <= 0 || *x > r->length()) {
6148 /* file start = original start + how far we from the initial position ?
6151 framepos_t file_start = r->start() + pos;
6153 /* length = next position - current position
6156 framepos_t len = (*x) - pos;
6158 /* XXX we do we really want to allow even single-sample regions?
6159 shouldn't we have some kind of lower limit on region size?
6168 if (RegionFactory::region_name (new_name, r->name())) {
6172 /* do NOT announce new regions 1 by one, just wait till they are all done */
6176 plist.add (ARDOUR::Properties::start, file_start);
6177 plist.add (ARDOUR::Properties::length, len);
6178 plist.add (ARDOUR::Properties::name, new_name);
6179 plist.add (ARDOUR::Properties::layer, 0);
6181 boost::shared_ptr<Region> nr = RegionFactory::create (r->sources(), plist, false);
6182 /* because we set annouce to false, manually add the new region to the
6185 RegionFactory::map_add (nr);
6187 pl->add_region (nr, r->position() + pos);
6190 new_regions.push_front(nr);
6199 RegionFactory::region_name (new_name, r->name());
6201 /* Add the final region */
6204 plist.add (ARDOUR::Properties::start, r->start() + pos);
6205 plist.add (ARDOUR::Properties::length, r->last_frame() - (r->position() + pos) + 1);
6206 plist.add (ARDOUR::Properties::name, new_name);
6207 plist.add (ARDOUR::Properties::layer, 0);
6209 boost::shared_ptr<Region> nr = RegionFactory::create (r->sources(), plist, false);
6210 /* because we set annouce to false, manually add the new region to the
6213 RegionFactory::map_add (nr);
6214 pl->add_region (nr, r->position() + pos);
6217 new_regions.push_front(nr);
6222 /* We might have removed regions, which alters other regions' layering_index,
6223 so we need to do a recursive diff here.
6225 vector<Command*> cmds;
6227 _session->add_commands (cmds);
6229 _session->add_command (new StatefulDiffCommand (pl));
6233 for (list<boost::shared_ptr<Region> >::iterator i = new_regions.begin(); i != new_regions.end(); ++i){
6234 set_selected_regionview_from_region_list ((*i), Selection::Add);
6240 Editor::place_transient()
6246 RegionSelection rs = get_regions_from_selection_and_edit_point ();
6252 framepos_t where = get_preferred_edit_position();
6254 _session->begin_reversible_command (_("place transient"));
6256 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6257 framepos_t position = (*r)->region()->position();
6258 (*r)->region()->add_transient(where - position);
6261 _session->commit_reversible_command ();
6265 Editor::remove_transient(ArdourCanvas::Item* item)
6271 ArdourCanvas::Line* _line = reinterpret_cast<ArdourCanvas::Line*> (item);
6274 AudioRegionView* _arv = reinterpret_cast<AudioRegionView*> (item->get_data ("regionview"));
6275 _arv->remove_transient (*(float*) _line->get_data ("position"));
6279 Editor::snap_regions_to_grid ()
6281 list <boost::shared_ptr<Playlist > > used_playlists;
6283 RegionSelection rs = get_regions_from_selection_and_entered ();
6285 if (!_session || rs.empty()) {
6289 _session->begin_reversible_command (_("snap regions to grid"));
6291 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6293 boost::shared_ptr<Playlist> pl = (*r)->region()->playlist();
6295 if (!pl->frozen()) {
6296 /* we haven't seen this playlist before */
6298 /* remember used playlists so we can thaw them later */
6299 used_playlists.push_back(pl);
6303 framepos_t start_frame = (*r)->region()->first_frame ();
6304 snap_to (start_frame);
6305 (*r)->region()->set_position (start_frame);
6308 while (used_playlists.size() > 0) {
6309 list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
6311 used_playlists.pop_front();
6314 _session->commit_reversible_command ();
6318 Editor::close_region_gaps ()
6320 list <boost::shared_ptr<Playlist > > used_playlists;
6322 RegionSelection rs = get_regions_from_selection_and_entered ();
6324 if (!_session || rs.empty()) {
6328 Dialog dialog (_("Close Region Gaps"));
6331 table.set_spacings (12);
6332 table.set_border_width (12);
6333 Label* l = manage (left_aligned_label (_("Crossfade length")));
6334 table.attach (*l, 0, 1, 0, 1);
6336 SpinButton spin_crossfade (1, 0);
6337 spin_crossfade.set_range (0, 15);
6338 spin_crossfade.set_increments (1, 1);
6339 spin_crossfade.set_value (5);
6340 table.attach (spin_crossfade, 1, 2, 0, 1);
6342 table.attach (*manage (new Label (_("ms"))), 2, 3, 0, 1);
6344 l = manage (left_aligned_label (_("Pull-back length")));
6345 table.attach (*l, 0, 1, 1, 2);
6347 SpinButton spin_pullback (1, 0);
6348 spin_pullback.set_range (0, 100);
6349 spin_pullback.set_increments (1, 1);
6350 spin_pullback.set_value(30);
6351 table.attach (spin_pullback, 1, 2, 1, 2);
6353 table.attach (*manage (new Label (_("ms"))), 2, 3, 1, 2);
6355 dialog.get_vbox()->pack_start (table);
6356 dialog.add_button (Stock::CANCEL, RESPONSE_CANCEL);
6357 dialog.add_button (_("Ok"), RESPONSE_ACCEPT);
6360 if (dialog.run () == RESPONSE_CANCEL) {
6364 framepos_t crossfade_len = spin_crossfade.get_value();
6365 framepos_t pull_back_frames = spin_pullback.get_value();
6367 crossfade_len = lrintf (crossfade_len * _session->frame_rate()/1000);
6368 pull_back_frames = lrintf (pull_back_frames * _session->frame_rate()/1000);
6370 /* Iterate over the region list and make adjacent regions overlap by crossfade_len_ms */
6372 _session->begin_reversible_command (_("close region gaps"));
6375 boost::shared_ptr<Region> last_region;
6377 rs.sort_by_position_and_track();
6379 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6381 boost::shared_ptr<Playlist> pl = (*r)->region()->playlist();
6383 if (!pl->frozen()) {
6384 /* we haven't seen this playlist before */
6386 /* remember used playlists so we can thaw them later */
6387 used_playlists.push_back(pl);
6391 framepos_t position = (*r)->region()->position();
6393 if (idx == 0 || position < last_region->position()){
6394 last_region = (*r)->region();
6399 (*r)->region()->trim_front( (position - pull_back_frames));
6400 last_region->trim_end( (position - pull_back_frames + crossfade_len));
6402 last_region = (*r)->region();
6407 while (used_playlists.size() > 0) {
6408 list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
6410 used_playlists.pop_front();
6413 _session->commit_reversible_command ();
6417 Editor::tab_to_transient (bool forward)
6419 AnalysisFeatureList positions;
6421 RegionSelection rs = get_regions_from_selection_and_entered ();
6427 framepos_t pos = _session->audible_frame ();
6429 if (!selection->tracks.empty()) {
6431 /* don't waste time searching for transients in duplicate playlists.
6434 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
6436 for (TrackViewList::iterator t = ts.begin(); t != ts.end(); ++t) {
6438 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*t);
6441 boost::shared_ptr<Track> tr = rtv->track();
6443 boost::shared_ptr<Playlist> pl = tr->playlist ();
6445 framepos_t result = pl->find_next_transient (pos, forward ? 1 : -1);
6448 positions.push_back (result);
6461 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6462 (*r)->region()->get_transients (positions);
6466 TransientDetector::cleanup_transients (positions, _session->frame_rate(), 3.0);
6469 AnalysisFeatureList::iterator x;
6471 for (x = positions.begin(); x != positions.end(); ++x) {
6477 if (x != positions.end ()) {
6478 _session->request_locate (*x);
6482 AnalysisFeatureList::reverse_iterator x;
6484 for (x = positions.rbegin(); x != positions.rend(); ++x) {
6490 if (x != positions.rend ()) {
6491 _session->request_locate (*x);
6497 Editor::playhead_forward_to_grid ()
6503 framepos_t pos = playhead_cursor->current_frame ();
6504 if (pos < max_framepos - 1) {
6506 snap_to_internal (pos, RoundUpAlways, false);
6507 _session->request_locate (pos);
6513 Editor::playhead_backward_to_grid ()
6519 framepos_t pos = playhead_cursor->current_frame ();
6522 snap_to_internal (pos, RoundDownAlways, false);
6523 _session->request_locate (pos);
6528 Editor::set_track_height (Height h)
6530 TrackSelection& ts (selection->tracks);
6532 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
6533 (*x)->set_height_enum (h);
6538 Editor::toggle_tracks_active ()
6540 TrackSelection& ts (selection->tracks);
6542 bool target = false;
6548 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
6549 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*x);
6553 target = !rtv->_route->active();
6556 rtv->_route->set_active (target, this);
6562 Editor::remove_tracks ()
6564 TrackSelection& ts (selection->tracks);
6570 vector<string> choices;
6574 const char* trackstr;
6576 vector<boost::shared_ptr<Route> > routes;
6577 bool special_bus = false;
6579 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
6580 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*x);
6584 if (rtv->is_track()) {
6589 routes.push_back (rtv->_route);
6591 if (rtv->route()->is_master() || rtv->route()->is_monitor()) {
6596 if (special_bus && !Config->get_allow_special_bus_removal()) {
6597 MessageDialog msg (_("That would be bad news ...."),
6601 msg.set_secondary_text (string_compose (_(
6602 "Removing the master or monitor bus is such a bad idea\n\
6603 that %1 is not going to allow it.\n\
6605 If you really want to do this sort of thing\n\
6606 edit your ardour.rc file to set the\n\
6607 \"allow-special-bus-removal\" option to be \"yes\""), PROGRAM_NAME));
6614 if (ntracks + nbusses == 0) {
6618 // XXX should be using gettext plural forms, maybe?
6620 trackstr = _("tracks");
6622 trackstr = _("track");
6626 busstr = _("busses");
6633 prompt = string_compose (_("Do you really want to remove %1 %2 and %3 %4?\n"
6634 "(You may also lose the playlists associated with the %2)\n\n"
6635 "This action cannot be undone, and the session file will be overwritten!"),
6636 ntracks, trackstr, nbusses, busstr);
6638 prompt = string_compose (_("Do you really want to remove %1 %2?\n"
6639 "(You may also lose the playlists associated with the %2)\n\n"
6640 "This action cannot be undone, and the session file will be overwritten!"),
6643 } else if (nbusses) {
6644 prompt = string_compose (_("Do you really want to remove %1 %2?\n\n"
6645 "This action cannot be undone, and the session file will be overwritten"),
6649 choices.push_back (_("No, do nothing."));
6650 if (ntracks + nbusses > 1) {
6651 choices.push_back (_("Yes, remove them."));
6653 choices.push_back (_("Yes, remove it."));
6658 title = string_compose (_("Remove %1"), trackstr);
6660 title = string_compose (_("Remove %1"), busstr);
6663 Choice prompter (title, prompt, choices);
6665 if (prompter.run () != 1) {
6670 Session::StateProtector sp (_session);
6671 DisplaySuspender ds;
6672 for (vector<boost::shared_ptr<Route> >::iterator x = routes.begin(); x != routes.end(); ++x) {
6673 _session->remove_route (*x);
6679 Editor::do_insert_time ()
6681 if (selection->tracks.empty()) {
6685 InsertTimeDialog d (*this);
6686 int response = d.run ();
6688 if (response != RESPONSE_OK) {
6692 if (d.distance() == 0) {
6696 InsertTimeOption opt = d.intersected_region_action ();
6699 get_preferred_edit_position(),
6705 d.move_glued_markers(),
6706 d.move_locked_markers(),
6712 Editor::insert_time (
6713 framepos_t pos, framecnt_t frames, InsertTimeOption opt,
6714 bool all_playlists, bool ignore_music_glue, bool markers_too, bool glued_markers_too, bool locked_markers_too, bool tempo_too
6717 bool commit = false;
6719 if (Config->get_edit_mode() == Lock) {
6723 begin_reversible_command (_("insert time"));
6725 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
6727 for (TrackViewList::iterator x = ts.begin(); x != ts.end(); ++x) {
6731 /* don't operate on any playlist more than once, which could
6732 * happen if "all playlists" is enabled, but there is more
6733 * than 1 track using playlists "from" a given track.
6736 set<boost::shared_ptr<Playlist> > pl;
6738 if (all_playlists) {
6739 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*x);
6741 vector<boost::shared_ptr<Playlist> > all = _session->playlists->playlists_for_track (rtav->track ());
6742 for (vector<boost::shared_ptr<Playlist> >::iterator p = all.begin(); p != all.end(); ++p) {
6747 if ((*x)->playlist ()) {
6748 pl.insert ((*x)->playlist ());
6752 for (set<boost::shared_ptr<Playlist> >::iterator i = pl.begin(); i != pl.end(); ++i) {
6754 (*i)->clear_changes ();
6755 (*i)->clear_owned_changes ();
6757 if (opt == SplitIntersected) {
6761 (*i)->shift (pos, frames, (opt == MoveIntersected), ignore_music_glue);
6763 vector<Command*> cmds;
6765 _session->add_commands (cmds);
6767 _session->add_command (new StatefulDiffCommand (*i));
6772 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*x);
6774 rtav->route ()->shift (pos, frames);
6782 XMLNode& before (_session->locations()->get_state());
6783 Locations::LocationList copy (_session->locations()->list());
6785 for (Locations::LocationList::iterator i = copy.begin(); i != copy.end(); ++i) {
6787 Locations::LocationList::const_iterator tmp;
6789 bool const was_locked = (*i)->locked ();
6790 if (locked_markers_too) {
6794 if ((*i)->position_lock_style() == AudioTime || glued_markers_too) {
6796 if ((*i)->start() >= pos) {
6797 (*i)->set_start ((*i)->start() + frames);
6798 if (!(*i)->is_mark()) {
6799 (*i)->set_end ((*i)->end() + frames);
6812 XMLNode& after (_session->locations()->get_state());
6813 _session->add_command (new MementoCommand<Locations>(*_session->locations(), &before, &after));
6818 _session->tempo_map().insert_time (pos, frames);
6822 commit_reversible_command ();
6827 Editor::fit_selected_tracks ()
6829 if (!selection->tracks.empty()) {
6830 fit_tracks (selection->tracks);
6834 /* no selected tracks - use tracks with selected regions */
6836 if (!selection->regions.empty()) {
6837 for (RegionSelection::iterator r = selection->regions.begin(); r != selection->regions.end(); ++r) {
6838 tvl.push_back (&(*r)->get_time_axis_view ());
6844 } else if (internal_editing()) {
6845 /* no selected tracks, or regions, but in internal edit mode, so follow the mouse and use
6848 if (entered_track) {
6849 tvl.push_back (entered_track);
6858 Editor::fit_tracks (TrackViewList & tracks)
6860 if (tracks.empty()) {
6864 uint32_t child_heights = 0;
6865 int visible_tracks = 0;
6867 for (TrackSelection::iterator t = tracks.begin(); t != tracks.end(); ++t) {
6869 if (!(*t)->marked_for_display()) {
6873 child_heights += (*t)->effective_height() - (*t)->current_height();
6877 /* compute the per-track height from:
6879 total canvas visible height -
6880 height that will be taken by visible children of selected
6881 tracks - height of the ruler/hscroll area
6883 uint32_t h = (uint32_t) floor ((trackviews_height() - child_heights) / visible_tracks);
6884 double first_y_pos = DBL_MAX;
6886 if (h < TimeAxisView::preset_height (HeightSmall)) {
6887 MessageDialog msg (*this, _("There are too many tracks to fit in the current window"));
6888 /* too small to be displayed */
6892 undo_visual_stack.push_back (current_visual_state (true));
6893 no_save_visual = true;
6895 /* build a list of all tracks, including children */
6898 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
6900 TimeAxisView::Children c = (*i)->get_child_list ();
6901 for (TimeAxisView::Children::iterator j = c.begin(); j != c.end(); ++j) {
6902 all.push_back (j->get());
6906 bool prev_was_selected = false;
6907 bool is_selected = tracks.contains (all.front());
6908 bool next_is_selected;
6910 for (TrackViewList::iterator t = all.begin(); t != all.end(); ++t) {
6912 TrackViewList::iterator next;
6917 if (next != all.end()) {
6918 next_is_selected = tracks.contains (*next);
6920 next_is_selected = false;
6923 if ((*t)->marked_for_display ()) {
6925 (*t)->set_height (h);
6926 first_y_pos = std::min ((*t)->y_position (), first_y_pos);
6928 if (prev_was_selected && next_is_selected) {
6929 hide_track_in_display (*t);
6934 prev_was_selected = is_selected;
6935 is_selected = next_is_selected;
6939 set the controls_layout height now, because waiting for its size
6940 request signal handler will cause the vertical adjustment setting to fail
6943 controls_layout.property_height () = _full_canvas_height;
6944 vertical_adjustment.set_value (first_y_pos);
6946 redo_visual_stack.push_back (current_visual_state (true));
6948 visible_tracks_selector.set_text (_("Sel"));
6952 Editor::save_visual_state (uint32_t n)
6954 while (visual_states.size() <= n) {
6955 visual_states.push_back (0);
6958 if (visual_states[n] != 0) {
6959 delete visual_states[n];
6962 visual_states[n] = current_visual_state (true);
6967 Editor::goto_visual_state (uint32_t n)
6969 if (visual_states.size() <= n) {
6973 if (visual_states[n] == 0) {
6977 use_visual_state (*visual_states[n]);
6981 Editor::start_visual_state_op (uint32_t n)
6983 save_visual_state (n);
6985 PopUp* pup = new PopUp (WIN_POS_MOUSE, 1000, true);
6987 snprintf (buf, sizeof (buf), _("Saved view %u"), n+1);
6988 pup->set_text (buf);
6993 Editor::cancel_visual_state_op (uint32_t n)
6995 goto_visual_state (n);
6999 Editor::toggle_region_mute ()
7001 if (_ignore_region_action) {
7005 RegionSelection rs = get_regions_from_selection_and_entered ();
7011 if (rs.size() > 1) {
7012 begin_reversible_command (_("mute regions"));
7014 begin_reversible_command (_("mute region"));
7017 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
7019 (*i)->region()->playlist()->clear_changes ();
7020 (*i)->region()->set_muted (!(*i)->region()->muted ());
7021 _session->add_command (new StatefulDiffCommand ((*i)->region()->playlist()));
7025 commit_reversible_command ();
7029 Editor::combine_regions ()
7031 /* foreach track with selected regions, take all selected regions
7032 and join them into a new region containing the subregions (as a
7036 typedef set<RouteTimeAxisView*> RTVS;
7039 if (selection->regions.empty()) {
7043 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
7044 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(&(*i)->get_time_axis_view());
7047 tracks.insert (rtv);
7051 begin_reversible_command (_("combine regions"));
7053 vector<RegionView*> new_selection;
7055 for (RTVS::iterator i = tracks.begin(); i != tracks.end(); ++i) {
7058 if ((rv = (*i)->combine_regions ()) != 0) {
7059 new_selection.push_back (rv);
7063 selection->clear_regions ();
7064 for (vector<RegionView*>::iterator i = new_selection.begin(); i != new_selection.end(); ++i) {
7065 selection->add (*i);
7068 commit_reversible_command ();
7072 Editor::uncombine_regions ()
7074 typedef set<RouteTimeAxisView*> RTVS;
7077 if (selection->regions.empty()) {
7081 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
7082 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(&(*i)->get_time_axis_view());
7085 tracks.insert (rtv);
7089 begin_reversible_command (_("uncombine regions"));
7091 for (RTVS::iterator i = tracks.begin(); i != tracks.end(); ++i) {
7092 (*i)->uncombine_regions ();
7095 commit_reversible_command ();
7099 Editor::toggle_midi_input_active (bool flip_others)
7102 boost::shared_ptr<RouteList> rl (new RouteList);
7104 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
7105 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
7111 boost::shared_ptr<MidiTrack> mt = rtav->midi_track();
7114 rl->push_back (rtav->route());
7115 onoff = !mt->input_active();
7119 _session->set_exclusive_input_active (rl, onoff, flip_others);
7126 lock_dialog = new Gtk::Dialog (string_compose (_("%1: Locked"), PROGRAM_NAME), true);
7128 Gtk::Image* padlock = manage (new Gtk::Image (ARDOUR_UI_UTILS::get_icon ("padlock_closed")));
7129 lock_dialog->get_vbox()->pack_start (*padlock);
7131 ArdourButton* b = manage (new ArdourButton);
7132 b->set_name ("lock button");
7133 b->set_text (_("Click to unlock"));
7134 b->signal_clicked.connect (sigc::mem_fun (*this, &Editor::unlock));
7135 lock_dialog->get_vbox()->pack_start (*b);
7137 lock_dialog->get_vbox()->show_all ();
7138 lock_dialog->set_size_request (200, 200);
7142 /* The global menu bar continues to be accessible to applications
7143 with modal dialogs, which means that we need to desensitize
7144 all items in the menu bar. Since those items are really just
7145 proxies for actions, that means disabling all actions.
7147 ActionManager::disable_all_actions ();
7149 lock_dialog->present ();
7155 lock_dialog->hide ();
7158 ActionManager::pop_action_state ();
7161 if (ARDOUR_UI::config()->get_lock_gui_after_seconds()) {
7162 start_lock_event_timing ();
7167 Editor::bring_in_callback (Gtk::Label* label, uint32_t n, uint32_t total, string name)
7169 Gtkmm2ext::UI::instance()->call_slot (invalidator (*this), boost::bind (&Editor::update_bring_in_message, this, label, n, total, name));
7173 Editor::update_bring_in_message (Gtk::Label* label, uint32_t n, uint32_t total, string name)
7175 label->set_text (string_compose ("Copying %1, %2 of %3", name, n, total));
7176 Gtkmm2ext::UI::instance()->flush_pending ();
7180 Editor::bring_all_sources_into_session ()
7187 ArdourDialog w (_("Moving embedded files into session folder"));
7188 w.get_vbox()->pack_start (msg);
7191 /* flush all pending GUI events because we're about to start copying
7195 Gtkmm2ext::UI::instance()->flush_pending ();
7199 _session->bring_all_sources_into_session (boost::bind (&Editor::bring_in_callback, this, &msg, _1, _2, _3));