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 */
30 #include "pbd/error.h"
31 #include "pbd/basename.h"
32 #include "pbd/pthread_utils.h"
33 #include "pbd/memento_command.h"
34 #include "pbd/unwind.h"
35 #include "pbd/whitespace.h"
36 #include "pbd/stateful_diff_command.h"
38 #include <gtkmm2ext/utils.h>
39 #include <gtkmm2ext/choice.h>
40 #include <gtkmm2ext/popup.h>
42 #include "ardour/audio_track.h"
43 #include "ardour/audioregion.h"
44 #include "ardour/dB.h"
45 #include "ardour/location.h"
46 #include "ardour/midi_region.h"
47 #include "ardour/midi_track.h"
48 #include "ardour/operations.h"
49 #include "ardour/playlist_factory.h"
50 #include "ardour/profile.h"
51 #include "ardour/quantize.h"
52 #include "ardour/region_factory.h"
53 #include "ardour/reverse.h"
54 #include "ardour/session.h"
55 #include "ardour/session_playlists.h"
56 #include "ardour/strip_silence.h"
57 #include "ardour/transient_detector.h"
59 #include "canvas/canvas.h"
62 #include "ardour_ui.h"
63 #include "audio_region_view.h"
64 #include "audio_streamview.h"
65 #include "audio_time_axis.h"
66 #include "automation_time_axis.h"
67 #include "control_point.h"
71 #include "editor_cursors.h"
72 #include "editor_drag.h"
73 #include "editor_regions.h"
74 #include "editor_routes.h"
75 #include "gui_thread.h"
76 #include "insert_time_dialog.h"
77 #include "interthread_progress_window.h"
79 #include "midi_region_view.h"
80 #include "mixer_strip.h"
81 #include "mouse_cursors.h"
82 #include "normalize_dialog.h"
83 #include "patch_change_dialog.h"
84 #include "quantize_dialog.h"
85 #include "region_gain_line.h"
86 #include "rgb_macros.h"
87 #include "route_time_axis.h"
88 #include "selection.h"
89 #include "selection_templates.h"
90 #include "streamview.h"
91 #include "strip_silence_dialog.h"
92 #include "time_axis_view.h"
93 #include "transpose_dialog.h"
98 using namespace ARDOUR;
101 using namespace Gtkmm2ext;
102 using namespace Editing;
103 using Gtkmm2ext::Keyboard;
105 /***********************************************************************
107 ***********************************************************************/
110 Editor::undo (uint32_t n)
112 if (_drags->active ()) {
122 Editor::redo (uint32_t n)
124 if (_drags->active ()) {
134 Editor::split_regions_at (framepos_t where, RegionSelection& regions)
138 RegionSelection pre_selected_regions = selection->regions;
139 bool working_on_selection = !pre_selected_regions.empty();
141 list<boost::shared_ptr<Playlist> > used_playlists;
142 list<RouteTimeAxisView*> used_trackviews;
144 if (regions.empty()) {
148 begin_reversible_command (_("split"));
150 // if splitting a single region, and snap-to is using
151 // region boundaries, don't pay attention to them
153 if (regions.size() == 1) {
154 switch (_snap_type) {
155 case SnapToRegionStart:
156 case SnapToRegionSync:
157 case SnapToRegionEnd:
166 EditorFreeze(); /* Emit Signal */
169 for (RegionSelection::iterator a = regions.begin(); a != regions.end(); ) {
171 RegionSelection::iterator tmp;
173 /* XXX this test needs to be more complicated, to make sure we really
174 have something to split.
177 if (!(*a)->region()->covers (where)) {
185 boost::shared_ptr<Playlist> pl = (*a)->region()->playlist();
193 /* we haven't seen this playlist before */
195 /* remember used playlists so we can thaw them later */
196 used_playlists.push_back(pl);
198 TimeAxisView& tv = (*a)->get_time_axis_view();
199 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (&tv);
201 used_trackviews.push_back (rtv);
208 pl->clear_changes ();
209 pl->split_region ((*a)->region(), where);
210 _session->add_command (new StatefulDiffCommand (pl));
216 vector<sigc::connection> region_added_connections;
218 for (list<RouteTimeAxisView*>::iterator i = used_trackviews.begin(); i != used_trackviews.end(); ++i) {
219 region_added_connections.push_back ((*i)->view()->RegionViewAdded.connect (sigc::mem_fun(*this, &Editor::collect_new_region_view)));
222 latest_regionviews.clear ();
224 while (used_playlists.size() > 0) {
225 list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
227 used_playlists.pop_front();
230 for (vector<sigc::connection>::iterator c = region_added_connections.begin(); c != region_added_connections.end(); ++c) {
234 commit_reversible_command ();
237 EditorThaw(); /* Emit Signal */
240 if (ARDOUR::Profile->get_mixbus()) {
241 //IFF we were working on selected regions, try to reinstate the other region selections that existed before the freeze/thaw.
242 _ignore_follow_edits = true; //a split will change the region selection in mysterious ways; its not practical or wanted to follow this edit
243 if( working_on_selection ) {
244 selection->add ( pre_selected_regions );
245 selection->add (latest_regionviews); //these are the new regions created after the split
247 _ignore_follow_edits = false;
251 /** Move one extreme of the current range selection. If more than one range is selected,
252 * the start of the earliest range or the end of the latest range is moved.
254 * @param move_end true to move the end of the current range selection, false to move
256 * @param next true to move the extreme to the next region boundary, false to move to
260 Editor::move_range_selection_start_or_end_to_region_boundary (bool move_end, bool next)
262 if (selection->time.start() == selection->time.end_frame()) {
266 framepos_t start = selection->time.start ();
267 framepos_t end = selection->time.end_frame ();
269 /* the position of the thing we may move */
270 framepos_t pos = move_end ? end : start;
271 int dir = next ? 1 : -1;
273 /* so we don't find the current region again */
274 if (dir > 0 || pos > 0) {
278 framepos_t const target = get_region_boundary (pos, dir, true, false);
293 begin_reversible_command (_("alter selection"));
294 selection->set_preserving_all_ranges (start, end);
295 commit_reversible_command ();
299 Editor::nudge_forward_release (GdkEventButton* ev)
301 if (ev->state & Keyboard::PrimaryModifier) {
302 nudge_forward (false, true);
304 nudge_forward (false, false);
310 Editor::nudge_backward_release (GdkEventButton* ev)
312 if (ev->state & Keyboard::PrimaryModifier) {
313 nudge_backward (false, true);
315 nudge_backward (false, false);
322 Editor::nudge_forward (bool next, bool force_playhead)
325 framepos_t next_distance;
331 RegionSelection rs = get_regions_from_selection_and_entered ();
333 if (!force_playhead && !rs.empty()) {
335 begin_reversible_command (_("nudge regions forward"));
337 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
338 boost::shared_ptr<Region> r ((*i)->region());
340 distance = get_nudge_distance (r->position(), next_distance);
343 distance = next_distance;
347 r->set_position (r->position() + distance);
348 _session->add_command (new StatefulDiffCommand (r));
351 commit_reversible_command ();
354 } else if (!force_playhead && !selection->markers.empty()) {
358 begin_reversible_command (_("nudge location forward"));
360 for (MarkerSelection::iterator i = selection->markers.begin(); i != selection->markers.end(); ++i) {
362 Location* loc = find_location_from_marker ((*i), is_start);
366 XMLNode& before (loc->get_state());
369 distance = get_nudge_distance (loc->start(), next_distance);
371 distance = next_distance;
373 if (max_framepos - distance > loc->start() + loc->length()) {
374 loc->set_start (loc->start() + distance);
376 loc->set_start (max_framepos - loc->length());
379 distance = get_nudge_distance (loc->end(), next_distance);
381 distance = next_distance;
383 if (max_framepos - distance > loc->end()) {
384 loc->set_end (loc->end() + distance);
386 loc->set_end (max_framepos);
389 XMLNode& after (loc->get_state());
390 _session->add_command (new MementoCommand<Location>(*loc, &before, &after));
394 commit_reversible_command ();
397 distance = get_nudge_distance (playhead_cursor->current_frame (), next_distance);
398 _session->request_locate (playhead_cursor->current_frame () + distance);
403 Editor::nudge_backward (bool next, bool force_playhead)
406 framepos_t next_distance;
412 RegionSelection rs = get_regions_from_selection_and_entered ();
414 if (!force_playhead && !rs.empty()) {
416 begin_reversible_command (_("nudge regions backward"));
418 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
419 boost::shared_ptr<Region> r ((*i)->region());
421 distance = get_nudge_distance (r->position(), next_distance);
424 distance = next_distance;
429 if (r->position() > distance) {
430 r->set_position (r->position() - distance);
434 _session->add_command (new StatefulDiffCommand (r));
437 commit_reversible_command ();
439 } else if (!force_playhead && !selection->markers.empty()) {
443 begin_reversible_command (_("nudge location forward"));
445 for (MarkerSelection::iterator i = selection->markers.begin(); i != selection->markers.end(); ++i) {
447 Location* loc = find_location_from_marker ((*i), is_start);
451 XMLNode& before (loc->get_state());
454 distance = get_nudge_distance (loc->start(), next_distance);
456 distance = next_distance;
458 if (distance < loc->start()) {
459 loc->set_start (loc->start() - distance);
464 distance = get_nudge_distance (loc->end(), next_distance);
467 distance = next_distance;
470 if (distance < loc->end() - loc->length()) {
471 loc->set_end (loc->end() - distance);
473 loc->set_end (loc->length());
477 XMLNode& after (loc->get_state());
478 _session->add_command (new MementoCommand<Location>(*loc, &before, &after));
482 commit_reversible_command ();
486 distance = get_nudge_distance (playhead_cursor->current_frame (), next_distance);
488 if (playhead_cursor->current_frame () > distance) {
489 _session->request_locate (playhead_cursor->current_frame () - distance);
491 _session->goto_start();
497 Editor::nudge_forward_capture_offset ()
499 RegionSelection rs = get_regions_from_selection_and_entered ();
501 if (!_session || rs.empty()) {
505 begin_reversible_command (_("nudge forward"));
507 framepos_t const distance = _session->worst_output_latency();
509 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
510 boost::shared_ptr<Region> r ((*i)->region());
513 r->set_position (r->position() + distance);
514 _session->add_command(new StatefulDiffCommand (r));
517 commit_reversible_command ();
521 Editor::nudge_backward_capture_offset ()
523 RegionSelection rs = get_regions_from_selection_and_entered ();
525 if (!_session || rs.empty()) {
529 begin_reversible_command (_("nudge backward"));
531 framepos_t const distance = _session->worst_output_latency();
533 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
534 boost::shared_ptr<Region> r ((*i)->region());
538 if (r->position() > distance) {
539 r->set_position (r->position() - distance);
543 _session->add_command(new StatefulDiffCommand (r));
546 commit_reversible_command ();
549 struct RegionSelectionPositionSorter {
550 bool operator() (RegionView* a, RegionView* b) {
551 return a->region()->position() < b->region()->position();
556 Editor::sequence_regions ()
559 framepos_t r_end_prev;
567 RegionSelection rs = get_regions_from_selection_and_entered ();
568 rs.sort(RegionSelectionPositionSorter());
572 begin_reversible_command (_("sequence regions"));
573 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
574 boost::shared_ptr<Region> r ((*i)->region());
582 if(r->position_locked())
589 r->set_position(r_end_prev);
592 _session->add_command (new StatefulDiffCommand (r));
594 r_end=r->position() + r->length();
598 commit_reversible_command ();
606 Editor::move_to_start ()
608 _session->goto_start ();
612 Editor::move_to_end ()
615 _session->request_locate (_session->current_end_frame());
619 Editor::build_region_boundary_cache ()
622 vector<RegionPoint> interesting_points;
623 boost::shared_ptr<Region> r;
624 TrackViewList tracks;
627 region_boundary_cache.clear ();
633 switch (_snap_type) {
634 case SnapToRegionStart:
635 interesting_points.push_back (Start);
637 case SnapToRegionEnd:
638 interesting_points.push_back (End);
640 case SnapToRegionSync:
641 interesting_points.push_back (SyncPoint);
643 case SnapToRegionBoundary:
644 interesting_points.push_back (Start);
645 interesting_points.push_back (End);
648 fatal << string_compose (_("build_region_boundary_cache called with snap_type = %1"), _snap_type) << endmsg;
653 TimeAxisView *ontrack = 0;
656 if (!selection->tracks.empty()) {
657 tlist = selection->tracks.filter_to_unique_playlists ();
659 tlist = track_views.filter_to_unique_playlists ();
662 while (pos < _session->current_end_frame() && !at_end) {
665 framepos_t lpos = max_framepos;
667 for (vector<RegionPoint>::iterator p = interesting_points.begin(); p != interesting_points.end(); ++p) {
669 if ((r = find_next_region (pos, *p, 1, tlist, &ontrack)) == 0) {
670 if (*p == interesting_points.back()) {
673 /* move to next point type */
679 rpos = r->first_frame();
683 rpos = r->last_frame();
687 rpos = r->sync_position ();
695 RouteTimeAxisView *rtav;
697 if (ontrack != 0 && (rtav = dynamic_cast<RouteTimeAxisView*>(ontrack)) != 0 ) {
698 if (rtav->track() != 0) {
699 speed = rtav->track()->speed();
703 rpos = track_frame_to_session_frame (rpos, speed);
709 /* prevent duplicates, but we don't use set<> because we want to be able
713 vector<framepos_t>::iterator ri;
715 for (ri = region_boundary_cache.begin(); ri != region_boundary_cache.end(); ++ri) {
721 if (ri == region_boundary_cache.end()) {
722 region_boundary_cache.push_back (rpos);
729 /* finally sort to be sure that the order is correct */
731 sort (region_boundary_cache.begin(), region_boundary_cache.end());
734 boost::shared_ptr<Region>
735 Editor::find_next_region (framepos_t frame, RegionPoint point, int32_t dir, TrackViewList& tracks, TimeAxisView **ontrack)
737 TrackViewList::iterator i;
738 framepos_t closest = max_framepos;
739 boost::shared_ptr<Region> ret;
743 framepos_t track_frame;
744 RouteTimeAxisView *rtav;
746 for (i = tracks.begin(); i != tracks.end(); ++i) {
749 boost::shared_ptr<Region> r;
752 if ( (rtav = dynamic_cast<RouteTimeAxisView*>(*i)) != 0 ) {
753 if (rtav->track()!=0)
754 track_speed = rtav->track()->speed();
757 track_frame = session_frame_to_track_frame(frame, track_speed);
759 if ((r = (*i)->find_next_region (track_frame, point, dir)) == 0) {
765 rpos = r->first_frame ();
769 rpos = r->last_frame ();
773 rpos = r->sync_position ();
777 // rpos is a "track frame", converting it to "_session frame"
778 rpos = track_frame_to_session_frame(rpos, track_speed);
781 distance = rpos - frame;
783 distance = frame - rpos;
786 if (distance < closest) {
798 Editor::find_next_region_boundary (framepos_t pos, int32_t dir, const TrackViewList& tracks)
800 framecnt_t distance = max_framepos;
801 framepos_t current_nearest = -1;
803 for (TrackViewList::const_iterator i = tracks.begin(); i != tracks.end(); ++i) {
804 framepos_t contender;
807 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*i);
813 if ((contender = rtv->find_next_region_boundary (pos, dir)) < 0) {
817 d = ::llabs (pos - contender);
820 current_nearest = contender;
825 return current_nearest;
829 Editor::get_region_boundary (framepos_t pos, int32_t dir, bool with_selection, bool only_onscreen)
834 if (with_selection && Config->get_region_boundaries_from_selected_tracks()) {
836 if (!selection->tracks.empty()) {
838 target = find_next_region_boundary (pos, dir, selection->tracks);
842 if (only_onscreen || Config->get_region_boundaries_from_onscreen_tracks()) {
843 get_onscreen_tracks (tvl);
844 target = find_next_region_boundary (pos, dir, tvl);
846 target = find_next_region_boundary (pos, dir, track_views);
852 if (only_onscreen || Config->get_region_boundaries_from_onscreen_tracks()) {
853 get_onscreen_tracks (tvl);
854 target = find_next_region_boundary (pos, dir, tvl);
856 target = find_next_region_boundary (pos, dir, track_views);
864 Editor::cursor_to_region_boundary (bool with_selection, int32_t dir)
866 framepos_t pos = playhead_cursor->current_frame ();
873 // so we don't find the current region again..
874 if (dir > 0 || pos > 0) {
878 if ((target = get_region_boundary (pos, dir, with_selection, false)) < 0) {
882 _session->request_locate (target);
886 Editor::cursor_to_next_region_boundary (bool with_selection)
888 cursor_to_region_boundary (with_selection, 1);
892 Editor::cursor_to_previous_region_boundary (bool with_selection)
894 cursor_to_region_boundary (with_selection, -1);
898 Editor::cursor_to_region_point (EditorCursor* cursor, RegionPoint point, int32_t dir)
900 boost::shared_ptr<Region> r;
901 framepos_t pos = cursor->current_frame ();
907 TimeAxisView *ontrack = 0;
909 // so we don't find the current region again..
913 if (!selection->tracks.empty()) {
915 r = find_next_region (pos, point, dir, selection->tracks, &ontrack);
917 } else if (clicked_axisview) {
920 t.push_back (clicked_axisview);
922 r = find_next_region (pos, point, dir, t, &ontrack);
926 r = find_next_region (pos, point, dir, track_views, &ontrack);
935 pos = r->first_frame ();
939 pos = r->last_frame ();
943 pos = r->sync_position ();
948 RouteTimeAxisView *rtav;
950 if ( ontrack != 0 && (rtav = dynamic_cast<RouteTimeAxisView*>(ontrack)) != 0 ) {
951 if (rtav->track() != 0) {
952 speed = rtav->track()->speed();
956 pos = track_frame_to_session_frame(pos, speed);
958 if (cursor == playhead_cursor) {
959 _session->request_locate (pos);
961 cursor->set_position (pos);
966 Editor::cursor_to_next_region_point (EditorCursor* cursor, RegionPoint point)
968 cursor_to_region_point (cursor, point, 1);
972 Editor::cursor_to_previous_region_point (EditorCursor* cursor, RegionPoint point)
974 cursor_to_region_point (cursor, point, -1);
978 Editor::cursor_to_selection_start (EditorCursor *cursor)
982 switch (mouse_mode) {
984 if (!selection->regions.empty()) {
985 pos = selection->regions.start();
990 if (!selection->time.empty()) {
991 pos = selection->time.start ();
999 if (cursor == playhead_cursor) {
1000 _session->request_locate (pos);
1002 cursor->set_position (pos);
1007 Editor::cursor_to_selection_end (EditorCursor *cursor)
1011 switch (mouse_mode) {
1013 if (!selection->regions.empty()) {
1014 pos = selection->regions.end_frame();
1019 if (!selection->time.empty()) {
1020 pos = selection->time.end_frame ();
1028 if (cursor == playhead_cursor) {
1029 _session->request_locate (pos);
1031 cursor->set_position (pos);
1036 Editor::selected_marker_to_region_boundary (bool with_selection, int32_t dir)
1046 if (selection->markers.empty()) {
1050 if (!mouse_frame (mouse, ignored)) {
1054 add_location_mark (mouse);
1057 if ((loc = find_location_from_marker (selection->markers.front(), ignored)) == 0) {
1061 framepos_t pos = loc->start();
1063 // so we don't find the current region again..
1064 if (dir > 0 || pos > 0) {
1068 if ((target = get_region_boundary (pos, dir, with_selection, false)) < 0) {
1072 loc->move_to (target);
1076 Editor::selected_marker_to_next_region_boundary (bool with_selection)
1078 selected_marker_to_region_boundary (with_selection, 1);
1082 Editor::selected_marker_to_previous_region_boundary (bool with_selection)
1084 selected_marker_to_region_boundary (with_selection, -1);
1088 Editor::selected_marker_to_region_point (RegionPoint point, int32_t dir)
1090 boost::shared_ptr<Region> r;
1095 if (!_session || selection->markers.empty()) {
1099 if ((loc = find_location_from_marker (selection->markers.front(), ignored)) == 0) {
1103 TimeAxisView *ontrack = 0;
1107 // so we don't find the current region again..
1111 if (!selection->tracks.empty()) {
1113 r = find_next_region (pos, point, dir, selection->tracks, &ontrack);
1117 r = find_next_region (pos, point, dir, track_views, &ontrack);
1126 pos = r->first_frame ();
1130 pos = r->last_frame ();
1134 pos = r->adjust_to_sync (r->first_frame());
1139 RouteTimeAxisView *rtav;
1141 if (ontrack != 0 && (rtav = dynamic_cast<RouteTimeAxisView*>(ontrack)) != 0) {
1142 if (rtav->track() != 0) {
1143 speed = rtav->track()->speed();
1147 pos = track_frame_to_session_frame(pos, speed);
1153 Editor::selected_marker_to_next_region_point (RegionPoint point)
1155 selected_marker_to_region_point (point, 1);
1159 Editor::selected_marker_to_previous_region_point (RegionPoint point)
1161 selected_marker_to_region_point (point, -1);
1165 Editor::selected_marker_to_selection_start ()
1171 if (!_session || selection->markers.empty()) {
1175 if ((loc = find_location_from_marker (selection->markers.front(), ignored)) == 0) {
1179 switch (mouse_mode) {
1181 if (!selection->regions.empty()) {
1182 pos = selection->regions.start();
1187 if (!selection->time.empty()) {
1188 pos = selection->time.start ();
1200 Editor::selected_marker_to_selection_end ()
1206 if (!_session || selection->markers.empty()) {
1210 if ((loc = find_location_from_marker (selection->markers.front(), ignored)) == 0) {
1214 switch (mouse_mode) {
1216 if (!selection->regions.empty()) {
1217 pos = selection->regions.end_frame();
1222 if (!selection->time.empty()) {
1223 pos = selection->time.end_frame ();
1235 Editor::scroll_playhead (bool forward)
1237 framepos_t pos = playhead_cursor->current_frame ();
1238 framecnt_t delta = (framecnt_t) floor (current_page_samples() / 0.8);
1241 if (pos == max_framepos) {
1245 if (pos < max_framepos - delta) {
1264 _session->request_locate (pos);
1268 Editor::cursor_align (bool playhead_to_edit)
1274 if (playhead_to_edit) {
1276 if (selection->markers.empty()) {
1280 _session->request_locate (selection->markers.front()->position(), _session->transport_rolling());
1283 /* move selected markers to playhead */
1285 for (MarkerSelection::iterator i = selection->markers.begin(); i != selection->markers.end(); ++i) {
1288 Location* loc = find_location_from_marker (*i, ignored);
1290 if (loc->is_mark()) {
1291 loc->set_start (playhead_cursor->current_frame ());
1293 loc->set (playhead_cursor->current_frame (),
1294 playhead_cursor->current_frame () + loc->length());
1301 Editor::scroll_backward (float pages)
1303 framepos_t const one_page = (framepos_t) rint (_visible_canvas_width * samples_per_pixel);
1304 framepos_t const cnt = (framepos_t) floor (pages * one_page);
1307 if (leftmost_frame < cnt) {
1310 frame = leftmost_frame - cnt;
1313 reset_x_origin (frame);
1317 Editor::scroll_forward (float pages)
1319 framepos_t const one_page = (framepos_t) rint (_visible_canvas_width * samples_per_pixel);
1320 framepos_t const cnt = (framepos_t) floor (pages * one_page);
1323 if (max_framepos - cnt < leftmost_frame) {
1324 frame = max_framepos - cnt;
1326 frame = leftmost_frame + cnt;
1329 reset_x_origin (frame);
1333 Editor::scroll_tracks_down ()
1335 double vert_value = vertical_adjustment.get_value() + vertical_adjustment.get_page_size();
1336 if (vert_value > vertical_adjustment.get_upper() - _visible_canvas_height) {
1337 vert_value = vertical_adjustment.get_upper() - _visible_canvas_height;
1340 vertical_adjustment.set_value (vert_value);
1344 Editor::scroll_tracks_up ()
1346 vertical_adjustment.set_value (vertical_adjustment.get_value() - vertical_adjustment.get_page_size());
1350 Editor::scroll_tracks_down_line ()
1352 double vert_value = vertical_adjustment.get_value() + 60;
1354 if (vert_value > vertical_adjustment.get_upper() - _visible_canvas_height) {
1355 vert_value = vertical_adjustment.get_upper() - _visible_canvas_height;
1358 vertical_adjustment.set_value (vert_value);
1362 Editor::scroll_tracks_up_line ()
1364 reset_y_origin (vertical_adjustment.get_value() - 60);
1368 Editor::scroll_down_one_track ()
1370 TrackViewList::reverse_iterator next = track_views.rbegin();
1371 std::pair<TimeAxisView*,double> res;
1372 const double top_of_trackviews = vertical_adjustment.get_value();
1374 for (TrackViewList::reverse_iterator t = track_views.rbegin(); t != track_views.rend(); ++t) {
1375 if ((*t)->hidden()) {
1380 if (next != track_views.rbegin()) {
1381 --next; // moves "next" towards the lower/later tracks since it is a reverse iterator
1384 /* If this is the upper-most visible trackview, we want to display
1385 the one above it (next)
1388 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.rbegin()) {
1398 ensure_time_axis_view_is_visible (**next, true);
1406 Editor::scroll_up_one_track ()
1408 TrackViewList::iterator prev = track_views.end();
1409 std::pair<TimeAxisView*,double> res;
1410 double top_of_trackviews = vertical_adjustment.get_value ();
1412 for (TrackViewList::iterator t = track_views.begin(); t != track_views.end(); ++t) {
1414 if ((*t)->hidden()) {
1418 /* find the trackview at the top of the trackview group */
1419 res = (*t)->covers_y_position (top_of_trackviews);
1428 if (prev != track_views.end()) {
1429 ensure_time_axis_view_is_visible (**prev, true);
1439 Editor::tav_zoom_step (bool coarser)
1441 DisplaySuspender ds;
1445 if (selection->tracks.empty()) {
1448 ts = &selection->tracks;
1451 for (TrackViewList::iterator i = ts->begin(); i != ts->end(); ++i) {
1452 TimeAxisView *tv = (static_cast<TimeAxisView*>(*i));
1453 tv->step_height (coarser);
1458 Editor::tav_zoom_smooth (bool coarser, bool force_all)
1460 DisplaySuspender ds;
1464 if (selection->tracks.empty() || force_all) {
1467 ts = &selection->tracks;
1470 for (TrackViewList::iterator i = ts->begin(); i != ts->end(); ++i) {
1471 TimeAxisView *tv = (static_cast<TimeAxisView*>(*i));
1472 uint32_t h = tv->current_height ();
1477 if (h >= TimeAxisView::preset_height (HeightSmall)) {
1482 tv->set_height (h + 5);
1489 Editor::temporal_zoom_step (bool coarser)
1491 ENSURE_GUI_THREAD (*this, &Editor::temporal_zoom_step, coarser)
1493 framecnt_t nspp = samples_per_pixel;
1501 temporal_zoom (nspp);
1505 Editor::temporal_zoom (framecnt_t fpp)
1511 framepos_t current_page = current_page_samples();
1512 framepos_t current_leftmost = leftmost_frame;
1513 framepos_t current_rightmost;
1514 framepos_t current_center;
1515 framepos_t new_page_size;
1516 framepos_t half_page_size;
1517 framepos_t leftmost_after_zoom = 0;
1519 bool in_track_canvas;
1523 if (fpp == samples_per_pixel) {
1527 // Imposing an arbitrary limit to zoom out as too much zoom out produces
1528 // segfaults for lack of memory. If somebody decides this is not high enough I
1529 // believe it can be raisen to higher values but some limit must be in place.
1531 // This constant represents 1 day @ 48kHz on a 1600 pixel wide display
1532 // all of which is used for the editor track displays. The whole day
1533 // would be 4147200000 samples, so 2592000 samples per pixel.
1535 nfpp = min (fpp, (framecnt_t) 2592000);
1536 nfpp = max ((framecnt_t) 1, fpp);
1538 new_page_size = (framepos_t) floor (_visible_canvas_width * nfpp);
1539 half_page_size = new_page_size / 2;
1541 switch (zoom_focus) {
1543 leftmost_after_zoom = current_leftmost;
1546 case ZoomFocusRight:
1547 current_rightmost = leftmost_frame + current_page;
1548 if (current_rightmost < new_page_size) {
1549 leftmost_after_zoom = 0;
1551 leftmost_after_zoom = current_rightmost - new_page_size;
1555 case ZoomFocusCenter:
1556 current_center = current_leftmost + (current_page/2);
1557 if (current_center < half_page_size) {
1558 leftmost_after_zoom = 0;
1560 leftmost_after_zoom = current_center - half_page_size;
1564 case ZoomFocusPlayhead:
1565 /* centre playhead */
1566 l = playhead_cursor->current_frame () - (new_page_size * 0.5);
1569 leftmost_after_zoom = 0;
1570 } else if (l > max_framepos) {
1571 leftmost_after_zoom = max_framepos - new_page_size;
1573 leftmost_after_zoom = (framepos_t) l;
1577 case ZoomFocusMouse:
1578 /* try to keep the mouse over the same point in the display */
1580 if (!mouse_frame (where, in_track_canvas)) {
1581 /* use playhead instead */
1582 where = playhead_cursor->current_frame ();
1584 if (where < half_page_size) {
1585 leftmost_after_zoom = 0;
1587 leftmost_after_zoom = where - half_page_size;
1592 l = - ((new_page_size * ((where - current_leftmost)/(double)current_page)) - where);
1595 leftmost_after_zoom = 0;
1596 } else if (l > max_framepos) {
1597 leftmost_after_zoom = max_framepos - new_page_size;
1599 leftmost_after_zoom = (framepos_t) l;
1606 /* try to keep the edit point in the same place */
1607 where = get_preferred_edit_position ();
1611 double l = - ((new_page_size * ((where - current_leftmost)/(double)current_page)) - where);
1614 leftmost_after_zoom = 0;
1615 } else if (l > max_framepos) {
1616 leftmost_after_zoom = max_framepos - new_page_size;
1618 leftmost_after_zoom = (framepos_t) l;
1622 /* edit point not defined */
1629 // leftmost_after_zoom = min (leftmost_after_zoom, _session->current_end_frame());
1631 reposition_and_zoom (leftmost_after_zoom, nfpp);
1635 Editor::calc_extra_zoom_edges(framepos_t &start, framepos_t &end)
1637 /* this func helps make sure we leave a little space
1638 at each end of the editor so that the zoom doesn't fit the region
1639 precisely to the screen.
1642 GdkScreen* screen = gdk_screen_get_default ();
1643 gint pixwidth = gdk_screen_get_width (screen);
1644 gint mmwidth = gdk_screen_get_width_mm (screen);
1645 double pix_per_mm = (double) pixwidth/ (double) mmwidth;
1646 double one_centimeter_in_pixels = pix_per_mm * 10.0;
1648 framepos_t range = end - start;
1649 double new_fpp = (double) range / (double) _visible_canvas_width;
1650 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;
1667 Editor::temporal_zoom_region (bool both_axes)
1669 framepos_t start = max_framepos;
1671 set<TimeAxisView*> tracks;
1673 RegionSelection rs = get_regions_from_selection_and_entered ();
1679 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
1681 if ((*i)->region()->position() < start) {
1682 start = (*i)->region()->position();
1685 if ((*i)->region()->last_frame() + 1 > end) {
1686 end = (*i)->region()->last_frame() + 1;
1689 tracks.insert (&((*i)->get_time_axis_view()));
1692 if ((start == 0 && end == 0) || end < start) {
1696 calc_extra_zoom_edges(start, end);
1698 /* if we're zooming on both axes we need to save track heights etc.
1701 undo_visual_stack.push_back (current_visual_state (both_axes));
1703 PBD::Unwinder<bool> nsv (no_save_visual, true);
1705 temporal_zoom_by_frame (start, end);
1708 uint32_t per_track_height = (uint32_t) floor ((_visible_canvas_height - 10.0) / tracks.size());
1710 /* set visible track heights appropriately */
1712 for (set<TimeAxisView*>::iterator t = tracks.begin(); t != tracks.end(); ++t) {
1713 (*t)->set_height (per_track_height);
1716 /* hide irrelevant tracks */
1718 DisplaySuspender ds;
1720 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1721 if (find (tracks.begin(), tracks.end(), (*i)) == tracks.end()) {
1722 hide_track_in_display (*i);
1726 vertical_adjustment.set_value (0.0);
1729 redo_visual_stack.push_back (current_visual_state (both_axes));
1733 Editor::zoom_to_region (bool both_axes)
1735 temporal_zoom_region (both_axes);
1739 Editor::temporal_zoom_selection (bool both_axes)
1741 if (!selection) return;
1743 //if a range is selected, zoom to that
1744 if (!selection->time.empty()) {
1746 framepos_t start = selection->time.start();
1747 framepos_t end = selection->time.end_frame();
1749 calc_extra_zoom_edges(start, end);
1751 temporal_zoom_by_frame (start, end);
1754 fit_selected_tracks();
1757 temporal_zoom_region(both_axes);
1764 Editor::temporal_zoom_session ()
1766 ENSURE_GUI_THREAD (*this, &Editor::temporal_zoom_session)
1769 framecnt_t start = _session->current_start_frame();
1770 framecnt_t end = _session->current_end_frame();
1772 if (_session->actively_recording () ) {
1773 framepos_t cur = playhead_cursor->current_frame ();
1775 /* recording beyond the end marker; zoom out
1776 * by 5 seconds more so that if 'follow
1777 * playhead' is active we don't immediately
1780 end = cur + _session->frame_rate() * 5;
1784 if ((start == 0 && end == 0) || end < start) {
1788 calc_extra_zoom_edges(start, end);
1790 temporal_zoom_by_frame (start, end);
1795 Editor::temporal_zoom_by_frame (framepos_t start, framepos_t end)
1797 if (!_session) return;
1799 if ((start == 0 && end == 0) || end < start) {
1803 framepos_t range = end - start;
1805 double const new_fpp = (double) range / (double) _visible_canvas_width;
1807 framepos_t new_page = (framepos_t) floor (_visible_canvas_width * new_fpp);
1808 framepos_t middle = (framepos_t) floor ((double) start + ((double) range / 2.0f));
1809 framepos_t new_leftmost = (framepos_t) floor ((double) middle - ((double) new_page / 2.0f));
1811 if (new_leftmost > middle) {
1815 if (new_leftmost < 0) {
1819 reposition_and_zoom (new_leftmost, new_fpp);
1823 Editor::temporal_zoom_to_frame (bool coarser, framepos_t frame)
1829 framecnt_t range_before = frame - leftmost_frame;
1833 if (samples_per_pixel <= 1) {
1836 new_spp = samples_per_pixel + (samples_per_pixel/2);
1838 range_before += range_before/2;
1840 if (samples_per_pixel >= 1) {
1841 new_spp = samples_per_pixel - (samples_per_pixel/2);
1843 /* could bail out here since we cannot zoom any finer,
1844 but leave that to the equality test below
1846 new_spp = samples_per_pixel;
1849 range_before -= range_before/2;
1852 if (new_spp == samples_per_pixel) {
1856 /* zoom focus is automatically taken as @param frame when this
1860 framepos_t new_leftmost = frame - (framepos_t)range_before;
1862 if (new_leftmost > frame) {
1866 if (new_leftmost < 0) {
1870 reposition_and_zoom (new_leftmost, new_spp);
1875 Editor::choose_new_marker_name(string &name) {
1877 if (!Config->get_name_new_markers()) {
1878 /* don't prompt user for a new name */
1882 ArdourPrompter dialog (true);
1884 dialog.set_prompt (_("New Name:"));
1886 dialog.set_title (_("New Location Marker"));
1888 dialog.set_name ("MarkNameWindow");
1889 dialog.set_size_request (250, -1);
1890 dialog.set_position (Gtk::WIN_POS_MOUSE);
1892 dialog.add_button (Stock::OK, RESPONSE_ACCEPT);
1893 dialog.set_initial_text (name);
1897 switch (dialog.run ()) {
1898 case RESPONSE_ACCEPT:
1904 dialog.get_result(name);
1911 Editor::add_location_from_selection ()
1915 if (selection->time.empty()) {
1919 if (_session == 0 || clicked_axisview == 0) {
1923 framepos_t start = selection->time[clicked_selection].start;
1924 framepos_t end = selection->time[clicked_selection].end;
1926 _session->locations()->next_available_name(rangename,"selection");
1927 Location *location = new Location (*_session, start, end, rangename, Location::IsRangeMarker);
1929 _session->begin_reversible_command (_("add marker"));
1930 XMLNode &before = _session->locations()->get_state();
1931 _session->locations()->add (location, true);
1932 XMLNode &after = _session->locations()->get_state();
1933 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
1934 _session->commit_reversible_command ();
1938 Editor::add_location_mark (framepos_t where)
1942 select_new_marker = true;
1944 _session->locations()->next_available_name(markername,"mark");
1945 if (!choose_new_marker_name(markername)) {
1948 Location *location = new Location (*_session, where, where, markername, Location::IsMark);
1949 _session->begin_reversible_command (_("add marker"));
1950 XMLNode &before = _session->locations()->get_state();
1951 _session->locations()->add (location, true);
1952 XMLNode &after = _session->locations()->get_state();
1953 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
1954 _session->commit_reversible_command ();
1958 Editor::add_location_from_playhead_cursor ()
1960 add_location_mark (_session->audible_frame());
1964 Editor::remove_location_at_playhead_cursor ()
1969 _session->begin_reversible_command (_("remove marker"));
1970 XMLNode &before = _session->locations()->get_state();
1971 bool removed = false;
1973 //find location(s) at this time
1974 Locations::LocationList locs;
1975 _session->locations()->find_all_between (_session->audible_frame(), _session->audible_frame()+1, locs, Location::Flags(0));
1976 for (Locations::LocationList::iterator i = locs.begin(); i != locs.end(); ++i) {
1977 if ((*i)->is_mark()) {
1978 _session->locations()->remove (*i);
1985 XMLNode &after = _session->locations()->get_state();
1986 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
1987 _session->commit_reversible_command ();
1992 /** Add a range marker around each selected region */
1994 Editor::add_locations_from_region ()
1996 RegionSelection rs = get_regions_from_selection_and_entered ();
2002 _session->begin_reversible_command (selection->regions.size () > 1 ? _("add markers") : _("add marker"));
2003 XMLNode &before = _session->locations()->get_state();
2005 for (RegionSelection::iterator i = rs.begin (); i != rs.end (); ++i) {
2007 boost::shared_ptr<Region> region = (*i)->region ();
2009 Location *location = new Location (*_session, region->position(), region->last_frame(), region->name(), Location::IsRangeMarker);
2011 _session->locations()->add (location, true);
2014 XMLNode &after = _session->locations()->get_state();
2015 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2016 _session->commit_reversible_command ();
2019 /** Add a single range marker around all selected regions */
2021 Editor::add_location_from_region ()
2023 RegionSelection rs = get_regions_from_selection_and_entered ();
2029 _session->begin_reversible_command (_("add marker"));
2030 XMLNode &before = _session->locations()->get_state();
2034 if (rs.size() > 1) {
2035 _session->locations()->next_available_name(markername, "regions");
2037 RegionView* rv = *(rs.begin());
2038 boost::shared_ptr<Region> region = rv->region();
2039 markername = region->name();
2042 if (!choose_new_marker_name(markername)) {
2046 // single range spanning all selected
2047 Location *location = new Location (*_session, selection->regions.start(), selection->regions.end_frame(), markername, Location::IsRangeMarker);
2048 _session->locations()->add (location, true);
2050 XMLNode &after = _session->locations()->get_state();
2051 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2052 _session->commit_reversible_command ();
2058 Editor::jump_forward_to_mark ()
2064 framepos_t pos = _session->locations()->first_mark_after (playhead_cursor->current_frame());
2070 _session->request_locate (pos, _session->transport_rolling());
2074 Editor::jump_backward_to_mark ()
2080 framepos_t pos = _session->locations()->first_mark_before (playhead_cursor->current_frame());
2086 _session->request_locate (pos, _session->transport_rolling());
2092 framepos_t const pos = _session->audible_frame ();
2095 _session->locations()->next_available_name (markername, "mark");
2097 if (!choose_new_marker_name (markername)) {
2101 _session->locations()->add (new Location (*_session, pos, 0, markername, Location::IsMark), true);
2105 Editor::clear_markers ()
2108 _session->begin_reversible_command (_("clear markers"));
2109 XMLNode &before = _session->locations()->get_state();
2110 _session->locations()->clear_markers ();
2111 XMLNode &after = _session->locations()->get_state();
2112 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2113 _session->commit_reversible_command ();
2118 Editor::clear_ranges ()
2121 _session->begin_reversible_command (_("clear ranges"));
2122 XMLNode &before = _session->locations()->get_state();
2124 _session->locations()->clear_ranges ();
2126 XMLNode &after = _session->locations()->get_state();
2127 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2128 _session->commit_reversible_command ();
2133 Editor::clear_locations ()
2135 _session->begin_reversible_command (_("clear locations"));
2136 XMLNode &before = _session->locations()->get_state();
2137 _session->locations()->clear ();
2138 XMLNode &after = _session->locations()->get_state();
2139 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2140 _session->commit_reversible_command ();
2141 _session->locations()->clear ();
2145 Editor::unhide_markers ()
2147 for (LocationMarkerMap::iterator i = location_markers.begin(); i != location_markers.end(); ++i) {
2148 Location *l = (*i).first;
2149 if (l->is_hidden() && l->is_mark()) {
2150 l->set_hidden(false, this);
2156 Editor::unhide_ranges ()
2158 for (LocationMarkerMap::iterator i = location_markers.begin(); i != location_markers.end(); ++i) {
2159 Location *l = (*i).first;
2160 if (l->is_hidden() && l->is_range_marker()) {
2161 l->set_hidden(false, this);
2166 /* INSERT/REPLACE */
2169 Editor::insert_region_list_selection (float times)
2171 RouteTimeAxisView *tv = 0;
2172 boost::shared_ptr<Playlist> playlist;
2174 if (clicked_routeview != 0) {
2175 tv = clicked_routeview;
2176 } else if (!selection->tracks.empty()) {
2177 if ((tv = dynamic_cast<RouteTimeAxisView*>(selection->tracks.front())) == 0) {
2180 } else if (entered_track != 0) {
2181 if ((tv = dynamic_cast<RouteTimeAxisView*>(entered_track)) == 0) {
2188 if ((playlist = tv->playlist()) == 0) {
2192 boost::shared_ptr<Region> region = _regions->get_single_selection ();
2197 begin_reversible_command (_("insert region"));
2198 playlist->clear_changes ();
2199 playlist->add_region ((RegionFactory::create (region, true)), get_preferred_edit_position(), times);
2200 if (Config->get_edit_mode() == Ripple)
2201 playlist->ripple (get_preferred_edit_position(), region->length() * times, boost::shared_ptr<Region>());
2203 _session->add_command(new StatefulDiffCommand (playlist));
2204 commit_reversible_command ();
2207 /* BUILT-IN EFFECTS */
2210 Editor::reverse_selection ()
2215 /* GAIN ENVELOPE EDITING */
2218 Editor::edit_envelope ()
2225 Editor::transition_to_rolling (bool fwd)
2231 if (_session->config.get_external_sync()) {
2232 switch (Config->get_sync_source()) {
2236 /* transport controlled by the master */
2241 if (_session->is_auditioning()) {
2242 _session->cancel_audition ();
2246 _session->request_transport_speed (fwd ? 1.0f : -1.0f);
2250 Editor::play_from_start ()
2252 _session->request_locate (_session->current_start_frame(), true);
2256 Editor::play_from_edit_point ()
2258 _session->request_locate (get_preferred_edit_position(), true);
2262 Editor::play_from_edit_point_and_return ()
2264 framepos_t start_frame;
2265 framepos_t return_frame;
2267 start_frame = get_preferred_edit_position (true);
2269 if (_session->transport_rolling()) {
2270 _session->request_locate (start_frame, false);
2274 /* don't reset the return frame if its already set */
2276 if ((return_frame = _session->requested_return_frame()) < 0) {
2277 return_frame = _session->audible_frame();
2280 if (start_frame >= 0) {
2281 _session->request_roll_at_and_return (start_frame, return_frame);
2286 Editor::play_selection ()
2288 if (selection->time.empty()) {
2292 _session->request_play_range (&selection->time, true);
2296 Editor::get_preroll ()
2298 return 1.0 /*Config->get_edit_preroll_seconds()*/ * _session->frame_rate();
2303 Editor::maybe_locate_with_edit_preroll ( framepos_t location )
2305 if ( _session->transport_rolling() || !Config->get_follow_edits() || _ignore_follow_edits )
2308 location -= get_preroll();
2310 //don't try to locate before the beginning of time
2314 //if follow_playhead is on, keep the playhead on the screen
2315 if ( _follow_playhead )
2316 if ( location < leftmost_frame )
2317 location = leftmost_frame;
2319 _session->request_locate( location );
2323 Editor::play_with_preroll ()
2325 if (selection->time.empty()) {
2328 framepos_t preroll = get_preroll();
2330 framepos_t start = 0;
2331 if (selection->time[clicked_selection].start > preroll)
2332 start = selection->time[clicked_selection].start - preroll;
2334 framepos_t end = selection->time[clicked_selection].end + preroll;
2336 AudioRange ar (start, end, 0);
2337 list<AudioRange> lar;
2340 _session->request_play_range (&lar, true);
2345 Editor::play_location (Location& location)
2347 if (location.start() <= location.end()) {
2351 _session->request_bounded_roll (location.start(), location.end());
2355 Editor::loop_location (Location& location)
2357 if (location.start() <= location.end()) {
2363 if ((tll = transport_loop_location()) != 0) {
2364 tll->set (location.start(), location.end());
2366 // enable looping, reposition and start rolling
2367 _session->request_locate (tll->start(), true);
2368 _session->request_play_loop (true);
2373 Editor::do_layer_operation (LayerOperation op)
2375 if (selection->regions.empty ()) {
2379 bool const multiple = selection->regions.size() > 1;
2383 begin_reversible_command (_("raise regions"));
2385 begin_reversible_command (_("raise region"));
2391 begin_reversible_command (_("raise regions to top"));
2393 begin_reversible_command (_("raise region to top"));
2399 begin_reversible_command (_("lower regions"));
2401 begin_reversible_command (_("lower region"));
2407 begin_reversible_command (_("lower regions to bottom"));
2409 begin_reversible_command (_("lower region"));
2414 set<boost::shared_ptr<Playlist> > playlists = selection->regions.playlists ();
2415 for (set<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
2416 (*i)->clear_owned_changes ();
2419 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
2420 boost::shared_ptr<Region> r = (*i)->region ();
2432 r->lower_to_bottom ();
2436 for (set<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
2437 vector<Command*> cmds;
2439 _session->add_commands (cmds);
2442 commit_reversible_command ();
2446 Editor::raise_region ()
2448 do_layer_operation (Raise);
2452 Editor::raise_region_to_top ()
2454 do_layer_operation (RaiseToTop);
2458 Editor::lower_region ()
2460 do_layer_operation (Lower);
2464 Editor::lower_region_to_bottom ()
2466 do_layer_operation (LowerToBottom);
2469 /** Show the region editor for the selected regions */
2471 Editor::show_region_properties ()
2473 selection->foreach_regionview (&RegionView::show_region_editor);
2476 /** Show the midi list editor for the selected MIDI regions */
2478 Editor::show_midi_list_editor ()
2480 selection->foreach_midi_regionview (&MidiRegionView::show_list_editor);
2484 Editor::rename_region ()
2486 RegionSelection rs = get_regions_from_selection_and_entered ();
2492 ArdourDialog d (*this, _("Rename Region"), true, false);
2494 Label label (_("New name:"));
2497 hbox.set_spacing (6);
2498 hbox.pack_start (label, false, false);
2499 hbox.pack_start (entry, true, true);
2501 d.get_vbox()->set_border_width (12);
2502 d.get_vbox()->pack_start (hbox, false, false);
2504 d.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
2505 d.add_button(Gtk::Stock::OK, Gtk::RESPONSE_OK);
2507 d.set_size_request (300, -1);
2509 entry.set_text (rs.front()->region()->name());
2510 entry.select_region (0, -1);
2512 entry.signal_activate().connect (sigc::bind (sigc::mem_fun (d, &Dialog::response), RESPONSE_OK));
2518 int const ret = d.run();
2522 if (ret != RESPONSE_OK) {
2526 std::string str = entry.get_text();
2527 strip_whitespace_edges (str);
2529 rs.front()->region()->set_name (str);
2530 _regions->redisplay ();
2535 Editor::audition_playlist_region_via_route (boost::shared_ptr<Region> region, Route& route)
2537 if (_session->is_auditioning()) {
2538 _session->cancel_audition ();
2541 // note: some potential for creativity here, because region doesn't
2542 // have to belong to the playlist that Route is handling
2544 // bool was_soloed = route.soloed();
2546 route.set_solo (true, this);
2548 _session->request_bounded_roll (region->position(), region->position() + region->length());
2550 /* XXX how to unset the solo state ? */
2553 /** Start an audition of the first selected region */
2555 Editor::play_edit_range ()
2557 framepos_t start, end;
2559 if (get_edit_op_range (start, end)) {
2560 _session->request_bounded_roll (start, end);
2565 Editor::play_selected_region ()
2567 framepos_t start = max_framepos;
2570 RegionSelection rs = get_regions_from_selection_and_entered ();
2576 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
2577 if ((*i)->region()->position() < start) {
2578 start = (*i)->region()->position();
2580 if ((*i)->region()->last_frame() + 1 > end) {
2581 end = (*i)->region()->last_frame() + 1;
2585 _session->request_bounded_roll (start, end);
2589 Editor::audition_playlist_region_standalone (boost::shared_ptr<Region> region)
2591 _session->audition_region (region);
2595 Editor::region_from_selection ()
2597 if (clicked_axisview == 0) {
2601 if (selection->time.empty()) {
2605 framepos_t start = selection->time[clicked_selection].start;
2606 framepos_t end = selection->time[clicked_selection].end;
2608 TrackViewList tracks = get_tracks_for_range_action ();
2610 framepos_t selection_cnt = end - start + 1;
2612 for (TrackSelection::iterator i = tracks.begin(); i != tracks.end(); ++i) {
2613 boost::shared_ptr<Region> current;
2614 boost::shared_ptr<Playlist> pl;
2615 framepos_t internal_start;
2618 if ((pl = (*i)->playlist()) == 0) {
2622 if ((current = pl->top_region_at (start)) == 0) {
2626 internal_start = start - current->position();
2627 RegionFactory::region_name (new_name, current->name(), true);
2631 plist.add (ARDOUR::Properties::start, current->start() + internal_start);
2632 plist.add (ARDOUR::Properties::length, selection_cnt);
2633 plist.add (ARDOUR::Properties::name, new_name);
2634 plist.add (ARDOUR::Properties::layer, 0);
2636 boost::shared_ptr<Region> region (RegionFactory::create (current, plist));
2641 Editor::create_region_from_selection (vector<boost::shared_ptr<Region> >& new_regions)
2643 if (selection->time.empty() || selection->tracks.empty()) {
2647 framepos_t start = selection->time[clicked_selection].start;
2648 framepos_t end = selection->time[clicked_selection].end;
2650 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
2651 sort_track_selection (ts);
2653 for (TrackSelection::iterator i = ts.begin(); i != ts.end(); ++i) {
2654 boost::shared_ptr<Region> current;
2655 boost::shared_ptr<Playlist> playlist;
2656 framepos_t internal_start;
2659 if ((playlist = (*i)->playlist()) == 0) {
2663 if ((current = playlist->top_region_at(start)) == 0) {
2667 internal_start = start - current->position();
2668 RegionFactory::region_name (new_name, current->name(), true);
2672 plist.add (ARDOUR::Properties::start, current->start() + internal_start);
2673 plist.add (ARDOUR::Properties::length, end - start + 1);
2674 plist.add (ARDOUR::Properties::name, new_name);
2676 new_regions.push_back (RegionFactory::create (current, plist));
2681 Editor::split_multichannel_region ()
2683 RegionSelection rs = get_regions_from_selection_and_entered ();
2689 vector< boost::shared_ptr<Region> > v;
2691 for (list<RegionView*>::iterator x = rs.begin(); x != rs.end(); ++x) {
2692 (*x)->region()->separate_by_channel (*_session, v);
2697 Editor::new_region_from_selection ()
2699 region_from_selection ();
2700 cancel_selection ();
2704 add_if_covered (RegionView* rv, const AudioRange* ar, RegionSelection* rs)
2706 switch (rv->region()->coverage (ar->start, ar->end - 1)) {
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->points.empty()) {
3851 begin_reversible_command (opname + _(" points"));
3853 cut_copy_points (op);
3854 if (op == Cut || op == Delete) {
3855 selection->clear_points ();
3857 } else if (!selection->regions.empty() || !selection->points.empty()) {
3861 if (selection->regions.empty()) {
3862 thing_name = _("points");
3863 } else if (selection->points.empty()) {
3864 thing_name = _("regions");
3866 thing_name = _("objects");
3869 begin_reversible_command (opname + ' ' + thing_name);
3872 if (!selection->regions.empty()) {
3873 cut_copy_regions (op, selection->regions);
3875 if (op == Cut || op == Delete) {
3876 selection->clear_regions ();
3880 if (!selection->points.empty()) {
3881 cut_copy_points (op);
3883 if (op == Cut || op == Delete) {
3884 selection->clear_points ();
3887 } else if (selection->time.empty()) {
3888 framepos_t start, end;
3889 /* no time selection, see if we can get an edit range
3892 if (get_edit_op_range (start, end)) {
3893 selection->set (start, end);
3895 } else if (!selection->time.empty()) {
3896 begin_reversible_command (opname + _(" range"));
3899 cut_copy_ranges (op);
3901 if (op == Cut || op == Delete) {
3902 selection->clear_time ();
3907 commit_reversible_command ();
3910 if (op == Delete || op == Cut || op == Clear) {
3915 struct AutomationRecord {
3916 AutomationRecord () : state (0) {}
3917 AutomationRecord (XMLNode* s) : state (s) {}
3919 XMLNode* state; ///< state before any operation
3920 boost::shared_ptr<Evoral::ControlList> copy; ///< copied events for the cut buffer
3923 /** Cut, copy or clear selected automation points.
3924 * @param op Operation (Cut, Copy or Clear)
3927 Editor::cut_copy_points (CutCopyOp op)
3929 if (selection->points.empty ()) {
3933 /* XXX: not ideal, as there may be more than one track involved in the point selection */
3934 _last_cut_copy_source_track = &selection->points.front()->line().trackview;
3936 /* Keep a record of the AutomationLists that we end up using in this operation */
3937 typedef std::map<boost::shared_ptr<AutomationList>, AutomationRecord> Lists;
3940 /* Go through all selected points, making an AutomationRecord for each distinct AutomationList */
3941 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
3942 boost::shared_ptr<AutomationList> al = (*i)->line().the_list();
3943 if (lists.find (al) == lists.end ()) {
3944 /* We haven't seen this list yet, so make a record for it. This includes
3945 taking a copy of its current state, in case this is needed for undo later.
3947 lists[al] = AutomationRecord (&al->get_state ());
3951 if (op == Cut || op == Copy) {
3952 /* This operation will involve putting things in the cut buffer, so create an empty
3953 ControlList for each of our source lists to put the cut buffer data in.
3955 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
3956 i->second.copy = i->first->create (i->first->parameter ());
3959 /* Add all selected points to the relevant copy ControlLists */
3960 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
3961 boost::shared_ptr<AutomationList> al = (*i)->line().the_list();
3962 AutomationList::const_iterator j = (*i)->model ();
3963 lists[al].copy->add ((*j)->when, (*j)->value);
3966 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
3967 /* Correct this copy list so that it starts at time 0 */
3968 double const start = i->second.copy->front()->when;
3969 for (AutomationList::iterator j = i->second.copy->begin(); j != i->second.copy->end(); ++j) {
3970 (*j)->when -= start;
3973 /* And add it to the cut buffer */
3974 cut_buffer->add (i->second.copy);
3978 if (op == Delete || op == Cut) {
3979 /* This operation needs to remove things from the main AutomationList, so do that now */
3981 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
3982 i->first->freeze ();
3985 /* Remove each selected point from its AutomationList */
3986 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
3987 boost::shared_ptr<AutomationList> al = (*i)->line().the_list();
3988 al->erase ((*i)->model ());
3991 /* Thaw the lists and add undo records for them */
3992 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
3993 boost::shared_ptr<AutomationList> al = i->first;
3995 _session->add_command (new MementoCommand<AutomationList> (*al.get(), i->second.state, &(al->get_state ())));
4000 /** Cut, copy or clear selected automation points.
4001 * @param op Operation (Cut, Copy or Clear)
4004 Editor::cut_copy_midi (CutCopyOp op)
4006 for (MidiRegionSelection::iterator i = selection->midi_regions.begin(); i != selection->midi_regions.end(); ++i) {
4007 MidiRegionView* mrv = *i;
4008 mrv->cut_copy_clear (op);
4014 struct lt_playlist {
4015 bool operator () (const PlaylistState& a, const PlaylistState& b) {
4016 return a.playlist < b.playlist;
4020 struct PlaylistMapping {
4022 boost::shared_ptr<Playlist> pl;
4024 PlaylistMapping (TimeAxisView* tvp) : tv (tvp) {}
4027 /** Remove `clicked_regionview' */
4029 Editor::remove_clicked_region ()
4031 if (clicked_routeview == 0 || clicked_regionview == 0) {
4035 boost::shared_ptr<Playlist> playlist = clicked_routeview->playlist();
4037 playlist->clear_changes ();
4038 playlist->clear_owned_changes ();
4039 playlist->remove_region (clicked_regionview->region());
4040 if (Config->get_edit_mode() == Ripple)
4041 playlist->ripple (clicked_regionview->region()->position(), -clicked_regionview->region()->length(), boost::shared_ptr<Region>());
4043 /* We might have removed regions, which alters other regions' layering_index,
4044 so we need to do a recursive diff here.
4046 vector<Command*> cmds;
4047 playlist->rdiff (cmds);
4048 _session->add_commands (cmds);
4050 _session->add_command(new StatefulDiffCommand (playlist));
4051 commit_reversible_command ();
4055 /** Remove the selected regions */
4057 Editor::remove_selected_regions ()
4059 RegionSelection rs = get_regions_from_selection_and_entered ();
4061 if (!_session || rs.empty()) {
4065 begin_reversible_command (_("remove region"));
4067 list<boost::shared_ptr<Region> > regions_to_remove;
4069 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
4070 // we can't just remove the region(s) in this loop because
4071 // this removes them from the RegionSelection, and they thus
4072 // disappear from underneath the iterator, and the ++i above
4073 // SEGVs in a puzzling fashion.
4075 // so, first iterate over the regions to be removed from rs and
4076 // add them to the regions_to_remove list, and then
4077 // iterate over the list to actually remove them.
4079 regions_to_remove.push_back ((*i)->region());
4082 vector<boost::shared_ptr<Playlist> > playlists;
4084 for (list<boost::shared_ptr<Region> >::iterator rl = regions_to_remove.begin(); rl != regions_to_remove.end(); ++rl) {
4086 boost::shared_ptr<Playlist> playlist = (*rl)->playlist();
4089 // is this check necessary?
4093 /* get_regions_from_selection_and_entered() guarantees that
4094 the playlists involved are unique, so there is no need
4098 playlists.push_back (playlist);
4100 playlist->clear_changes ();
4101 playlist->clear_owned_changes ();
4102 playlist->freeze ();
4103 playlist->remove_region (*rl);
4104 if (Config->get_edit_mode() == Ripple)
4105 playlist->ripple ((*rl)->position(), -(*rl)->length(), boost::shared_ptr<Region>());
4109 vector<boost::shared_ptr<Playlist> >::iterator pl;
4111 for (pl = playlists.begin(); pl != playlists.end(); ++pl) {
4114 /* We might have removed regions, which alters other regions' layering_index,
4115 so we need to do a recursive diff here.
4117 vector<Command*> cmds;
4118 (*pl)->rdiff (cmds);
4119 _session->add_commands (cmds);
4121 _session->add_command(new StatefulDiffCommand (*pl));
4124 commit_reversible_command ();
4127 /** Cut, copy or clear selected regions.
4128 * @param op Operation (Cut, Copy or Clear)
4131 Editor::cut_copy_regions (CutCopyOp op, RegionSelection& rs)
4133 /* we can't use a std::map here because the ordering is important, and we can't trivially sort
4134 a map when we want ordered access to both elements. i think.
4137 vector<PlaylistMapping> pmap;
4139 framepos_t first_position = max_framepos;
4141 typedef set<boost::shared_ptr<Playlist> > FreezeList;
4142 FreezeList freezelist;
4144 /* get ordering correct before we cut/copy */
4146 rs.sort_by_position_and_track ();
4148 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
4150 first_position = min ((framepos_t) (*x)->region()->position(), first_position);
4152 if (op == Cut || op == Clear || op == Delete) {
4153 boost::shared_ptr<Playlist> pl = (*x)->region()->playlist();
4156 FreezeList::iterator fl;
4158 // only take state if this is a new playlist.
4159 for (fl = freezelist.begin(); fl != freezelist.end(); ++fl) {
4165 if (fl == freezelist.end()) {
4166 pl->clear_changes();
4167 pl->clear_owned_changes ();
4169 freezelist.insert (pl);
4174 TimeAxisView* tv = &(*x)->get_time_axis_view();
4175 vector<PlaylistMapping>::iterator z;
4177 for (z = pmap.begin(); z != pmap.end(); ++z) {
4178 if ((*z).tv == tv) {
4183 if (z == pmap.end()) {
4184 pmap.push_back (PlaylistMapping (tv));
4188 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ) {
4190 boost::shared_ptr<Playlist> pl = (*x)->region()->playlist();
4193 /* region not yet associated with a playlist (e.g. unfinished
4200 TimeAxisView& tv = (*x)->get_time_axis_view();
4201 boost::shared_ptr<Playlist> npl;
4202 RegionSelection::iterator tmp;
4209 vector<PlaylistMapping>::iterator z;
4211 for (z = pmap.begin(); z != pmap.end(); ++z) {
4212 if ((*z).tv == &tv) {
4217 assert (z != pmap.end());
4220 npl = PlaylistFactory::create (pl->data_type(), *_session, "cutlist", true);
4228 boost::shared_ptr<Region> r = (*x)->region();
4229 boost::shared_ptr<Region> _xx;
4235 pl->remove_region (r);
4236 if (Config->get_edit_mode() == Ripple)
4237 pl->ripple (r->position(), -r->length(), boost::shared_ptr<Region>());
4241 _xx = RegionFactory::create (r);
4242 npl->add_region (_xx, r->position() - first_position);
4243 pl->remove_region (r);
4244 if (Config->get_edit_mode() == Ripple)
4245 pl->ripple (r->position(), -r->length(), boost::shared_ptr<Region>());
4249 /* copy region before adding, so we're not putting same object into two different playlists */
4250 npl->add_region (RegionFactory::create (r), r->position() - first_position);
4254 pl->remove_region (r);
4255 if (Config->get_edit_mode() == Ripple)
4256 pl->ripple (r->position(), -r->length(), boost::shared_ptr<Region>());
4265 list<boost::shared_ptr<Playlist> > foo;
4267 /* the pmap is in the same order as the tracks in which selected regions occured */
4269 for (vector<PlaylistMapping>::iterator i = pmap.begin(); i != pmap.end(); ++i) {
4272 foo.push_back ((*i).pl);
4277 cut_buffer->set (foo);
4281 _last_cut_copy_source_track = 0;
4283 _last_cut_copy_source_track = pmap.front().tv;
4287 for (FreezeList::iterator pl = freezelist.begin(); pl != freezelist.end(); ++pl) {
4290 /* We might have removed regions, which alters other regions' layering_index,
4291 so we need to do a recursive diff here.
4293 vector<Command*> cmds;
4294 (*pl)->rdiff (cmds);
4295 _session->add_commands (cmds);
4297 _session->add_command (new StatefulDiffCommand (*pl));
4302 Editor::cut_copy_ranges (CutCopyOp op)
4304 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4306 /* Sort the track selection now, so that it if is used, the playlists
4307 selected by the calls below to cut_copy_clear are in the order that
4308 their tracks appear in the editor. This makes things like paste
4309 of ranges work properly.
4312 sort_track_selection (ts);
4315 if (!entered_track) {
4318 ts.push_back (entered_track);
4321 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4322 (*i)->cut_copy_clear (*selection, op);
4327 Editor::paste (float times, bool from_context)
4329 DEBUG_TRACE (DEBUG::CutNPaste, "paste to preferred edit pos\n");
4331 paste_internal (get_preferred_edit_position (false, from_context), times);
4335 Editor::mouse_paste ()
4340 if (!mouse_frame (where, ignored)) {
4345 paste_internal (where, 1);
4349 Editor::paste_internal (framepos_t position, float times)
4351 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("apparent paste position is %1\n", position));
4353 if (internal_editing()) {
4354 if (cut_buffer->midi_notes.empty()) {
4358 if (cut_buffer->empty()) {
4363 if (position == max_framepos) {
4364 position = get_preferred_edit_position();
4365 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("preferred edit position is %1\n", position));
4369 TrackViewList::iterator i;
4372 /* get everything in the correct order */
4374 if (_edit_point == Editing::EditAtMouse && entered_track) {
4375 /* With the mouse edit point, paste onto the track under the mouse */
4376 ts.push_back (entered_track);
4377 } else if (!selection->tracks.empty()) {
4378 /* Otherwise, if there are some selected tracks, paste to them */
4379 ts = selection->tracks.filter_to_unique_playlists ();
4380 sort_track_selection (ts);
4381 } else if (_last_cut_copy_source_track) {
4382 /* Otherwise paste to the track that the cut/copy came from;
4383 see discussion in mantis #3333.
4385 ts.push_back (_last_cut_copy_source_track);
4388 if (internal_editing ()) {
4390 /* undo/redo is handled by individual tracks/regions */
4392 for (nth = 0, i = ts.begin(); i != ts.end(); ++i, ++nth) {
4395 RegionSelection::iterator r;
4396 MidiNoteSelection::iterator cb;
4398 get_regions_at (rs, position, ts);
4400 for (cb = cut_buffer->midi_notes.begin(), r = rs.begin();
4401 cb != cut_buffer->midi_notes.end() && r != rs.end(); ++r) {
4402 MidiRegionView* mrv = dynamic_cast<MidiRegionView*> (*r);
4404 mrv->paste (position, times, **cb);
4412 /* we do redo (do you do voodoo?) */
4414 begin_reversible_command (Operations::paste);
4416 for (nth = 0, i = ts.begin(); i != ts.end(); ++i, ++nth) {
4417 (*i)->paste (position, times, *cut_buffer, nth);
4420 commit_reversible_command ();
4425 Editor::duplicate_some_regions (RegionSelection& regions, float times)
4427 boost::shared_ptr<Playlist> playlist;
4428 RegionSelection sel = regions; // clear (below) may clear the argument list if its the current region selection
4429 RegionSelection foo;
4431 framepos_t const start_frame = regions.start ();
4432 framepos_t const end_frame = regions.end_frame ();
4434 begin_reversible_command (Operations::duplicate_region);
4436 selection->clear_regions ();
4438 for (RegionSelection::iterator i = sel.begin(); i != sel.end(); ++i) {
4440 boost::shared_ptr<Region> r ((*i)->region());
4442 TimeAxisView& tv = (*i)->get_time_axis_view();
4443 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (&tv);
4444 latest_regionviews.clear ();
4445 sigc::connection c = rtv->view()->RegionViewAdded.connect (sigc::mem_fun(*this, &Editor::collect_new_region_view));
4447 playlist = (*i)->region()->playlist();
4448 playlist->clear_changes ();
4449 playlist->duplicate (r, end_frame + (r->first_frame() - start_frame), times);
4450 _session->add_command(new StatefulDiffCommand (playlist));
4454 foo.insert (foo.end(), latest_regionviews.begin(), latest_regionviews.end());
4457 commit_reversible_command ();
4460 selection->set (foo);
4465 Editor::duplicate_selection (float times)
4467 if (selection->time.empty() || selection->tracks.empty()) {
4471 boost::shared_ptr<Playlist> playlist;
4472 vector<boost::shared_ptr<Region> > new_regions;
4473 vector<boost::shared_ptr<Region> >::iterator ri;
4475 create_region_from_selection (new_regions);
4477 if (new_regions.empty()) {
4481 begin_reversible_command (_("duplicate selection"));
4483 ri = new_regions.begin();
4485 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4487 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4488 if ((playlist = (*i)->playlist()) == 0) {
4491 playlist->clear_changes ();
4492 playlist->duplicate (*ri, selection->time[clicked_selection].end, times);
4493 _session->add_command (new StatefulDiffCommand (playlist));
4496 if (ri == new_regions.end()) {
4501 commit_reversible_command ();
4504 /** Reset all selected points to the relevant default value */
4506 Editor::reset_point_selection ()
4508 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
4509 ARDOUR::AutomationList::iterator j = (*i)->model ();
4510 (*j)->value = (*i)->line().the_list()->default_value ();
4515 Editor::center_playhead ()
4517 float const page = _visible_canvas_width * samples_per_pixel;
4518 center_screen_internal (playhead_cursor->current_frame (), page);
4522 Editor::center_edit_point ()
4524 float const page = _visible_canvas_width * samples_per_pixel;
4525 center_screen_internal (get_preferred_edit_position(), page);
4528 /** Caller must begin and commit a reversible command */
4530 Editor::clear_playlist (boost::shared_ptr<Playlist> playlist)
4532 playlist->clear_changes ();
4534 _session->add_command (new StatefulDiffCommand (playlist));
4538 Editor::nudge_track (bool use_edit, bool forwards)
4540 boost::shared_ptr<Playlist> playlist;
4541 framepos_t distance;
4542 framepos_t next_distance;
4546 start = get_preferred_edit_position();
4551 if ((distance = get_nudge_distance (start, next_distance)) == 0) {
4555 if (selection->tracks.empty()) {
4559 begin_reversible_command (_("nudge track"));
4561 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4563 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4565 if ((playlist = (*i)->playlist()) == 0) {
4569 playlist->clear_changes ();
4570 playlist->clear_owned_changes ();
4572 playlist->nudge_after (start, distance, forwards);
4574 vector<Command*> cmds;
4576 playlist->rdiff (cmds);
4577 _session->add_commands (cmds);
4579 _session->add_command (new StatefulDiffCommand (playlist));
4582 commit_reversible_command ();
4586 Editor::remove_last_capture ()
4588 vector<string> choices;
4595 if (Config->get_verify_remove_last_capture()) {
4596 prompt = _("Do you really want to destroy the last capture?"
4597 "\n(This is destructive and cannot be undone)");
4599 choices.push_back (_("No, do nothing."));
4600 choices.push_back (_("Yes, destroy it."));
4602 Gtkmm2ext::Choice prompter (_("Destroy last capture"), prompt, choices);
4604 if (prompter.run () == 1) {
4605 _session->remove_last_capture ();
4606 _regions->redisplay ();
4610 _session->remove_last_capture();
4611 _regions->redisplay ();
4616 Editor::normalize_region ()
4622 RegionSelection rs = get_regions_from_selection_and_entered ();
4628 NormalizeDialog dialog (rs.size() > 1);
4630 if (dialog.run () == RESPONSE_CANCEL) {
4634 set_canvas_cursor (_cursors->wait);
4637 /* XXX: should really only count audio regions here */
4638 int const regions = rs.size ();
4640 /* Make a list of the selected audio regions' maximum amplitudes, and also
4641 obtain the maximum amplitude of them all.
4643 list<double> max_amps;
4645 for (RegionSelection::const_iterator i = rs.begin(); i != rs.end(); ++i) {
4646 AudioRegionView const * arv = dynamic_cast<AudioRegionView const *> (*i);
4648 dialog.descend (1.0 / regions);
4649 double const a = arv->audio_region()->maximum_amplitude (&dialog);
4652 /* the user cancelled the operation */
4653 set_canvas_cursor (current_canvas_cursor);
4657 max_amps.push_back (a);
4658 max_amp = max (max_amp, a);
4663 begin_reversible_command (_("normalize"));
4665 list<double>::const_iterator a = max_amps.begin ();
4667 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
4668 AudioRegionView* const arv = dynamic_cast<AudioRegionView*> (*r);
4673 arv->region()->clear_changes ();
4675 double const amp = dialog.normalize_individually() ? *a : max_amp;
4677 arv->audio_region()->normalize (amp, dialog.target ());
4678 _session->add_command (new StatefulDiffCommand (arv->region()));
4683 commit_reversible_command ();
4684 set_canvas_cursor (current_canvas_cursor);
4689 Editor::reset_region_scale_amplitude ()
4695 RegionSelection rs = get_regions_from_selection_and_entered ();
4701 begin_reversible_command ("reset gain");
4703 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
4704 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
4707 arv->region()->clear_changes ();
4708 arv->audio_region()->set_scale_amplitude (1.0f);
4709 _session->add_command (new StatefulDiffCommand (arv->region()));
4712 commit_reversible_command ();
4716 Editor::adjust_region_gain (bool up)
4718 RegionSelection rs = get_regions_from_selection_and_entered ();
4720 if (!_session || rs.empty()) {
4724 begin_reversible_command ("adjust region gain");
4726 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
4727 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
4732 arv->region()->clear_changes ();
4734 double dB = accurate_coefficient_to_dB (arv->audio_region()->scale_amplitude ());
4742 arv->audio_region()->set_scale_amplitude (dB_to_coefficient (dB));
4743 _session->add_command (new StatefulDiffCommand (arv->region()));
4746 commit_reversible_command ();
4751 Editor::reverse_region ()
4757 Reverse rev (*_session);
4758 apply_filter (rev, _("reverse regions"));
4762 Editor::strip_region_silence ()
4768 RegionSelection rs = get_regions_from_selection_and_entered ();
4774 std::list<RegionView*> audio_only;
4776 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
4777 AudioRegionView* const arv = dynamic_cast<AudioRegionView*> (*i);
4779 audio_only.push_back (arv);
4783 StripSilenceDialog d (_session, audio_only);
4784 int const r = d.run ();
4788 if (r == Gtk::RESPONSE_OK) {
4789 ARDOUR::AudioIntervalMap silences;
4790 d.silences (silences);
4791 StripSilence s (*_session, silences, d.fade_length());
4792 apply_filter (s, _("strip silence"), &d);
4797 Editor::apply_midi_note_edit_op_to_region (MidiOperator& op, MidiRegionView& mrv)
4799 Evoral::Sequence<Evoral::MusicalTime>::Notes selected;
4800 mrv.selection_as_notelist (selected, true);
4802 vector<Evoral::Sequence<Evoral::MusicalTime>::Notes> v;
4803 v.push_back (selected);
4805 framepos_t pos_frames = mrv.midi_region()->position() - mrv.midi_region()->start();
4806 double pos_beats = _session->tempo_map().framewalk_to_beats(0, pos_frames);
4808 return op (mrv.midi_region()->model(), pos_beats, v);
4812 Editor::apply_midi_note_edit_op (MidiOperator& op)
4816 RegionSelection rs = get_regions_from_selection_and_entered ();
4822 begin_reversible_command (op.name ());
4824 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
4825 RegionSelection::iterator tmp = r;
4828 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*r);
4831 cmd = apply_midi_note_edit_op_to_region (op, *mrv);
4834 _session->add_command (cmd);
4841 commit_reversible_command ();
4845 Editor::fork_region ()
4847 RegionSelection rs = get_regions_from_selection_and_entered ();
4853 begin_reversible_command (_("Fork Region(s)"));
4855 set_canvas_cursor (_cursors->wait);
4858 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
4859 RegionSelection::iterator tmp = r;
4862 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*>(*r);
4866 boost::shared_ptr<Playlist> playlist = mrv->region()->playlist();
4867 boost::shared_ptr<MidiSource> new_source = _session->create_midi_source_by_stealing_name (mrv->midi_view()->track());
4868 boost::shared_ptr<MidiRegion> newregion = mrv->midi_region()->clone (new_source);
4870 playlist->clear_changes ();
4871 playlist->replace_region (mrv->region(), newregion, mrv->region()->position());
4872 _session->add_command(new StatefulDiffCommand (playlist));
4874 error << string_compose (_("Could not unlink %1"), mrv->region()->name()) << endmsg;
4881 commit_reversible_command ();
4883 set_canvas_cursor (current_canvas_cursor);
4887 Editor::quantize_region ()
4889 int selected_midi_region_cnt = 0;
4895 RegionSelection rs = get_regions_from_selection_and_entered ();
4901 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
4902 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*r);
4904 selected_midi_region_cnt++;
4908 if (selected_midi_region_cnt == 0) {
4912 QuantizeDialog* qd = new QuantizeDialog (*this);
4915 const int r = qd->run ();
4918 if (r == Gtk::RESPONSE_OK) {
4919 Quantize quant (*_session, qd->snap_start(), qd->snap_end(),
4920 qd->start_grid_size(), qd->end_grid_size(),
4921 qd->strength(), qd->swing(), qd->threshold());
4923 apply_midi_note_edit_op (quant);
4928 Editor::insert_patch_change (bool from_context)
4930 RegionSelection rs = get_regions_from_selection_and_entered ();
4936 const framepos_t p = get_preferred_edit_position (false, from_context);
4938 /* XXX: bit of a hack; use the MIDNAM from the first selected region;
4939 there may be more than one, but the PatchChangeDialog can only offer
4940 one set of patch menus.
4942 MidiRegionView* first = dynamic_cast<MidiRegionView*> (rs.front ());
4944 Evoral::PatchChange<Evoral::MusicalTime> empty (0, 0, 0, 0);
4945 PatchChangeDialog d (0, _session, empty, first->instrument_info(), Gtk::Stock::ADD);
4947 if (d.run() == RESPONSE_CANCEL) {
4951 for (RegionSelection::iterator i = rs.begin (); i != rs.end(); ++i) {
4952 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*i);
4954 if (p >= mrv->region()->first_frame() && p <= mrv->region()->last_frame()) {
4955 mrv->add_patch_change (p - mrv->region()->position(), d.patch ());
4962 Editor::apply_filter (Filter& filter, string command, ProgressReporter* progress)
4964 RegionSelection rs = get_regions_from_selection_and_entered ();
4970 begin_reversible_command (command);
4972 set_canvas_cursor (_cursors->wait);
4976 int const N = rs.size ();
4978 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
4979 RegionSelection::iterator tmp = r;
4982 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
4984 boost::shared_ptr<Playlist> playlist = arv->region()->playlist();
4987 progress->descend (1.0 / N);
4990 if (arv->audio_region()->apply (filter, progress) == 0) {
4992 playlist->clear_changes ();
4993 playlist->clear_owned_changes ();
4995 if (filter.results.empty ()) {
4997 /* no regions returned; remove the old one */
4998 playlist->remove_region (arv->region ());
5002 std::vector<boost::shared_ptr<Region> >::iterator res = filter.results.begin ();
5004 /* first region replaces the old one */
5005 playlist->replace_region (arv->region(), *res, (*res)->position());
5009 while (res != filter.results.end()) {
5010 playlist->add_region (*res, (*res)->position());
5016 /* We might have removed regions, which alters other regions' layering_index,
5017 so we need to do a recursive diff here.
5019 vector<Command*> cmds;
5020 playlist->rdiff (cmds);
5021 _session->add_commands (cmds);
5023 _session->add_command(new StatefulDiffCommand (playlist));
5029 progress->ascend ();
5037 commit_reversible_command ();
5040 set_canvas_cursor (current_canvas_cursor);
5044 Editor::external_edit_region ()
5050 Editor::reset_region_gain_envelopes ()
5052 RegionSelection rs = get_regions_from_selection_and_entered ();
5054 if (!_session || rs.empty()) {
5058 _session->begin_reversible_command (_("reset region gain"));
5060 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5061 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
5063 boost::shared_ptr<AutomationList> alist (arv->audio_region()->envelope());
5064 XMLNode& before (alist->get_state());
5066 arv->audio_region()->set_default_envelope ();
5067 _session->add_command (new MementoCommand<AutomationList>(*arv->audio_region()->envelope().get(), &before, &alist->get_state()));
5071 _session->commit_reversible_command ();
5075 Editor::set_region_gain_visibility (RegionView* rv)
5077 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (rv);
5079 arv->update_envelope_visibility();
5084 Editor::set_gain_envelope_visibility ()
5090 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5091 AudioTimeAxisView* v = dynamic_cast<AudioTimeAxisView*>(*i);
5093 v->audio_view()->foreach_regionview (sigc::mem_fun (this, &Editor::set_region_gain_visibility));
5099 Editor::toggle_gain_envelope_active ()
5101 if (_ignore_region_action) {
5105 RegionSelection rs = get_regions_from_selection_and_entered ();
5107 if (!_session || rs.empty()) {
5111 _session->begin_reversible_command (_("region gain envelope active"));
5113 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5114 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
5116 arv->region()->clear_changes ();
5117 arv->audio_region()->set_envelope_active (!arv->audio_region()->envelope_active());
5118 _session->add_command (new StatefulDiffCommand (arv->region()));
5122 _session->commit_reversible_command ();
5126 Editor::toggle_region_lock ()
5128 if (_ignore_region_action) {
5132 RegionSelection rs = get_regions_from_selection_and_entered ();
5134 if (!_session || rs.empty()) {
5138 _session->begin_reversible_command (_("toggle region lock"));
5140 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5141 (*i)->region()->clear_changes ();
5142 (*i)->region()->set_locked (!(*i)->region()->locked());
5143 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5146 _session->commit_reversible_command ();
5150 Editor::toggle_region_video_lock ()
5152 if (_ignore_region_action) {
5156 RegionSelection rs = get_regions_from_selection_and_entered ();
5158 if (!_session || rs.empty()) {
5162 _session->begin_reversible_command (_("Toggle Video Lock"));
5164 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5165 (*i)->region()->clear_changes ();
5166 (*i)->region()->set_video_locked (!(*i)->region()->video_locked());
5167 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5170 _session->commit_reversible_command ();
5174 Editor::toggle_region_lock_style ()
5176 if (_ignore_region_action) {
5180 RegionSelection rs = get_regions_from_selection_and_entered ();
5182 if (!_session || rs.empty()) {
5186 _session->begin_reversible_command (_("region lock style"));
5188 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5189 (*i)->region()->clear_changes ();
5190 PositionLockStyle const ns = (*i)->region()->position_lock_style() == AudioTime ? MusicTime : AudioTime;
5191 (*i)->region()->set_position_lock_style (ns);
5192 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5195 _session->commit_reversible_command ();
5199 Editor::toggle_opaque_region ()
5201 if (_ignore_region_action) {
5205 RegionSelection rs = get_regions_from_selection_and_entered ();
5207 if (!_session || rs.empty()) {
5211 _session->begin_reversible_command (_("change region opacity"));
5213 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5214 (*i)->region()->clear_changes ();
5215 (*i)->region()->set_opaque (!(*i)->region()->opaque());
5216 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5219 _session->commit_reversible_command ();
5223 Editor::toggle_record_enable ()
5225 bool new_state = false;
5227 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5228 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5231 if (!rtav->is_track())
5235 new_state = !rtav->track()->record_enabled();
5239 rtav->track()->set_record_enabled (new_state, this);
5244 Editor::toggle_solo ()
5246 bool new_state = false;
5248 boost::shared_ptr<RouteList> rl (new RouteList);
5250 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5251 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5258 new_state = !rtav->route()->soloed ();
5262 rl->push_back (rtav->route());
5265 _session->set_solo (rl, new_state, Session::rt_cleanup, true);
5269 Editor::toggle_mute ()
5271 bool new_state = false;
5273 boost::shared_ptr<RouteList> rl (new RouteList);
5275 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5276 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5283 new_state = !rtav->route()->muted();
5287 rl->push_back (rtav->route());
5290 _session->set_mute (rl, new_state, Session::rt_cleanup, true);
5294 Editor::toggle_solo_isolate ()
5300 Editor::fade_range ()
5302 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
5304 begin_reversible_command (_("fade range"));
5306 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
5307 (*i)->fade_range (selection->time);
5310 commit_reversible_command ();
5315 Editor::set_fade_length (bool in)
5317 RegionSelection rs = get_regions_from_selection_and_entered ();
5323 /* we need a region to measure the offset from the start */
5325 RegionView* rv = rs.front ();
5327 framepos_t pos = get_preferred_edit_position();
5331 if (pos > rv->region()->last_frame() || pos < rv->region()->first_frame()) {
5332 /* edit point is outside the relevant region */
5337 if (pos <= rv->region()->position()) {
5341 len = pos - rv->region()->position();
5342 cmd = _("set fade in length");
5344 if (pos >= rv->region()->last_frame()) {
5348 len = rv->region()->last_frame() - pos;
5349 cmd = _("set fade out length");
5352 begin_reversible_command (cmd);
5354 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5355 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5361 boost::shared_ptr<AutomationList> alist;
5363 alist = tmp->audio_region()->fade_in();
5365 alist = tmp->audio_region()->fade_out();
5368 XMLNode &before = alist->get_state();
5371 tmp->audio_region()->set_fade_in_length (len);
5372 tmp->audio_region()->set_fade_in_active (true);
5374 tmp->audio_region()->set_fade_out_length (len);
5375 tmp->audio_region()->set_fade_out_active (true);
5378 XMLNode &after = alist->get_state();
5379 _session->add_command(new MementoCommand<AutomationList>(*alist, &before, &after));
5382 commit_reversible_command ();
5386 Editor::set_fade_in_shape (FadeShape shape)
5388 RegionSelection rs = get_regions_from_selection_and_entered ();
5394 begin_reversible_command (_("set fade in shape"));
5396 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5397 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5403 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_in();
5404 XMLNode &before = alist->get_state();
5406 tmp->audio_region()->set_fade_in_shape (shape);
5408 XMLNode &after = alist->get_state();
5409 _session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
5412 commit_reversible_command ();
5417 Editor::set_fade_out_shape (FadeShape shape)
5419 RegionSelection rs = get_regions_from_selection_and_entered ();
5425 begin_reversible_command (_("set fade out shape"));
5427 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5428 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5434 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_out();
5435 XMLNode &before = alist->get_state();
5437 tmp->audio_region()->set_fade_out_shape (shape);
5439 XMLNode &after = alist->get_state();
5440 _session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
5443 commit_reversible_command ();
5447 Editor::set_fade_in_active (bool yn)
5449 RegionSelection rs = get_regions_from_selection_and_entered ();
5455 begin_reversible_command (_("set fade in active"));
5457 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5458 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5465 boost::shared_ptr<AudioRegion> ar (tmp->audio_region());
5467 ar->clear_changes ();
5468 ar->set_fade_in_active (yn);
5469 _session->add_command (new StatefulDiffCommand (ar));
5472 commit_reversible_command ();
5476 Editor::set_fade_out_active (bool yn)
5478 RegionSelection rs = get_regions_from_selection_and_entered ();
5484 begin_reversible_command (_("set fade out active"));
5486 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5487 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5493 boost::shared_ptr<AudioRegion> ar (tmp->audio_region());
5495 ar->clear_changes ();
5496 ar->set_fade_out_active (yn);
5497 _session->add_command(new StatefulDiffCommand (ar));
5500 commit_reversible_command ();
5504 Editor::toggle_region_fades (int dir)
5506 if (_ignore_region_action) {
5510 boost::shared_ptr<AudioRegion> ar;
5513 RegionSelection rs = get_regions_from_selection_and_entered ();
5519 RegionSelection::iterator i;
5520 for (i = rs.begin(); i != rs.end(); ++i) {
5521 if ((ar = boost::dynamic_pointer_cast<AudioRegion>((*i)->region())) != 0) {
5523 yn = ar->fade_out_active ();
5525 yn = ar->fade_in_active ();
5531 if (i == rs.end()) {
5535 /* XXX should this undo-able? */
5537 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5538 if ((ar = boost::dynamic_pointer_cast<AudioRegion>((*i)->region())) == 0) {
5541 if (dir == 1 || dir == 0) {
5542 ar->set_fade_in_active (!yn);
5545 if (dir == -1 || dir == 0) {
5546 ar->set_fade_out_active (!yn);
5552 /** Update region fade visibility after its configuration has been changed */
5554 Editor::update_region_fade_visibility ()
5556 bool _fade_visibility = _session->config.get_show_region_fades ();
5558 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5559 AudioTimeAxisView* v = dynamic_cast<AudioTimeAxisView*>(*i);
5561 if (_fade_visibility) {
5562 v->audio_view()->show_all_fades ();
5564 v->audio_view()->hide_all_fades ();
5571 Editor::set_edit_point ()
5576 if (!mouse_frame (where, ignored)) {
5582 if (selection->markers.empty()) {
5584 mouse_add_new_marker (where);
5589 Location* loc = find_location_from_marker (selection->markers.front(), ignored);
5592 loc->move_to (where);
5598 Editor::set_playhead_cursor ()
5600 if (entered_marker) {
5601 _session->request_locate (entered_marker->position(), _session->transport_rolling());
5606 if (!mouse_frame (where, ignored)) {
5613 _session->request_locate (where, _session->transport_rolling());
5617 if ( Config->get_follow_edits() )
5618 cancel_time_selection();
5622 Editor::split_region ()
5624 if ( !selection->time.empty()) {
5625 separate_regions_between (selection->time);
5629 RegionSelection rs = get_regions_from_selection_and_edit_point ();
5631 framepos_t where = get_preferred_edit_position ();
5637 split_regions_at (where, rs);
5640 struct EditorOrderRouteSorter {
5641 bool operator() (boost::shared_ptr<Route> a, boost::shared_ptr<Route> b) {
5642 return a->order_key () < b->order_key ();
5647 Editor::select_next_route()
5649 if (selection->tracks.empty()) {
5650 selection->set (track_views.front());
5654 TimeAxisView* current = selection->tracks.front();
5658 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5659 if (*i == current) {
5661 if (i != track_views.end()) {
5664 current = (*(track_views.begin()));
5665 //selection->set (*(track_views.begin()));
5670 rui = dynamic_cast<RouteUI *>(current);
5671 } while ( current->hidden() || (rui != NULL && !rui->route()->active()));
5673 selection->set(current);
5675 ensure_time_axis_view_is_visible (*current, false);
5679 Editor::select_prev_route()
5681 if (selection->tracks.empty()) {
5682 selection->set (track_views.front());
5686 TimeAxisView* current = selection->tracks.front();
5690 for (TrackViewList::reverse_iterator i = track_views.rbegin(); i != track_views.rend(); ++i) {
5691 if (*i == current) {
5693 if (i != track_views.rend()) {
5696 current = *(track_views.rbegin());
5701 rui = dynamic_cast<RouteUI *>(current);
5702 } while ( current->hidden() || (rui != NULL && !rui->route()->active()));
5704 selection->set (current);
5706 ensure_time_axis_view_is_visible (*current, false);
5710 Editor::set_loop_from_selection (bool play)
5712 if (_session == 0 || selection->time.empty()) {
5716 framepos_t start = selection->time[clicked_selection].start;
5717 framepos_t end = selection->time[clicked_selection].end;
5719 set_loop_range (start, end, _("set loop range from selection"));
5722 _session->request_locate (start, true);
5723 _session->request_play_loop (true);
5728 Editor::set_loop_from_edit_range (bool play)
5730 if (_session == 0) {
5737 if (!get_edit_op_range (start, end)) {
5741 set_loop_range (start, end, _("set loop range from edit range"));
5744 _session->request_locate (start, true);
5745 _session->request_play_loop (true);
5750 Editor::set_loop_from_region (bool play)
5752 framepos_t start = max_framepos;
5755 RegionSelection rs = get_regions_from_selection_and_entered ();
5761 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5762 if ((*i)->region()->position() < start) {
5763 start = (*i)->region()->position();
5765 if ((*i)->region()->last_frame() + 1 > end) {
5766 end = (*i)->region()->last_frame() + 1;
5770 set_loop_range (start, end, _("set loop range from region"));
5773 _session->request_locate (start, true);
5774 _session->request_play_loop (true);
5779 Editor::set_punch_from_selection ()
5781 if (_session == 0 || selection->time.empty()) {
5785 framepos_t start = selection->time[clicked_selection].start;
5786 framepos_t end = selection->time[clicked_selection].end;
5788 set_punch_range (start, end, _("set punch range from selection"));
5792 Editor::set_punch_from_edit_range ()
5794 if (_session == 0) {
5801 if (!get_edit_op_range (start, end)) {
5805 set_punch_range (start, end, _("set punch range from edit range"));
5809 Editor::set_punch_from_region ()
5811 framepos_t start = max_framepos;
5814 RegionSelection rs = get_regions_from_selection_and_entered ();
5820 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5821 if ((*i)->region()->position() < start) {
5822 start = (*i)->region()->position();
5824 if ((*i)->region()->last_frame() + 1 > end) {
5825 end = (*i)->region()->last_frame() + 1;
5829 set_punch_range (start, end, _("set punch range from region"));
5833 Editor::pitch_shift_region ()
5835 RegionSelection rs = get_regions_from_selection_and_entered ();
5837 RegionSelection audio_rs;
5838 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5839 if (dynamic_cast<AudioRegionView*> (*i)) {
5840 audio_rs.push_back (*i);
5844 if (audio_rs.empty()) {
5848 pitch_shift (audio_rs, 1.2);
5852 Editor::transpose_region ()
5854 RegionSelection rs = get_regions_from_selection_and_entered ();
5856 list<MidiRegionView*> midi_region_views;
5857 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5858 MidiRegionView* mrv = dynamic_cast<MidiRegionView*> (*i);
5860 midi_region_views.push_back (mrv);
5865 int const r = d.run ();
5866 if (r != RESPONSE_ACCEPT) {
5870 for (list<MidiRegionView*>::iterator i = midi_region_views.begin(); i != midi_region_views.end(); ++i) {
5871 (*i)->midi_region()->transpose (d.semitones ());
5876 Editor::set_tempo_from_region ()
5878 RegionSelection rs = get_regions_from_selection_and_entered ();
5880 if (!_session || rs.empty()) {
5884 RegionView* rv = rs.front();
5886 define_one_bar (rv->region()->position(), rv->region()->last_frame() + 1);
5890 Editor::use_range_as_bar ()
5892 framepos_t start, end;
5893 if (get_edit_op_range (start, end)) {
5894 define_one_bar (start, end);
5899 Editor::define_one_bar (framepos_t start, framepos_t end)
5901 framepos_t length = end - start;
5903 const Meter& m (_session->tempo_map().meter_at (start));
5905 /* length = 1 bar */
5907 /* now we want frames per beat.
5908 we have frames per bar, and beats per bar, so ...
5911 /* XXXX METER MATH */
5913 double frames_per_beat = length / m.divisions_per_bar();
5915 /* beats per minute = */
5917 double beats_per_minute = (_session->frame_rate() * 60.0) / frames_per_beat;
5919 /* now decide whether to:
5921 (a) set global tempo
5922 (b) add a new tempo marker
5926 const TempoSection& t (_session->tempo_map().tempo_section_at (start));
5928 bool do_global = false;
5930 if ((_session->tempo_map().n_tempos() == 1) && (_session->tempo_map().n_meters() == 1)) {
5932 /* only 1 tempo & 1 meter: ask if the user wants to set the tempo
5933 at the start, or create a new marker
5936 vector<string> options;
5937 options.push_back (_("Cancel"));
5938 options.push_back (_("Add new marker"));
5939 options.push_back (_("Set global tempo"));
5942 _("Define one bar"),
5943 _("Do you want to set the global tempo or add a new tempo marker?"),
5947 c.set_default_response (2);
5963 /* more than 1 tempo and/or meter section already, go ahead do the "usual":
5964 if the marker is at the region starter, change it, otherwise add
5969 begin_reversible_command (_("set tempo from region"));
5970 XMLNode& before (_session->tempo_map().get_state());
5973 _session->tempo_map().change_initial_tempo (beats_per_minute, t.note_type());
5974 } else if (t.frame() == start) {
5975 _session->tempo_map().change_existing_tempo_at (start, beats_per_minute, t.note_type());
5977 Timecode::BBT_Time bbt;
5978 _session->tempo_map().bbt_time (start, bbt);
5979 _session->tempo_map().add_tempo (Tempo (beats_per_minute, t.note_type()), bbt);
5982 XMLNode& after (_session->tempo_map().get_state());
5984 _session->add_command (new MementoCommand<TempoMap>(_session->tempo_map(), &before, &after));
5985 commit_reversible_command ();
5989 Editor::split_region_at_transients ()
5991 AnalysisFeatureList positions;
5993 RegionSelection rs = get_regions_from_selection_and_entered ();
5995 if (!_session || rs.empty()) {
5999 _session->begin_reversible_command (_("split regions"));
6001 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ) {
6003 RegionSelection::iterator tmp;
6008 boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion> ((*i)->region());
6010 if (ar && (ar->get_transients (positions) == 0)) {
6011 split_region_at_points ((*i)->region(), positions, true);
6018 _session->commit_reversible_command ();
6023 Editor::split_region_at_points (boost::shared_ptr<Region> r, AnalysisFeatureList& positions, bool can_ferret, bool select_new)
6025 bool use_rhythmic_rodent = false;
6027 boost::shared_ptr<Playlist> pl = r->playlist();
6029 list<boost::shared_ptr<Region> > new_regions;
6035 if (positions.empty()) {
6040 if (positions.size() > 20 && can_ferret) {
6041 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);
6042 MessageDialog msg (msgstr,
6045 Gtk::BUTTONS_OK_CANCEL);
6048 msg.add_button (_("Call for the Ferret!"), RESPONSE_APPLY);
6049 msg.set_secondary_text (_("Press OK to continue with this split operation\nor ask the Ferret dialog to tune the analysis"));
6051 msg.set_secondary_text (_("Press OK to continue with this split operation"));
6054 msg.set_title (_("Excessive split?"));
6057 int response = msg.run();
6063 case RESPONSE_APPLY:
6064 use_rhythmic_rodent = true;
6071 if (use_rhythmic_rodent) {
6072 show_rhythm_ferret ();
6076 AnalysisFeatureList::const_iterator x;
6078 pl->clear_changes ();
6079 pl->clear_owned_changes ();
6081 x = positions.begin();
6083 if (x == positions.end()) {
6088 pl->remove_region (r);
6092 while (x != positions.end()) {
6094 /* deal with positons that are out of scope of present region bounds */
6095 if (*x <= 0 || *x > r->length()) {
6100 /* file start = original start + how far we from the initial position ?
6103 framepos_t file_start = r->start() + pos;
6105 /* length = next position - current position
6108 framepos_t len = (*x) - pos;
6110 /* XXX we do we really want to allow even single-sample regions?
6111 shouldn't we have some kind of lower limit on region size?
6120 if (RegionFactory::region_name (new_name, r->name())) {
6124 /* do NOT announce new regions 1 by one, just wait till they are all done */
6128 plist.add (ARDOUR::Properties::start, file_start);
6129 plist.add (ARDOUR::Properties::length, len);
6130 plist.add (ARDOUR::Properties::name, new_name);
6131 plist.add (ARDOUR::Properties::layer, 0);
6133 boost::shared_ptr<Region> nr = RegionFactory::create (r->sources(), plist, false);
6134 /* because we set annouce to false, manually add the new region to the
6137 RegionFactory::map_add (nr);
6139 pl->add_region (nr, r->position() + pos);
6142 new_regions.push_front(nr);
6151 RegionFactory::region_name (new_name, r->name());
6153 /* Add the final region */
6156 plist.add (ARDOUR::Properties::start, r->start() + pos);
6157 plist.add (ARDOUR::Properties::length, r->last_frame() - (r->position() + pos) + 1);
6158 plist.add (ARDOUR::Properties::name, new_name);
6159 plist.add (ARDOUR::Properties::layer, 0);
6161 boost::shared_ptr<Region> nr = RegionFactory::create (r->sources(), plist, false);
6162 /* because we set annouce to false, manually add the new region to the
6165 RegionFactory::map_add (nr);
6166 pl->add_region (nr, r->position() + pos);
6169 new_regions.push_front(nr);
6174 /* We might have removed regions, which alters other regions' layering_index,
6175 so we need to do a recursive diff here.
6177 vector<Command*> cmds;
6179 _session->add_commands (cmds);
6181 _session->add_command (new StatefulDiffCommand (pl));
6185 for (list<boost::shared_ptr<Region> >::iterator i = new_regions.begin(); i != new_regions.end(); ++i){
6186 set_selected_regionview_from_region_list ((*i), Selection::Add);
6192 Editor::place_transient()
6198 RegionSelection rs = get_regions_from_selection_and_edit_point ();
6204 framepos_t where = get_preferred_edit_position();
6206 _session->begin_reversible_command (_("place transient"));
6208 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6209 framepos_t position = (*r)->region()->position();
6210 (*r)->region()->add_transient(where - position);
6213 _session->commit_reversible_command ();
6217 Editor::remove_transient(ArdourCanvas::Item* item)
6223 ArdourCanvas::Line* _line = reinterpret_cast<ArdourCanvas::Line*> (item);
6226 AudioRegionView* _arv = reinterpret_cast<AudioRegionView*> (item->get_data ("regionview"));
6227 _arv->remove_transient (*(float*) _line->get_data ("position"));
6231 Editor::snap_regions_to_grid ()
6233 list <boost::shared_ptr<Playlist > > used_playlists;
6235 RegionSelection rs = get_regions_from_selection_and_entered ();
6237 if (!_session || rs.empty()) {
6241 _session->begin_reversible_command (_("snap regions to grid"));
6243 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6245 boost::shared_ptr<Playlist> pl = (*r)->region()->playlist();
6247 if (!pl->frozen()) {
6248 /* we haven't seen this playlist before */
6250 /* remember used playlists so we can thaw them later */
6251 used_playlists.push_back(pl);
6255 framepos_t start_frame = (*r)->region()->first_frame ();
6256 snap_to (start_frame);
6257 (*r)->region()->set_position (start_frame);
6260 while (used_playlists.size() > 0) {
6261 list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
6263 used_playlists.pop_front();
6266 _session->commit_reversible_command ();
6270 Editor::close_region_gaps ()
6272 list <boost::shared_ptr<Playlist > > used_playlists;
6274 RegionSelection rs = get_regions_from_selection_and_entered ();
6276 if (!_session || rs.empty()) {
6280 Dialog dialog (_("Close Region Gaps"));
6283 table.set_spacings (12);
6284 table.set_border_width (12);
6285 Label* l = manage (left_aligned_label (_("Crossfade length")));
6286 table.attach (*l, 0, 1, 0, 1);
6288 SpinButton spin_crossfade (1, 0);
6289 spin_crossfade.set_range (0, 15);
6290 spin_crossfade.set_increments (1, 1);
6291 spin_crossfade.set_value (5);
6292 table.attach (spin_crossfade, 1, 2, 0, 1);
6294 table.attach (*manage (new Label (_("ms"))), 2, 3, 0, 1);
6296 l = manage (left_aligned_label (_("Pull-back length")));
6297 table.attach (*l, 0, 1, 1, 2);
6299 SpinButton spin_pullback (1, 0);
6300 spin_pullback.set_range (0, 100);
6301 spin_pullback.set_increments (1, 1);
6302 spin_pullback.set_value(30);
6303 table.attach (spin_pullback, 1, 2, 1, 2);
6305 table.attach (*manage (new Label (_("ms"))), 2, 3, 1, 2);
6307 dialog.get_vbox()->pack_start (table);
6308 dialog.add_button (Stock::CANCEL, RESPONSE_CANCEL);
6309 dialog.add_button (_("Ok"), RESPONSE_ACCEPT);
6312 if (dialog.run () == RESPONSE_CANCEL) {
6316 framepos_t crossfade_len = spin_crossfade.get_value();
6317 framepos_t pull_back_frames = spin_pullback.get_value();
6319 crossfade_len = lrintf (crossfade_len * _session->frame_rate()/1000);
6320 pull_back_frames = lrintf (pull_back_frames * _session->frame_rate()/1000);
6322 /* Iterate over the region list and make adjacent regions overlap by crossfade_len_ms */
6324 _session->begin_reversible_command (_("close region gaps"));
6327 boost::shared_ptr<Region> last_region;
6329 rs.sort_by_position_and_track();
6331 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6333 boost::shared_ptr<Playlist> pl = (*r)->region()->playlist();
6335 if (!pl->frozen()) {
6336 /* we haven't seen this playlist before */
6338 /* remember used playlists so we can thaw them later */
6339 used_playlists.push_back(pl);
6343 framepos_t position = (*r)->region()->position();
6345 if (idx == 0 || position < last_region->position()){
6346 last_region = (*r)->region();
6351 (*r)->region()->trim_front( (position - pull_back_frames));
6352 last_region->trim_end( (position - pull_back_frames + crossfade_len));
6354 last_region = (*r)->region();
6359 while (used_playlists.size() > 0) {
6360 list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
6362 used_playlists.pop_front();
6365 _session->commit_reversible_command ();
6369 Editor::tab_to_transient (bool forward)
6371 AnalysisFeatureList positions;
6373 RegionSelection rs = get_regions_from_selection_and_entered ();
6379 framepos_t pos = _session->audible_frame ();
6381 if (!selection->tracks.empty()) {
6383 /* don't waste time searching for transients in duplicate playlists.
6386 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
6388 for (TrackViewList::iterator t = ts.begin(); t != ts.end(); ++t) {
6390 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*t);
6393 boost::shared_ptr<Track> tr = rtv->track();
6395 boost::shared_ptr<Playlist> pl = tr->playlist ();
6397 framepos_t result = pl->find_next_transient (pos, forward ? 1 : -1);
6400 positions.push_back (result);
6413 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6414 (*r)->region()->get_transients (positions);
6418 TransientDetector::cleanup_transients (positions, _session->frame_rate(), 3.0);
6421 AnalysisFeatureList::iterator x;
6423 for (x = positions.begin(); x != positions.end(); ++x) {
6429 if (x != positions.end ()) {
6430 _session->request_locate (*x);
6434 AnalysisFeatureList::reverse_iterator x;
6436 for (x = positions.rbegin(); x != positions.rend(); ++x) {
6442 if (x != positions.rend ()) {
6443 _session->request_locate (*x);
6449 Editor::playhead_forward_to_grid ()
6455 framepos_t pos = playhead_cursor->current_frame ();
6456 if (pos < max_framepos - 1) {
6458 snap_to_internal (pos, 1, false);
6459 _session->request_locate (pos);
6465 Editor::playhead_backward_to_grid ()
6471 framepos_t pos = playhead_cursor->current_frame ();
6474 snap_to_internal (pos, -1, false);
6475 _session->request_locate (pos);
6480 Editor::set_track_height (Height h)
6482 TrackSelection& ts (selection->tracks);
6484 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
6485 (*x)->set_height_enum (h);
6490 Editor::toggle_tracks_active ()
6492 TrackSelection& ts (selection->tracks);
6494 bool target = false;
6500 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
6501 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*x);
6505 target = !rtv->_route->active();
6508 rtv->_route->set_active (target, this);
6514 Editor::remove_tracks ()
6516 TrackSelection& ts (selection->tracks);
6522 vector<string> choices;
6526 const char* trackstr;
6528 vector<boost::shared_ptr<Route> > routes;
6529 bool special_bus = false;
6531 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
6532 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*x);
6536 if (rtv->is_track()) {
6541 routes.push_back (rtv->_route);
6543 if (rtv->route()->is_master() || rtv->route()->is_monitor()) {
6548 if (special_bus && !Config->get_allow_special_bus_removal()) {
6549 MessageDialog msg (_("That would be bad news ...."),
6553 msg.set_secondary_text (string_compose (_(
6554 "Removing the master or monitor bus is such a bad idea\n\
6555 that %1 is not going to allow it.\n\
6557 If you really want to do this sort of thing\n\
6558 edit your ardour.rc file to set the\n\
6559 \"allow-special-bus-removal\" option to be \"yes\""), PROGRAM_NAME));
6566 if (ntracks + nbusses == 0) {
6570 // XXX should be using gettext plural forms, maybe?
6572 trackstr = _("tracks");
6574 trackstr = _("track");
6578 busstr = _("busses");
6585 prompt = string_compose (_("Do you really want to remove %1 %2 and %3 %4?\n"
6586 "(You may also lose the playlists associated with the %2)\n\n"
6587 "This action cannot be undone, and the session file will be overwritten!"),
6588 ntracks, trackstr, nbusses, busstr);
6590 prompt = string_compose (_("Do you really want to remove %1 %2?\n"
6591 "(You may also lose the playlists associated with the %2)\n\n"
6592 "This action cannot be undone, and the session file will be overwritten!"),
6595 } else if (nbusses) {
6596 prompt = string_compose (_("Do you really want to remove %1 %2?\n\n"
6597 "This action cannot be undone, and the session file will be overwritten"),
6601 choices.push_back (_("No, do nothing."));
6602 if (ntracks + nbusses > 1) {
6603 choices.push_back (_("Yes, remove them."));
6605 choices.push_back (_("Yes, remove it."));
6610 title = string_compose (_("Remove %1"), trackstr);
6612 title = string_compose (_("Remove %1"), busstr);
6615 Choice prompter (title, prompt, choices);
6617 if (prompter.run () != 1) {
6622 Session::StateProtector sp (_session);
6623 DisplaySuspender ds;
6624 for (vector<boost::shared_ptr<Route> >::iterator x = routes.begin(); x != routes.end(); ++x) {
6625 _session->remove_route (*x);
6631 Editor::do_insert_time ()
6633 if (selection->tracks.empty()) {
6637 InsertTimeDialog d (*this);
6638 int response = d.run ();
6640 if (response != RESPONSE_OK) {
6644 if (d.distance() == 0) {
6648 InsertTimeOption opt = d.intersected_region_action ();
6651 get_preferred_edit_position(),
6657 d.move_glued_markers(),
6658 d.move_locked_markers(),
6664 Editor::insert_time (
6665 framepos_t pos, framecnt_t frames, InsertTimeOption opt,
6666 bool all_playlists, bool ignore_music_glue, bool markers_too, bool glued_markers_too, bool locked_markers_too, bool tempo_too
6669 bool commit = false;
6671 if (Config->get_edit_mode() == Lock) {
6675 begin_reversible_command (_("insert time"));
6677 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
6679 for (TrackViewList::iterator x = ts.begin(); x != ts.end(); ++x) {
6683 /* don't operate on any playlist more than once, which could
6684 * happen if "all playlists" is enabled, but there is more
6685 * than 1 track using playlists "from" a given track.
6688 set<boost::shared_ptr<Playlist> > pl;
6690 if (all_playlists) {
6691 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*x);
6693 vector<boost::shared_ptr<Playlist> > all = _session->playlists->playlists_for_track (rtav->track ());
6694 for (vector<boost::shared_ptr<Playlist> >::iterator p = all.begin(); p != all.end(); ++p) {
6699 if ((*x)->playlist ()) {
6700 pl.insert ((*x)->playlist ());
6704 for (set<boost::shared_ptr<Playlist> >::iterator i = pl.begin(); i != pl.end(); ++i) {
6706 (*i)->clear_changes ();
6707 (*i)->clear_owned_changes ();
6709 if (opt == SplitIntersected) {
6713 (*i)->shift (pos, frames, (opt == MoveIntersected), ignore_music_glue);
6715 vector<Command*> cmds;
6717 _session->add_commands (cmds);
6719 _session->add_command (new StatefulDiffCommand (*i));
6724 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*x);
6726 rtav->route ()->shift (pos, frames);
6734 XMLNode& before (_session->locations()->get_state());
6735 Locations::LocationList copy (_session->locations()->list());
6737 for (Locations::LocationList::iterator i = copy.begin(); i != copy.end(); ++i) {
6739 Locations::LocationList::const_iterator tmp;
6741 bool const was_locked = (*i)->locked ();
6742 if (locked_markers_too) {
6746 if ((*i)->position_lock_style() == AudioTime || glued_markers_too) {
6748 if ((*i)->start() >= pos) {
6749 (*i)->set_start ((*i)->start() + frames);
6750 if (!(*i)->is_mark()) {
6751 (*i)->set_end ((*i)->end() + frames);
6764 XMLNode& after (_session->locations()->get_state());
6765 _session->add_command (new MementoCommand<Locations>(*_session->locations(), &before, &after));
6770 _session->tempo_map().insert_time (pos, frames);
6774 commit_reversible_command ();
6779 Editor::fit_selected_tracks ()
6781 if (!selection->tracks.empty()) {
6782 fit_tracks (selection->tracks);
6786 /* no selected tracks - use tracks with selected regions */
6788 if (!selection->regions.empty()) {
6789 for (RegionSelection::iterator r = selection->regions.begin(); r != selection->regions.end(); ++r) {
6790 tvl.push_back (&(*r)->get_time_axis_view ());
6796 } else if (internal_editing()) {
6797 /* no selected tracks, or regions, but in internal edit mode, so follow the mouse and use
6800 if (entered_track) {
6801 tvl.push_back (entered_track);
6810 Editor::fit_tracks (TrackViewList & tracks)
6812 if (tracks.empty()) {
6816 uint32_t child_heights = 0;
6817 int visible_tracks = 0;
6819 for (TrackSelection::iterator t = tracks.begin(); t != tracks.end(); ++t) {
6821 if (!(*t)->marked_for_display()) {
6825 child_heights += (*t)->effective_height() - (*t)->current_height();
6829 /* compute the per-track height from:
6831 total canvas visible height -
6832 height that will be taken by visible children of selected
6833 tracks - height of the ruler/hscroll area
6835 uint32_t h = (uint32_t) floor ((trackviews_height() - child_heights) / visible_tracks);
6836 double first_y_pos = DBL_MAX;
6838 if (h < TimeAxisView::preset_height (HeightSmall)) {
6839 MessageDialog msg (*this, _("There are too many tracks to fit in the current window"));
6840 /* too small to be displayed */
6844 undo_visual_stack.push_back (current_visual_state (true));
6845 no_save_visual = true;
6847 /* build a list of all tracks, including children */
6850 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
6852 TimeAxisView::Children c = (*i)->get_child_list ();
6853 for (TimeAxisView::Children::iterator j = c.begin(); j != c.end(); ++j) {
6854 all.push_back (j->get());
6858 bool prev_was_selected = false;
6859 bool is_selected = tracks.contains (all.front());
6860 bool next_is_selected;
6862 for (TrackViewList::iterator t = all.begin(); t != all.end(); ++t) {
6864 TrackViewList::iterator next;
6869 if (next != all.end()) {
6870 next_is_selected = tracks.contains (*next);
6872 next_is_selected = false;
6875 if ((*t)->marked_for_display ()) {
6877 (*t)->set_height (h);
6878 first_y_pos = std::min ((*t)->y_position (), first_y_pos);
6880 if (prev_was_selected && next_is_selected) {
6881 hide_track_in_display (*t);
6886 prev_was_selected = is_selected;
6887 is_selected = next_is_selected;
6891 set the controls_layout height now, because waiting for its size
6892 request signal handler will cause the vertical adjustment setting to fail
6895 controls_layout.property_height () = _full_canvas_height;
6896 vertical_adjustment.set_value (first_y_pos);
6898 redo_visual_stack.push_back (current_visual_state (true));
6900 visible_tracks_selector.set_text (_("Sel"));
6904 Editor::save_visual_state (uint32_t n)
6906 while (visual_states.size() <= n) {
6907 visual_states.push_back (0);
6910 if (visual_states[n] != 0) {
6911 delete visual_states[n];
6914 visual_states[n] = current_visual_state (true);
6919 Editor::goto_visual_state (uint32_t n)
6921 if (visual_states.size() <= n) {
6925 if (visual_states[n] == 0) {
6929 use_visual_state (*visual_states[n]);
6933 Editor::start_visual_state_op (uint32_t n)
6935 save_visual_state (n);
6937 PopUp* pup = new PopUp (WIN_POS_MOUSE, 1000, true);
6939 snprintf (buf, sizeof (buf), _("Saved view %u"), n+1);
6940 pup->set_text (buf);
6945 Editor::cancel_visual_state_op (uint32_t n)
6947 goto_visual_state (n);
6951 Editor::toggle_region_mute ()
6953 if (_ignore_region_action) {
6957 RegionSelection rs = get_regions_from_selection_and_entered ();
6963 if (rs.size() > 1) {
6964 begin_reversible_command (_("mute regions"));
6966 begin_reversible_command (_("mute region"));
6969 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
6971 (*i)->region()->playlist()->clear_changes ();
6972 (*i)->region()->set_muted (!(*i)->region()->muted ());
6973 _session->add_command (new StatefulDiffCommand ((*i)->region()->playlist()));
6977 commit_reversible_command ();
6981 Editor::combine_regions ()
6983 /* foreach track with selected regions, take all selected regions
6984 and join them into a new region containing the subregions (as a
6988 typedef set<RouteTimeAxisView*> RTVS;
6991 if (selection->regions.empty()) {
6995 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
6996 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(&(*i)->get_time_axis_view());
6999 tracks.insert (rtv);
7003 begin_reversible_command (_("combine regions"));
7005 vector<RegionView*> new_selection;
7007 for (RTVS::iterator i = tracks.begin(); i != tracks.end(); ++i) {
7010 if ((rv = (*i)->combine_regions ()) != 0) {
7011 new_selection.push_back (rv);
7015 selection->clear_regions ();
7016 for (vector<RegionView*>::iterator i = new_selection.begin(); i != new_selection.end(); ++i) {
7017 selection->add (*i);
7020 commit_reversible_command ();
7024 Editor::uncombine_regions ()
7026 typedef set<RouteTimeAxisView*> RTVS;
7029 if (selection->regions.empty()) {
7033 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
7034 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(&(*i)->get_time_axis_view());
7037 tracks.insert (rtv);
7041 begin_reversible_command (_("uncombine regions"));
7043 for (RTVS::iterator i = tracks.begin(); i != tracks.end(); ++i) {
7044 (*i)->uncombine_regions ();
7047 commit_reversible_command ();
7051 Editor::toggle_midi_input_active (bool flip_others)
7054 boost::shared_ptr<RouteList> rl (new RouteList);
7056 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
7057 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
7063 boost::shared_ptr<MidiTrack> mt = rtav->midi_track();
7066 rl->push_back (rtav->route());
7067 onoff = !mt->input_active();
7071 _session->set_exclusive_input_active (rl, onoff, flip_others);
7078 lock_dialog = new Gtk::Dialog (string_compose (_("%1: Locked"), PROGRAM_NAME), true);
7080 Gtk::Image* padlock = manage (new Gtk::Image (ARDOUR_UI_UTILS::get_icon ("padlock_closed")));
7081 lock_dialog->get_vbox()->pack_start (*padlock);
7083 ArdourButton* b = manage (new ArdourButton);
7084 b->set_name ("lock button");
7085 b->set_text (_("Click to unlock"));
7086 b->signal_clicked.connect (sigc::mem_fun (*this, &Editor::unlock));
7087 lock_dialog->get_vbox()->pack_start (*b);
7089 lock_dialog->get_vbox()->show_all ();
7090 lock_dialog->set_size_request (200, 200);
7094 /* The global menu bar continues to be accessible to applications
7095 with modal dialogs, which means that we need to desensitize
7096 all items in the menu bar. Since those items are really just
7097 proxies for actions, that means disabling all actions.
7099 ActionManager::disable_all_actions ();
7101 lock_dialog->present ();
7107 lock_dialog->hide ();
7110 ActionManager::pop_action_state ();
7113 if (ARDOUR_UI::config()->get_lock_gui_after_seconds()) {
7114 start_lock_event_timing ();
7119 Editor::bring_in_callback (Gtk::Label* label, uint32_t n, uint32_t total, string name)
7121 Gtkmm2ext::UI::instance()->call_slot (invalidator (*this), boost::bind (&Editor::update_bring_in_message, this, label, n, total, name));
7125 Editor::update_bring_in_message (Gtk::Label* label, uint32_t n, uint32_t total, string name)
7127 label->set_text (string_compose ("Copying %1, %2 of %3", name, n, total));
7128 Gtkmm2ext::UI::instance()->flush_pending ();
7132 Editor::bring_all_sources_into_session ()
7139 ArdourDialog w (_("Moving embedded files into session folder"));
7140 w.get_vbox()->pack_start (msg);
7143 /* flush all pending GUI events because we're about to start copying
7147 Gtkmm2ext::UI::instance()->flush_pending ();
7151 _session->bring_all_sources_into_session (boost::bind (&Editor::bring_in_callback, this, &msg, _1, _2, _3));