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 const gint pixwidth = gdk_screen_get_width (screen);
1644 const gint mmwidth = gdk_screen_get_width_mm (screen);
1645 const double pix_per_mm = (double) pixwidth/ (double) mmwidth;
1646 const double one_centimeter_in_pixels = pix_per_mm * 10.0;
1648 const framepos_t range = end - start;
1649 const framecnt_t new_fpp = (framecnt_t) ceil ((double) range / (double) _visible_canvas_width);
1650 const framepos_t extra_samples = (framepos_t) floor (one_centimeter_in_pixels * new_fpp);
1652 if (start > extra_samples) {
1653 start -= extra_samples;
1658 if (max_framepos - extra_samples > end) {
1659 end += extra_samples;
1666 Editor::temporal_zoom_region (bool both_axes)
1668 framepos_t start = max_framepos;
1670 set<TimeAxisView*> tracks;
1672 RegionSelection rs = get_regions_from_selection_and_entered ();
1678 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
1680 if ((*i)->region()->position() < start) {
1681 start = (*i)->region()->position();
1684 if ((*i)->region()->last_frame() + 1 > end) {
1685 end = (*i)->region()->last_frame() + 1;
1688 tracks.insert (&((*i)->get_time_axis_view()));
1691 if ((start == 0 && end == 0) || end < start) {
1695 calc_extra_zoom_edges (start, end);
1697 /* if we're zooming on both axes we need to save track heights etc.
1700 undo_visual_stack.push_back (current_visual_state (both_axes));
1702 PBD::Unwinder<bool> nsv (no_save_visual, true);
1704 temporal_zoom_by_frame (start, end);
1707 uint32_t per_track_height = (uint32_t) floor ((_visible_canvas_height - 10.0) / tracks.size());
1709 /* set visible track heights appropriately */
1711 for (set<TimeAxisView*>::iterator t = tracks.begin(); t != tracks.end(); ++t) {
1712 (*t)->set_height (per_track_height);
1715 /* hide irrelevant tracks */
1717 DisplaySuspender ds;
1719 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1720 if (find (tracks.begin(), tracks.end(), (*i)) == tracks.end()) {
1721 hide_track_in_display (*i);
1725 vertical_adjustment.set_value (0.0);
1728 redo_visual_stack.push_back (current_visual_state (both_axes));
1732 Editor::zoom_to_region (bool both_axes)
1734 temporal_zoom_region (both_axes);
1738 Editor::temporal_zoom_selection (bool both_axes)
1740 if (!selection) return;
1742 //if a range is selected, zoom to that
1743 if (!selection->time.empty()) {
1745 framepos_t start = selection->time.start();
1746 framepos_t end = selection->time.end_frame();
1748 calc_extra_zoom_edges(start, end);
1750 temporal_zoom_by_frame (start, end);
1753 fit_selected_tracks();
1756 temporal_zoom_region (both_axes);
1763 Editor::temporal_zoom_session ()
1765 ENSURE_GUI_THREAD (*this, &Editor::temporal_zoom_session)
1768 framecnt_t start = _session->current_start_frame();
1769 framecnt_t end = _session->current_end_frame();
1771 if (_session->actively_recording () ) {
1772 framepos_t cur = playhead_cursor->current_frame ();
1774 /* recording beyond the end marker; zoom out
1775 * by 5 seconds more so that if 'follow
1776 * playhead' is active we don't immediately
1779 end = cur + _session->frame_rate() * 5;
1783 if ((start == 0 && end == 0) || end < start) {
1787 calc_extra_zoom_edges(start, end);
1789 temporal_zoom_by_frame (start, end);
1794 Editor::temporal_zoom_by_frame (framepos_t start, framepos_t end)
1796 if (!_session) return;
1798 if ((start == 0 && end == 0) || end < start) {
1802 framepos_t range = end - start;
1804 const framecnt_t new_fpp = (framecnt_t) ceil ((double) range / (double) _visible_canvas_width);
1806 framepos_t new_page = range;
1807 framepos_t middle = (framepos_t) floor ((double) start + ((double) range / 2.0f));
1808 framepos_t new_leftmost = (framepos_t) floor ((double) middle - ((double) new_page / 2.0f));
1810 if (new_leftmost > middle) {
1814 if (new_leftmost < 0) {
1818 reposition_and_zoom (new_leftmost, new_fpp);
1822 Editor::temporal_zoom_to_frame (bool coarser, framepos_t frame)
1828 framecnt_t range_before = frame - leftmost_frame;
1832 if (samples_per_pixel <= 1) {
1835 new_spp = samples_per_pixel + (samples_per_pixel/2);
1837 range_before += range_before/2;
1839 if (samples_per_pixel >= 1) {
1840 new_spp = samples_per_pixel - (samples_per_pixel/2);
1842 /* could bail out here since we cannot zoom any finer,
1843 but leave that to the equality test below
1845 new_spp = samples_per_pixel;
1848 range_before -= range_before/2;
1851 if (new_spp == samples_per_pixel) {
1855 /* zoom focus is automatically taken as @param frame when this
1859 framepos_t new_leftmost = frame - (framepos_t)range_before;
1861 if (new_leftmost > frame) {
1865 if (new_leftmost < 0) {
1869 reposition_and_zoom (new_leftmost, new_spp);
1874 Editor::choose_new_marker_name(string &name) {
1876 if (!Config->get_name_new_markers()) {
1877 /* don't prompt user for a new name */
1881 ArdourPrompter dialog (true);
1883 dialog.set_prompt (_("New Name:"));
1885 dialog.set_title (_("New Location Marker"));
1887 dialog.set_name ("MarkNameWindow");
1888 dialog.set_size_request (250, -1);
1889 dialog.set_position (Gtk::WIN_POS_MOUSE);
1891 dialog.add_button (Stock::OK, RESPONSE_ACCEPT);
1892 dialog.set_initial_text (name);
1896 switch (dialog.run ()) {
1897 case RESPONSE_ACCEPT:
1903 dialog.get_result(name);
1910 Editor::add_location_from_selection ()
1914 if (selection->time.empty()) {
1918 if (_session == 0 || clicked_axisview == 0) {
1922 framepos_t start = selection->time[clicked_selection].start;
1923 framepos_t end = selection->time[clicked_selection].end;
1925 _session->locations()->next_available_name(rangename,"selection");
1926 Location *location = new Location (*_session, start, end, rangename, Location::IsRangeMarker);
1928 _session->begin_reversible_command (_("add marker"));
1929 XMLNode &before = _session->locations()->get_state();
1930 _session->locations()->add (location, true);
1931 XMLNode &after = _session->locations()->get_state();
1932 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
1933 _session->commit_reversible_command ();
1937 Editor::add_location_mark (framepos_t where)
1941 select_new_marker = true;
1943 _session->locations()->next_available_name(markername,"mark");
1944 if (!choose_new_marker_name(markername)) {
1947 Location *location = new Location (*_session, where, where, markername, Location::IsMark);
1948 _session->begin_reversible_command (_("add marker"));
1949 XMLNode &before = _session->locations()->get_state();
1950 _session->locations()->add (location, true);
1951 XMLNode &after = _session->locations()->get_state();
1952 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
1953 _session->commit_reversible_command ();
1957 Editor::add_location_from_playhead_cursor ()
1959 add_location_mark (_session->audible_frame());
1963 Editor::remove_location_at_playhead_cursor ()
1968 _session->begin_reversible_command (_("remove marker"));
1969 XMLNode &before = _session->locations()->get_state();
1970 bool removed = false;
1972 //find location(s) at this time
1973 Locations::LocationList locs;
1974 _session->locations()->find_all_between (_session->audible_frame(), _session->audible_frame()+1, locs, Location::Flags(0));
1975 for (Locations::LocationList::iterator i = locs.begin(); i != locs.end(); ++i) {
1976 if ((*i)->is_mark()) {
1977 _session->locations()->remove (*i);
1984 XMLNode &after = _session->locations()->get_state();
1985 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
1986 _session->commit_reversible_command ();
1991 /** Add a range marker around each selected region */
1993 Editor::add_locations_from_region ()
1995 RegionSelection rs = get_regions_from_selection_and_entered ();
2001 _session->begin_reversible_command (selection->regions.size () > 1 ? _("add markers") : _("add marker"));
2002 XMLNode &before = _session->locations()->get_state();
2004 for (RegionSelection::iterator i = rs.begin (); i != rs.end (); ++i) {
2006 boost::shared_ptr<Region> region = (*i)->region ();
2008 Location *location = new Location (*_session, region->position(), region->last_frame(), region->name(), Location::IsRangeMarker);
2010 _session->locations()->add (location, true);
2013 XMLNode &after = _session->locations()->get_state();
2014 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2015 _session->commit_reversible_command ();
2018 /** Add a single range marker around all selected regions */
2020 Editor::add_location_from_region ()
2022 RegionSelection rs = get_regions_from_selection_and_entered ();
2028 _session->begin_reversible_command (_("add marker"));
2029 XMLNode &before = _session->locations()->get_state();
2033 if (rs.size() > 1) {
2034 _session->locations()->next_available_name(markername, "regions");
2036 RegionView* rv = *(rs.begin());
2037 boost::shared_ptr<Region> region = rv->region();
2038 markername = region->name();
2041 if (!choose_new_marker_name(markername)) {
2045 // single range spanning all selected
2046 Location *location = new Location (*_session, selection->regions.start(), selection->regions.end_frame(), markername, Location::IsRangeMarker);
2047 _session->locations()->add (location, true);
2049 XMLNode &after = _session->locations()->get_state();
2050 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2051 _session->commit_reversible_command ();
2057 Editor::jump_forward_to_mark ()
2063 framepos_t pos = _session->locations()->first_mark_after (playhead_cursor->current_frame());
2069 _session->request_locate (pos, _session->transport_rolling());
2073 Editor::jump_backward_to_mark ()
2079 framepos_t pos = _session->locations()->first_mark_before (playhead_cursor->current_frame());
2085 _session->request_locate (pos, _session->transport_rolling());
2091 framepos_t const pos = _session->audible_frame ();
2094 _session->locations()->next_available_name (markername, "mark");
2096 if (!choose_new_marker_name (markername)) {
2100 _session->locations()->add (new Location (*_session, pos, 0, markername, Location::IsMark), true);
2104 Editor::clear_markers ()
2107 _session->begin_reversible_command (_("clear markers"));
2108 XMLNode &before = _session->locations()->get_state();
2109 _session->locations()->clear_markers ();
2110 XMLNode &after = _session->locations()->get_state();
2111 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2112 _session->commit_reversible_command ();
2117 Editor::clear_ranges ()
2120 _session->begin_reversible_command (_("clear ranges"));
2121 XMLNode &before = _session->locations()->get_state();
2123 _session->locations()->clear_ranges ();
2125 XMLNode &after = _session->locations()->get_state();
2126 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2127 _session->commit_reversible_command ();
2132 Editor::clear_locations ()
2134 _session->begin_reversible_command (_("clear locations"));
2135 XMLNode &before = _session->locations()->get_state();
2136 _session->locations()->clear ();
2137 XMLNode &after = _session->locations()->get_state();
2138 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2139 _session->commit_reversible_command ();
2140 _session->locations()->clear ();
2144 Editor::unhide_markers ()
2146 for (LocationMarkerMap::iterator i = location_markers.begin(); i != location_markers.end(); ++i) {
2147 Location *l = (*i).first;
2148 if (l->is_hidden() && l->is_mark()) {
2149 l->set_hidden(false, this);
2155 Editor::unhide_ranges ()
2157 for (LocationMarkerMap::iterator i = location_markers.begin(); i != location_markers.end(); ++i) {
2158 Location *l = (*i).first;
2159 if (l->is_hidden() && l->is_range_marker()) {
2160 l->set_hidden(false, this);
2165 /* INSERT/REPLACE */
2168 Editor::insert_region_list_selection (float times)
2170 RouteTimeAxisView *tv = 0;
2171 boost::shared_ptr<Playlist> playlist;
2173 if (clicked_routeview != 0) {
2174 tv = clicked_routeview;
2175 } else if (!selection->tracks.empty()) {
2176 if ((tv = dynamic_cast<RouteTimeAxisView*>(selection->tracks.front())) == 0) {
2179 } else if (entered_track != 0) {
2180 if ((tv = dynamic_cast<RouteTimeAxisView*>(entered_track)) == 0) {
2187 if ((playlist = tv->playlist()) == 0) {
2191 boost::shared_ptr<Region> region = _regions->get_single_selection ();
2196 begin_reversible_command (_("insert region"));
2197 playlist->clear_changes ();
2198 playlist->add_region ((RegionFactory::create (region, true)), get_preferred_edit_position(), times);
2199 if (Config->get_edit_mode() == Ripple)
2200 playlist->ripple (get_preferred_edit_position(), region->length() * times, boost::shared_ptr<Region>());
2202 _session->add_command(new StatefulDiffCommand (playlist));
2203 commit_reversible_command ();
2206 /* BUILT-IN EFFECTS */
2209 Editor::reverse_selection ()
2214 /* GAIN ENVELOPE EDITING */
2217 Editor::edit_envelope ()
2224 Editor::transition_to_rolling (bool fwd)
2230 if (_session->config.get_external_sync()) {
2231 switch (Config->get_sync_source()) {
2235 /* transport controlled by the master */
2240 if (_session->is_auditioning()) {
2241 _session->cancel_audition ();
2245 _session->request_transport_speed (fwd ? 1.0f : -1.0f);
2249 Editor::play_from_start ()
2251 _session->request_locate (_session->current_start_frame(), true);
2255 Editor::play_from_edit_point ()
2257 _session->request_locate (get_preferred_edit_position(), true);
2261 Editor::play_from_edit_point_and_return ()
2263 framepos_t start_frame;
2264 framepos_t return_frame;
2266 start_frame = get_preferred_edit_position (true);
2268 if (_session->transport_rolling()) {
2269 _session->request_locate (start_frame, false);
2273 /* don't reset the return frame if its already set */
2275 if ((return_frame = _session->requested_return_frame()) < 0) {
2276 return_frame = _session->audible_frame();
2279 if (start_frame >= 0) {
2280 _session->request_roll_at_and_return (start_frame, return_frame);
2285 Editor::play_selection ()
2287 if (selection->time.empty()) {
2291 _session->request_play_range (&selection->time, true);
2295 Editor::get_preroll ()
2297 return 1.0 /*Config->get_edit_preroll_seconds()*/ * _session->frame_rate();
2302 Editor::maybe_locate_with_edit_preroll ( framepos_t location )
2304 if ( _session->transport_rolling() || !Config->get_follow_edits() || _ignore_follow_edits )
2307 location -= get_preroll();
2309 //don't try to locate before the beginning of time
2313 //if follow_playhead is on, keep the playhead on the screen
2314 if ( _follow_playhead )
2315 if ( location < leftmost_frame )
2316 location = leftmost_frame;
2318 _session->request_locate( location );
2322 Editor::play_with_preroll ()
2324 if (selection->time.empty()) {
2327 framepos_t preroll = get_preroll();
2329 framepos_t start = 0;
2330 if (selection->time[clicked_selection].start > preroll)
2331 start = selection->time[clicked_selection].start - preroll;
2333 framepos_t end = selection->time[clicked_selection].end + preroll;
2335 AudioRange ar (start, end, 0);
2336 list<AudioRange> lar;
2339 _session->request_play_range (&lar, true);
2344 Editor::play_location (Location& location)
2346 if (location.start() <= location.end()) {
2350 _session->request_bounded_roll (location.start(), location.end());
2354 Editor::loop_location (Location& location)
2356 if (location.start() <= location.end()) {
2362 if ((tll = transport_loop_location()) != 0) {
2363 tll->set (location.start(), location.end());
2365 // enable looping, reposition and start rolling
2366 _session->request_locate (tll->start(), true);
2367 _session->request_play_loop (true);
2372 Editor::do_layer_operation (LayerOperation op)
2374 if (selection->regions.empty ()) {
2378 bool const multiple = selection->regions.size() > 1;
2382 begin_reversible_command (_("raise regions"));
2384 begin_reversible_command (_("raise region"));
2390 begin_reversible_command (_("raise regions to top"));
2392 begin_reversible_command (_("raise region to top"));
2398 begin_reversible_command (_("lower regions"));
2400 begin_reversible_command (_("lower region"));
2406 begin_reversible_command (_("lower regions to bottom"));
2408 begin_reversible_command (_("lower region"));
2413 set<boost::shared_ptr<Playlist> > playlists = selection->regions.playlists ();
2414 for (set<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
2415 (*i)->clear_owned_changes ();
2418 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
2419 boost::shared_ptr<Region> r = (*i)->region ();
2431 r->lower_to_bottom ();
2435 for (set<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
2436 vector<Command*> cmds;
2438 _session->add_commands (cmds);
2441 commit_reversible_command ();
2445 Editor::raise_region ()
2447 do_layer_operation (Raise);
2451 Editor::raise_region_to_top ()
2453 do_layer_operation (RaiseToTop);
2457 Editor::lower_region ()
2459 do_layer_operation (Lower);
2463 Editor::lower_region_to_bottom ()
2465 do_layer_operation (LowerToBottom);
2468 /** Show the region editor for the selected regions */
2470 Editor::show_region_properties ()
2472 selection->foreach_regionview (&RegionView::show_region_editor);
2475 /** Show the midi list editor for the selected MIDI regions */
2477 Editor::show_midi_list_editor ()
2479 selection->foreach_midi_regionview (&MidiRegionView::show_list_editor);
2483 Editor::rename_region ()
2485 RegionSelection rs = get_regions_from_selection_and_entered ();
2491 ArdourDialog d (*this, _("Rename Region"), true, false);
2493 Label label (_("New name:"));
2496 hbox.set_spacing (6);
2497 hbox.pack_start (label, false, false);
2498 hbox.pack_start (entry, true, true);
2500 d.get_vbox()->set_border_width (12);
2501 d.get_vbox()->pack_start (hbox, false, false);
2503 d.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
2504 d.add_button(Gtk::Stock::OK, Gtk::RESPONSE_OK);
2506 d.set_size_request (300, -1);
2508 entry.set_text (rs.front()->region()->name());
2509 entry.select_region (0, -1);
2511 entry.signal_activate().connect (sigc::bind (sigc::mem_fun (d, &Dialog::response), RESPONSE_OK));
2517 int const ret = d.run();
2521 if (ret != RESPONSE_OK) {
2525 std::string str = entry.get_text();
2526 strip_whitespace_edges (str);
2528 rs.front()->region()->set_name (str);
2529 _regions->redisplay ();
2534 Editor::audition_playlist_region_via_route (boost::shared_ptr<Region> region, Route& route)
2536 if (_session->is_auditioning()) {
2537 _session->cancel_audition ();
2540 // note: some potential for creativity here, because region doesn't
2541 // have to belong to the playlist that Route is handling
2543 // bool was_soloed = route.soloed();
2545 route.set_solo (true, this);
2547 _session->request_bounded_roll (region->position(), region->position() + region->length());
2549 /* XXX how to unset the solo state ? */
2552 /** Start an audition of the first selected region */
2554 Editor::play_edit_range ()
2556 framepos_t start, end;
2558 if (get_edit_op_range (start, end)) {
2559 _session->request_bounded_roll (start, end);
2564 Editor::play_selected_region ()
2566 framepos_t start = max_framepos;
2569 RegionSelection rs = get_regions_from_selection_and_entered ();
2575 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
2576 if ((*i)->region()->position() < start) {
2577 start = (*i)->region()->position();
2579 if ((*i)->region()->last_frame() + 1 > end) {
2580 end = (*i)->region()->last_frame() + 1;
2584 _session->request_bounded_roll (start, end);
2588 Editor::audition_playlist_region_standalone (boost::shared_ptr<Region> region)
2590 _session->audition_region (region);
2594 Editor::region_from_selection ()
2596 if (clicked_axisview == 0) {
2600 if (selection->time.empty()) {
2604 framepos_t start = selection->time[clicked_selection].start;
2605 framepos_t end = selection->time[clicked_selection].end;
2607 TrackViewList tracks = get_tracks_for_range_action ();
2609 framepos_t selection_cnt = end - start + 1;
2611 for (TrackSelection::iterator i = tracks.begin(); i != tracks.end(); ++i) {
2612 boost::shared_ptr<Region> current;
2613 boost::shared_ptr<Playlist> pl;
2614 framepos_t internal_start;
2617 if ((pl = (*i)->playlist()) == 0) {
2621 if ((current = pl->top_region_at (start)) == 0) {
2625 internal_start = start - current->position();
2626 RegionFactory::region_name (new_name, current->name(), true);
2630 plist.add (ARDOUR::Properties::start, current->start() + internal_start);
2631 plist.add (ARDOUR::Properties::length, selection_cnt);
2632 plist.add (ARDOUR::Properties::name, new_name);
2633 plist.add (ARDOUR::Properties::layer, 0);
2635 boost::shared_ptr<Region> region (RegionFactory::create (current, plist));
2640 Editor::create_region_from_selection (vector<boost::shared_ptr<Region> >& new_regions)
2642 if (selection->time.empty() || selection->tracks.empty()) {
2646 framepos_t start = selection->time[clicked_selection].start;
2647 framepos_t end = selection->time[clicked_selection].end;
2649 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
2650 sort_track_selection (ts);
2652 for (TrackSelection::iterator i = ts.begin(); i != ts.end(); ++i) {
2653 boost::shared_ptr<Region> current;
2654 boost::shared_ptr<Playlist> playlist;
2655 framepos_t internal_start;
2658 if ((playlist = (*i)->playlist()) == 0) {
2662 if ((current = playlist->top_region_at(start)) == 0) {
2666 internal_start = start - current->position();
2667 RegionFactory::region_name (new_name, current->name(), true);
2671 plist.add (ARDOUR::Properties::start, current->start() + internal_start);
2672 plist.add (ARDOUR::Properties::length, end - start + 1);
2673 plist.add (ARDOUR::Properties::name, new_name);
2675 new_regions.push_back (RegionFactory::create (current, plist));
2680 Editor::split_multichannel_region ()
2682 RegionSelection rs = get_regions_from_selection_and_entered ();
2688 vector< boost::shared_ptr<Region> > v;
2690 for (list<RegionView*>::iterator x = rs.begin(); x != rs.end(); ++x) {
2691 (*x)->region()->separate_by_channel (*_session, v);
2696 Editor::new_region_from_selection ()
2698 region_from_selection ();
2699 cancel_selection ();
2703 add_if_covered (RegionView* rv, const AudioRange* ar, RegionSelection* rs)
2705 switch (rv->region()->coverage (ar->start, ar->end - 1)) {
2706 case Evoral::OverlapNone:
2714 * - selected tracks, or if there are none...
2715 * - tracks containing selected regions, or if there are none...
2720 Editor::get_tracks_for_range_action () const
2724 if (selection->tracks.empty()) {
2726 /* use tracks with selected regions */
2728 RegionSelection rs = selection->regions;
2730 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
2731 TimeAxisView* tv = &(*i)->get_time_axis_view();
2733 if (!t.contains (tv)) {
2739 /* no regions and no tracks: use all tracks */
2745 t = selection->tracks;
2748 return t.filter_to_unique_playlists();
2752 Editor::separate_regions_between (const TimeSelection& ts)
2754 bool in_command = false;
2755 boost::shared_ptr<Playlist> playlist;
2756 RegionSelection new_selection;
2758 TrackViewList tmptracks = get_tracks_for_range_action ();
2759 sort_track_selection (tmptracks);
2761 for (TrackSelection::iterator i = tmptracks.begin(); i != tmptracks.end(); ++i) {
2763 RouteTimeAxisView* rtv;
2765 if ((rtv = dynamic_cast<RouteTimeAxisView*> ((*i))) != 0) {
2767 if (rtv->is_track()) {
2769 /* no edits to destructive tracks */
2771 if (rtv->track()->destructive()) {
2775 if ((playlist = rtv->playlist()) != 0) {
2777 playlist->clear_changes ();
2779 /* XXX need to consider musical time selections here at some point */
2781 double speed = rtv->track()->speed();
2784 for (list<AudioRange>::const_iterator t = ts.begin(); t != ts.end(); ++t) {
2786 sigc::connection c = rtv->view()->RegionViewAdded.connect (
2787 sigc::mem_fun(*this, &Editor::collect_new_region_view));
2789 latest_regionviews.clear ();
2791 playlist->partition ((framepos_t)((*t).start * speed),
2792 (framepos_t)((*t).end * speed), false);
2796 if (!latest_regionviews.empty()) {
2798 rtv->view()->foreach_regionview (sigc::bind (
2799 sigc::ptr_fun (add_if_covered),
2800 &(*t), &new_selection));
2803 begin_reversible_command (_("separate"));
2807 /* pick up changes to existing regions */
2809 vector<Command*> cmds;
2810 playlist->rdiff (cmds);
2811 _session->add_commands (cmds);
2813 /* pick up changes to the playlist itself (adds/removes)
2816 _session->add_command(new StatefulDiffCommand (playlist));
2825 // selection->set (new_selection);
2827 commit_reversible_command ();
2831 struct PlaylistState {
2832 boost::shared_ptr<Playlist> playlist;
2836 /** Take tracks from get_tracks_for_range_action and cut any regions
2837 * on those tracks so that the tracks are empty over the time
2841 Editor::separate_region_from_selection ()
2843 /* preferentially use *all* ranges in the time selection if we're in range mode
2844 to allow discontiguous operation, since get_edit_op_range() currently
2845 returns a single range.
2848 if (!selection->time.empty()) {
2850 separate_regions_between (selection->time);
2857 if (get_edit_op_range (start, end)) {
2859 AudioRange ar (start, end, 1);
2863 separate_regions_between (ts);
2869 Editor::separate_region_from_punch ()
2871 Location* loc = _session->locations()->auto_punch_location();
2873 separate_regions_using_location (*loc);
2878 Editor::separate_region_from_loop ()
2880 Location* loc = _session->locations()->auto_loop_location();
2882 separate_regions_using_location (*loc);
2887 Editor::separate_regions_using_location (Location& loc)
2889 if (loc.is_mark()) {
2893 AudioRange ar (loc.start(), loc.end(), 1);
2898 separate_regions_between (ts);
2901 /** Separate regions under the selected region */
2903 Editor::separate_under_selected_regions ()
2905 vector<PlaylistState> playlists;
2909 rs = get_regions_from_selection_and_entered();
2911 if (!_session || rs.empty()) {
2915 begin_reversible_command (_("separate region under"));
2917 list<boost::shared_ptr<Region> > regions_to_remove;
2919 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
2920 // we can't just remove the region(s) in this loop because
2921 // this removes them from the RegionSelection, and they thus
2922 // disappear from underneath the iterator, and the ++i above
2923 // SEGVs in a puzzling fashion.
2925 // so, first iterate over the regions to be removed from rs and
2926 // add them to the regions_to_remove list, and then
2927 // iterate over the list to actually remove them.
2929 regions_to_remove.push_back ((*i)->region());
2932 for (list<boost::shared_ptr<Region> >::iterator rl = regions_to_remove.begin(); rl != regions_to_remove.end(); ++rl) {
2934 boost::shared_ptr<Playlist> playlist = (*rl)->playlist();
2937 // is this check necessary?
2941 vector<PlaylistState>::iterator i;
2943 //only take state if this is a new playlist.
2944 for (i = playlists.begin(); i != playlists.end(); ++i) {
2945 if ((*i).playlist == playlist) {
2950 if (i == playlists.end()) {
2952 PlaylistState before;
2953 before.playlist = playlist;
2954 before.before = &playlist->get_state();
2956 playlist->freeze ();
2957 playlists.push_back(before);
2960 //Partition on the region bounds
2961 playlist->partition ((*rl)->first_frame() - 1, (*rl)->last_frame() + 1, true);
2963 //Re-add region that was just removed due to the partition operation
2964 playlist->add_region( (*rl), (*rl)->first_frame() );
2967 vector<PlaylistState>::iterator pl;
2969 for (pl = playlists.begin(); pl != playlists.end(); ++pl) {
2970 (*pl).playlist->thaw ();
2971 _session->add_command(new MementoCommand<Playlist>(*(*pl).playlist, (*pl).before, &(*pl).playlist->get_state()));
2974 commit_reversible_command ();
2978 Editor::crop_region_to_selection ()
2980 if (!selection->time.empty()) {
2982 crop_region_to (selection->time.start(), selection->time.end_frame());
2989 if (get_edit_op_range (start, end)) {
2990 crop_region_to (start, end);
2997 Editor::crop_region_to (framepos_t start, framepos_t end)
2999 vector<boost::shared_ptr<Playlist> > playlists;
3000 boost::shared_ptr<Playlist> playlist;
3003 if (selection->tracks.empty()) {
3004 ts = track_views.filter_to_unique_playlists();
3006 ts = selection->tracks.filter_to_unique_playlists ();
3009 sort_track_selection (ts);
3011 for (TrackSelection::iterator i = ts.begin(); i != ts.end(); ++i) {
3013 RouteTimeAxisView* rtv;
3015 if ((rtv = dynamic_cast<RouteTimeAxisView*> ((*i))) != 0) {
3017 boost::shared_ptr<Track> t = rtv->track();
3019 if (t != 0 && ! t->destructive()) {
3021 if ((playlist = rtv->playlist()) != 0) {
3022 playlists.push_back (playlist);
3028 if (playlists.empty()) {
3032 framepos_t the_start;
3036 begin_reversible_command (_("trim to selection"));
3038 for (vector<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
3040 boost::shared_ptr<Region> region;
3044 if ((region = (*i)->top_region_at(the_start)) == 0) {
3048 /* now adjust lengths to that we do the right thing
3049 if the selection extends beyond the region
3052 the_start = max (the_start, (framepos_t) region->position());
3053 if (max_framepos - the_start < region->length()) {
3054 the_end = the_start + region->length() - 1;
3056 the_end = max_framepos;
3058 the_end = min (end, the_end);
3059 cnt = the_end - the_start + 1;
3061 region->clear_changes ();
3062 region->trim_to (the_start, cnt);
3063 _session->add_command (new StatefulDiffCommand (region));
3066 commit_reversible_command ();
3070 Editor::region_fill_track ()
3072 RegionSelection rs = get_regions_from_selection_and_entered ();
3074 if (!_session || rs.empty()) {
3078 framepos_t const end = _session->current_end_frame ();
3080 begin_reversible_command (Operations::region_fill);
3082 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3084 boost::shared_ptr<Region> region ((*i)->region());
3086 boost::shared_ptr<Playlist> pl = region->playlist();
3088 if (end <= region->last_frame()) {
3092 double times = (double) (end - region->last_frame()) / (double) region->length();
3098 pl->clear_changes ();
3099 pl->add_region (RegionFactory::create (region, true), region->last_frame(), times);
3100 _session->add_command (new StatefulDiffCommand (pl));
3103 commit_reversible_command ();
3107 Editor::region_fill_selection ()
3109 if (clicked_routeview == 0 || !clicked_routeview->is_audio_track()) {
3113 if (selection->time.empty()) {
3117 boost::shared_ptr<Region> region = _regions->get_single_selection ();
3122 framepos_t start = selection->time[clicked_selection].start;
3123 framepos_t end = selection->time[clicked_selection].end;
3125 boost::shared_ptr<Playlist> playlist;
3127 if (selection->tracks.empty()) {
3131 framepos_t selection_length = end - start;
3132 float times = (float)selection_length / region->length();
3134 begin_reversible_command (Operations::fill_selection);
3136 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
3138 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
3140 if ((playlist = (*i)->playlist()) == 0) {
3144 playlist->clear_changes ();
3145 playlist->add_region (RegionFactory::create (region, true), start, times);
3146 _session->add_command (new StatefulDiffCommand (playlist));
3149 commit_reversible_command ();
3153 Editor::set_region_sync_position ()
3155 set_sync_point (get_preferred_edit_position (), get_regions_from_selection_and_edit_point ());
3159 Editor::set_sync_point (framepos_t where, const RegionSelection& rs)
3161 bool in_command = false;
3163 for (RegionSelection::const_iterator r = rs.begin(); r != rs.end(); ++r) {
3165 if (!(*r)->region()->covers (where)) {
3169 boost::shared_ptr<Region> region ((*r)->region());
3172 begin_reversible_command (_("set sync point"));
3176 region->clear_changes ();
3177 region->set_sync_position (where);
3178 _session->add_command(new StatefulDiffCommand (region));
3182 commit_reversible_command ();
3186 /** Remove the sync positions of the selection */
3188 Editor::remove_region_sync ()
3190 RegionSelection rs = get_regions_from_selection_and_entered ();
3196 begin_reversible_command (_("remove region sync"));
3198 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3200 (*i)->region()->clear_changes ();
3201 (*i)->region()->clear_sync_position ();
3202 _session->add_command(new StatefulDiffCommand ((*i)->region()));
3205 commit_reversible_command ();
3209 Editor::naturalize_region ()
3211 RegionSelection rs = get_regions_from_selection_and_entered ();
3217 if (rs.size() > 1) {
3218 begin_reversible_command (_("move regions to original position"));
3220 begin_reversible_command (_("move region to original position"));
3223 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3224 (*i)->region()->clear_changes ();
3225 (*i)->region()->move_to_natural_position ();
3226 _session->add_command (new StatefulDiffCommand ((*i)->region()));
3229 commit_reversible_command ();
3233 Editor::align_regions (RegionPoint what)
3235 RegionSelection const rs = get_regions_from_selection_and_edit_point ();
3241 begin_reversible_command (_("align selection"));
3243 framepos_t const position = get_preferred_edit_position ();
3245 for (RegionSelection::const_iterator i = rs.begin(); i != rs.end(); ++i) {
3246 align_region_internal ((*i)->region(), what, position);
3249 commit_reversible_command ();
3252 struct RegionSortByTime {
3253 bool operator() (const RegionView* a, const RegionView* b) {
3254 return a->region()->position() < b->region()->position();
3259 Editor::align_regions_relative (RegionPoint point)
3261 RegionSelection const rs = get_regions_from_selection_and_edit_point ();
3267 framepos_t const position = get_preferred_edit_position ();
3269 framepos_t distance = 0;
3273 list<RegionView*> sorted;
3274 rs.by_position (sorted);
3276 boost::shared_ptr<Region> r ((*sorted.begin())->region());
3281 if (position > r->position()) {
3282 distance = position - r->position();
3284 distance = r->position() - position;
3290 if (position > r->last_frame()) {
3291 distance = position - r->last_frame();
3292 pos = r->position() + distance;
3294 distance = r->last_frame() - position;
3295 pos = r->position() - distance;
3301 pos = r->adjust_to_sync (position);
3302 if (pos > r->position()) {
3303 distance = pos - r->position();
3305 distance = r->position() - pos;
3311 if (pos == r->position()) {
3315 begin_reversible_command (_("align selection (relative)"));
3317 /* move first one specially */
3319 r->clear_changes ();
3320 r->set_position (pos);
3321 _session->add_command(new StatefulDiffCommand (r));
3323 /* move rest by the same amount */
3327 for (list<RegionView*>::iterator i = sorted.begin(); i != sorted.end(); ++i) {
3329 boost::shared_ptr<Region> region ((*i)->region());
3331 region->clear_changes ();
3334 region->set_position (region->position() + distance);
3336 region->set_position (region->position() - distance);
3339 _session->add_command(new StatefulDiffCommand (region));
3343 commit_reversible_command ();
3347 Editor::align_region (boost::shared_ptr<Region> region, RegionPoint point, framepos_t position)
3349 begin_reversible_command (_("align region"));
3350 align_region_internal (region, point, position);
3351 commit_reversible_command ();
3355 Editor::align_region_internal (boost::shared_ptr<Region> region, RegionPoint point, framepos_t position)
3357 region->clear_changes ();
3361 region->set_position (region->adjust_to_sync (position));
3365 if (position > region->length()) {
3366 region->set_position (position - region->length());
3371 region->set_position (position);
3375 _session->add_command(new StatefulDiffCommand (region));
3379 Editor::trim_region_front ()
3385 Editor::trim_region_back ()
3387 trim_region (false);
3391 Editor::trim_region (bool front)
3393 framepos_t where = get_preferred_edit_position();
3394 RegionSelection rs = get_regions_from_selection_and_edit_point ();
3400 begin_reversible_command (front ? _("trim front") : _("trim back"));
3402 for (list<RegionView*>::const_iterator i = rs.by_layer().begin(); i != rs.by_layer().end(); ++i) {
3403 if (!(*i)->region()->locked()) {
3405 (*i)->region()->clear_changes ();
3408 (*i)->region()->trim_front (where);
3409 maybe_locate_with_edit_preroll ( where );
3411 (*i)->region()->trim_end (where);
3412 maybe_locate_with_edit_preroll ( where );
3415 _session->add_command (new StatefulDiffCommand ((*i)->region()));
3419 commit_reversible_command ();
3422 /** Trim the end of the selected regions to the position of the edit cursor */
3424 Editor::trim_region_to_loop ()
3426 Location* loc = _session->locations()->auto_loop_location();
3430 trim_region_to_location (*loc, _("trim to loop"));
3434 Editor::trim_region_to_punch ()
3436 Location* loc = _session->locations()->auto_punch_location();
3440 trim_region_to_location (*loc, _("trim to punch"));
3444 Editor::trim_region_to_location (const Location& loc, const char* str)
3446 RegionSelection rs = get_regions_from_selection_and_entered ();
3448 begin_reversible_command (str);
3450 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
3451 RegionView* rv = (*x);
3453 /* require region to span proposed trim */
3454 switch (rv->region()->coverage (loc.start(), loc.end())) {
3455 case Evoral::OverlapInternal:
3461 RouteTimeAxisView* tav = dynamic_cast<RouteTimeAxisView*> (&rv->get_time_axis_view());
3470 if (tav->track() != 0) {
3471 speed = tav->track()->speed();
3474 start = session_frame_to_track_frame (loc.start(), speed);
3475 end = session_frame_to_track_frame (loc.end(), speed);
3477 rv->region()->clear_changes ();
3478 rv->region()->trim_to (start, (end - start));
3479 _session->add_command(new StatefulDiffCommand (rv->region()));
3482 commit_reversible_command ();
3486 Editor::trim_region_to_previous_region_end ()
3488 return trim_to_region(false);
3492 Editor::trim_region_to_next_region_start ()
3494 return trim_to_region(true);
3498 Editor::trim_to_region(bool forward)
3500 RegionSelection rs = get_regions_from_selection_and_entered ();
3502 begin_reversible_command (_("trim to region"));
3504 boost::shared_ptr<Region> next_region;
3506 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
3508 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*x);
3514 AudioTimeAxisView* atav = dynamic_cast<AudioTimeAxisView*> (&arv->get_time_axis_view());
3522 if (atav->track() != 0) {
3523 speed = atav->track()->speed();
3527 boost::shared_ptr<Region> region = arv->region();
3528 boost::shared_ptr<Playlist> playlist (region->playlist());
3530 region->clear_changes ();
3534 next_region = playlist->find_next_region (region->first_frame(), Start, 1);
3540 region->trim_end((framepos_t) ( (next_region->first_frame() - 1) * speed));
3541 arv->region_changed (PropertyChange (ARDOUR::Properties::length));
3545 next_region = playlist->find_next_region (region->first_frame(), Start, 0);
3551 region->trim_front((framepos_t) ((next_region->last_frame() + 1) * speed));
3553 arv->region_changed (ARDOUR::bounds_change);
3556 _session->add_command(new StatefulDiffCommand (region));
3559 commit_reversible_command ();
3563 Editor::unfreeze_route ()
3565 if (clicked_routeview == 0 || !clicked_routeview->is_track()) {
3569 clicked_routeview->track()->unfreeze ();
3573 Editor::_freeze_thread (void* arg)
3575 return static_cast<Editor*>(arg)->freeze_thread ();
3579 Editor::freeze_thread ()
3581 /* create event pool because we may need to talk to the session */
3582 SessionEvent::create_per_thread_pool ("freeze events", 64);
3583 /* create per-thread buffers for process() tree to use */
3584 clicked_routeview->audio_track()->freeze_me (*current_interthread_info);
3585 current_interthread_info->done = true;
3590 Editor::freeze_route ()
3596 /* stop transport before we start. this is important */
3598 _session->request_transport_speed (0.0);
3600 /* wait for just a little while, because the above call is asynchronous */
3602 Glib::usleep (250000);
3604 if (clicked_routeview == 0 || !clicked_routeview->is_audio_track()) {
3608 if (!clicked_routeview->track()->bounceable (clicked_routeview->track()->main_outs(), true)) {
3610 _("This track/bus cannot be frozen because the signal adds or loses channels before reaching the outputs.\n"
3611 "This is typically caused by plugins that generate stereo output from mono input or vice versa.")
3613 d.set_title (_("Cannot freeze"));
3618 if (clicked_routeview->track()->has_external_redirects()) {
3619 MessageDialog d (string_compose (_("<b>%1</b>\n\nThis track has at least one send/insert/return as part of its signal flow.\n\n"
3620 "Freezing will only process the signal as far as the first send/insert/return."),
3621 clicked_routeview->track()->name()), true, MESSAGE_INFO, BUTTONS_NONE, true);
3623 d.add_button (_("Freeze anyway"), Gtk::RESPONSE_OK);
3624 d.add_button (_("Don't freeze"), Gtk::RESPONSE_CANCEL);
3625 d.set_title (_("Freeze Limits"));
3627 int response = d.run ();
3630 case Gtk::RESPONSE_CANCEL:
3637 InterThreadInfo itt;
3638 current_interthread_info = &itt;
3640 InterthreadProgressWindow ipw (current_interthread_info, _("Freeze"), _("Cancel Freeze"));
3642 pthread_create_and_store (X_("freezer"), &itt.thread, _freeze_thread, this);
3644 set_canvas_cursor (_cursors->wait);
3646 while (!itt.done && !itt.cancel) {
3647 gtk_main_iteration ();
3650 current_interthread_info = 0;
3651 set_canvas_cursor (current_canvas_cursor);
3655 Editor::bounce_range_selection (bool replace, bool enable_processing)
3657 if (selection->time.empty()) {
3661 TrackSelection views = selection->tracks;
3663 for (TrackViewList::iterator i = views.begin(); i != views.end(); ++i) {
3665 if (enable_processing) {
3667 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*i);
3669 if (rtv && rtv->track() && replace && enable_processing && !rtv->track()->bounceable (rtv->track()->main_outs(), false)) {
3671 _("You can't perform this operation because the processing of the signal "
3672 "will cause one or more of the tracks to end up with a region with more channels than this track has inputs.\n\n"
3673 "You can do this without processing, which is a different operation.")
3675 d.set_title (_("Cannot bounce"));
3682 framepos_t start = selection->time[clicked_selection].start;
3683 framepos_t end = selection->time[clicked_selection].end;
3684 framepos_t cnt = end - start + 1;
3686 begin_reversible_command (_("bounce range"));
3688 for (TrackViewList::iterator i = views.begin(); i != views.end(); ++i) {
3690 RouteTimeAxisView* rtv;
3692 if ((rtv = dynamic_cast<RouteTimeAxisView*> (*i)) == 0) {
3696 boost::shared_ptr<Playlist> playlist;
3698 if ((playlist = rtv->playlist()) == 0) {
3702 InterThreadInfo itt;
3704 playlist->clear_changes ();
3705 playlist->clear_owned_changes ();
3707 boost::shared_ptr<Region> r;
3709 if (enable_processing) {
3710 r = rtv->track()->bounce_range (start, start+cnt, itt, rtv->track()->main_outs(), false);
3712 r = rtv->track()->bounce_range (start, start+cnt, itt, boost::shared_ptr<Processor>(), false);
3720 list<AudioRange> ranges;
3721 ranges.push_back (AudioRange (start, start+cnt, 0));
3722 playlist->cut (ranges); // discard result
3723 playlist->add_region (r, start);
3726 vector<Command*> cmds;
3727 playlist->rdiff (cmds);
3728 _session->add_commands (cmds);
3730 _session->add_command (new StatefulDiffCommand (playlist));
3733 commit_reversible_command ();
3736 /** Delete selected regions, automation points or a time range */
3740 //special case: if the user is pointing in the editor/mixer strip, they may be trying to delete a plugin.
3741 //we need this because the editor-mixer strip is in the editor window, so it doesn't get the bindings from the mix window
3742 bool deleted = false;
3743 if ( current_mixer_strip && current_mixer_strip == MixerStrip::entered_mixer_strip() )
3744 deleted = current_mixer_strip->delete_processors ();
3750 /** Cut selected regions, automation points or a time range */
3757 /** Copy selected regions, automation points or a time range */
3765 /** @return true if a Cut, Copy or Clear is possible */
3767 Editor::can_cut_copy () const
3769 if (!selection->time.empty() || !selection->regions.empty() || !selection->points.empty())
3776 /** Cut, copy or clear selected regions, automation points or a time range.
3777 * @param op Operation (Delete, Cut, Copy or Clear)
3780 Editor::cut_copy (CutCopyOp op)
3782 /* only cancel selection if cut/copy is successful.*/
3788 opname = _("delete");
3797 opname = _("clear");
3801 /* if we're deleting something, and the mouse is still pressed,
3802 the thing we started a drag for will be gone when we release
3803 the mouse button(s). avoid this. see part 2 at the end of
3807 if (op == Delete || op == Cut || op == Clear) {
3808 if (_drags->active ()) {
3813 if ( op != Delete ) //"Delete" doesn't change copy/paste buf
3814 cut_buffer->clear ();
3816 if (entered_marker) {
3818 /* cut/delete op while pointing at a marker */
3821 Location* loc = find_location_from_marker (entered_marker, ignored);
3823 if (_session && loc) {
3824 Glib::signal_idle().connect (sigc::bind (sigc::mem_fun(*this, &Editor::really_remove_marker), loc));
3831 if (internal_editing()) {
3833 switch (effective_mouse_mode()) {
3836 begin_reversible_command (opname + ' ' + X_("MIDI"));
3838 commit_reversible_command ();
3847 bool did_edit = false;
3849 if (!selection->points.empty()) {
3850 begin_reversible_command (opname + _(" points"));
3852 cut_copy_points (op);
3853 if (op == Cut || op == Delete) {
3854 selection->clear_points ();
3856 } else if (!selection->regions.empty() || !selection->points.empty()) {
3860 if (selection->regions.empty()) {
3861 thing_name = _("points");
3862 } else if (selection->points.empty()) {
3863 thing_name = _("regions");
3865 thing_name = _("objects");
3868 begin_reversible_command (opname + ' ' + thing_name);
3871 if (!selection->regions.empty()) {
3872 cut_copy_regions (op, selection->regions);
3874 if (op == Cut || op == Delete) {
3875 selection->clear_regions ();
3879 if (!selection->points.empty()) {
3880 cut_copy_points (op);
3882 if (op == Cut || op == Delete) {
3883 selection->clear_points ();
3886 } else if (selection->time.empty()) {
3887 framepos_t start, end;
3888 /* no time selection, see if we can get an edit range
3891 if (get_edit_op_range (start, end)) {
3892 selection->set (start, end);
3894 } else if (!selection->time.empty()) {
3895 begin_reversible_command (opname + _(" range"));
3898 cut_copy_ranges (op);
3900 if (op == Cut || op == Delete) {
3901 selection->clear_time ();
3906 commit_reversible_command ();
3909 if (op == Delete || op == Cut || op == Clear) {
3914 struct AutomationRecord {
3915 AutomationRecord () : state (0) {}
3916 AutomationRecord (XMLNode* s) : state (s) {}
3918 XMLNode* state; ///< state before any operation
3919 boost::shared_ptr<Evoral::ControlList> copy; ///< copied events for the cut buffer
3922 /** Cut, copy or clear selected automation points.
3923 * @param op Operation (Cut, Copy or Clear)
3926 Editor::cut_copy_points (CutCopyOp op)
3928 if (selection->points.empty ()) {
3932 /* XXX: not ideal, as there may be more than one track involved in the point selection */
3933 _last_cut_copy_source_track = &selection->points.front()->line().trackview;
3935 /* Keep a record of the AutomationLists that we end up using in this operation */
3936 typedef std::map<boost::shared_ptr<AutomationList>, AutomationRecord> Lists;
3939 /* Go through all selected points, making an AutomationRecord for each distinct AutomationList */
3940 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
3941 boost::shared_ptr<AutomationList> al = (*i)->line().the_list();
3942 if (lists.find (al) == lists.end ()) {
3943 /* We haven't seen this list yet, so make a record for it. This includes
3944 taking a copy of its current state, in case this is needed for undo later.
3946 lists[al] = AutomationRecord (&al->get_state ());
3950 if (op == Cut || op == Copy) {
3951 /* This operation will involve putting things in the cut buffer, so create an empty
3952 ControlList for each of our source lists to put the cut buffer data in.
3954 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
3955 i->second.copy = i->first->create (i->first->parameter ());
3958 /* Add all selected points to the relevant copy ControlLists */
3959 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
3960 boost::shared_ptr<AutomationList> al = (*i)->line().the_list();
3961 AutomationList::const_iterator j = (*i)->model ();
3962 lists[al].copy->add ((*j)->when, (*j)->value);
3965 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
3966 /* Correct this copy list so that it starts at time 0 */
3967 double const start = i->second.copy->front()->when;
3968 for (AutomationList::iterator j = i->second.copy->begin(); j != i->second.copy->end(); ++j) {
3969 (*j)->when -= start;
3972 /* And add it to the cut buffer */
3973 cut_buffer->add (i->second.copy);
3977 if (op == Delete || op == Cut) {
3978 /* This operation needs to remove things from the main AutomationList, so do that now */
3980 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
3981 i->first->freeze ();
3984 /* Remove each selected point from its AutomationList */
3985 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
3986 boost::shared_ptr<AutomationList> al = (*i)->line().the_list();
3987 al->erase ((*i)->model ());
3990 /* Thaw the lists and add undo records for them */
3991 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
3992 boost::shared_ptr<AutomationList> al = i->first;
3994 _session->add_command (new MementoCommand<AutomationList> (*al.get(), i->second.state, &(al->get_state ())));
3999 /** Cut, copy or clear selected automation points.
4000 * @param op Operation (Cut, Copy or Clear)
4003 Editor::cut_copy_midi (CutCopyOp op)
4005 for (MidiRegionSelection::iterator i = selection->midi_regions.begin(); i != selection->midi_regions.end(); ++i) {
4006 MidiRegionView* mrv = *i;
4007 mrv->cut_copy_clear (op);
4013 struct lt_playlist {
4014 bool operator () (const PlaylistState& a, const PlaylistState& b) {
4015 return a.playlist < b.playlist;
4019 struct PlaylistMapping {
4021 boost::shared_ptr<Playlist> pl;
4023 PlaylistMapping (TimeAxisView* tvp) : tv (tvp) {}
4026 /** Remove `clicked_regionview' */
4028 Editor::remove_clicked_region ()
4030 if (clicked_routeview == 0 || clicked_regionview == 0) {
4034 boost::shared_ptr<Playlist> playlist = clicked_routeview->playlist();
4036 playlist->clear_changes ();
4037 playlist->clear_owned_changes ();
4038 playlist->remove_region (clicked_regionview->region());
4039 if (Config->get_edit_mode() == Ripple)
4040 playlist->ripple (clicked_regionview->region()->position(), -clicked_regionview->region()->length(), boost::shared_ptr<Region>());
4042 /* We might have removed regions, which alters other regions' layering_index,
4043 so we need to do a recursive diff here.
4045 vector<Command*> cmds;
4046 playlist->rdiff (cmds);
4047 _session->add_commands (cmds);
4049 _session->add_command(new StatefulDiffCommand (playlist));
4050 commit_reversible_command ();
4054 /** Remove the selected regions */
4056 Editor::remove_selected_regions ()
4058 RegionSelection rs = get_regions_from_selection_and_entered ();
4060 if (!_session || rs.empty()) {
4064 begin_reversible_command (_("remove region"));
4066 list<boost::shared_ptr<Region> > regions_to_remove;
4068 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
4069 // we can't just remove the region(s) in this loop because
4070 // this removes them from the RegionSelection, and they thus
4071 // disappear from underneath the iterator, and the ++i above
4072 // SEGVs in a puzzling fashion.
4074 // so, first iterate over the regions to be removed from rs and
4075 // add them to the regions_to_remove list, and then
4076 // iterate over the list to actually remove them.
4078 regions_to_remove.push_back ((*i)->region());
4081 vector<boost::shared_ptr<Playlist> > playlists;
4083 for (list<boost::shared_ptr<Region> >::iterator rl = regions_to_remove.begin(); rl != regions_to_remove.end(); ++rl) {
4085 boost::shared_ptr<Playlist> playlist = (*rl)->playlist();
4088 // is this check necessary?
4092 /* get_regions_from_selection_and_entered() guarantees that
4093 the playlists involved are unique, so there is no need
4097 playlists.push_back (playlist);
4099 playlist->clear_changes ();
4100 playlist->clear_owned_changes ();
4101 playlist->freeze ();
4102 playlist->remove_region (*rl);
4103 if (Config->get_edit_mode() == Ripple)
4104 playlist->ripple ((*rl)->position(), -(*rl)->length(), boost::shared_ptr<Region>());
4108 vector<boost::shared_ptr<Playlist> >::iterator pl;
4110 for (pl = playlists.begin(); pl != playlists.end(); ++pl) {
4113 /* We might have removed regions, which alters other regions' layering_index,
4114 so we need to do a recursive diff here.
4116 vector<Command*> cmds;
4117 (*pl)->rdiff (cmds);
4118 _session->add_commands (cmds);
4120 _session->add_command(new StatefulDiffCommand (*pl));
4123 commit_reversible_command ();
4126 /** Cut, copy or clear selected regions.
4127 * @param op Operation (Cut, Copy or Clear)
4130 Editor::cut_copy_regions (CutCopyOp op, RegionSelection& rs)
4132 /* we can't use a std::map here because the ordering is important, and we can't trivially sort
4133 a map when we want ordered access to both elements. i think.
4136 vector<PlaylistMapping> pmap;
4138 framepos_t first_position = max_framepos;
4140 typedef set<boost::shared_ptr<Playlist> > FreezeList;
4141 FreezeList freezelist;
4143 /* get ordering correct before we cut/copy */
4145 rs.sort_by_position_and_track ();
4147 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
4149 first_position = min ((framepos_t) (*x)->region()->position(), first_position);
4151 if (op == Cut || op == Clear || op == Delete) {
4152 boost::shared_ptr<Playlist> pl = (*x)->region()->playlist();
4155 FreezeList::iterator fl;
4157 // only take state if this is a new playlist.
4158 for (fl = freezelist.begin(); fl != freezelist.end(); ++fl) {
4164 if (fl == freezelist.end()) {
4165 pl->clear_changes();
4166 pl->clear_owned_changes ();
4168 freezelist.insert (pl);
4173 TimeAxisView* tv = &(*x)->get_time_axis_view();
4174 vector<PlaylistMapping>::iterator z;
4176 for (z = pmap.begin(); z != pmap.end(); ++z) {
4177 if ((*z).tv == tv) {
4182 if (z == pmap.end()) {
4183 pmap.push_back (PlaylistMapping (tv));
4187 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ) {
4189 boost::shared_ptr<Playlist> pl = (*x)->region()->playlist();
4192 /* region not yet associated with a playlist (e.g. unfinished
4199 TimeAxisView& tv = (*x)->get_time_axis_view();
4200 boost::shared_ptr<Playlist> npl;
4201 RegionSelection::iterator tmp;
4208 vector<PlaylistMapping>::iterator z;
4210 for (z = pmap.begin(); z != pmap.end(); ++z) {
4211 if ((*z).tv == &tv) {
4216 assert (z != pmap.end());
4219 npl = PlaylistFactory::create (pl->data_type(), *_session, "cutlist", true);
4227 boost::shared_ptr<Region> r = (*x)->region();
4228 boost::shared_ptr<Region> _xx;
4234 pl->remove_region (r);
4235 if (Config->get_edit_mode() == Ripple)
4236 pl->ripple (r->position(), -r->length(), boost::shared_ptr<Region>());
4240 _xx = RegionFactory::create (r);
4241 npl->add_region (_xx, r->position() - first_position);
4242 pl->remove_region (r);
4243 if (Config->get_edit_mode() == Ripple)
4244 pl->ripple (r->position(), -r->length(), boost::shared_ptr<Region>());
4248 /* copy region before adding, so we're not putting same object into two different playlists */
4249 npl->add_region (RegionFactory::create (r), r->position() - first_position);
4253 pl->remove_region (r);
4254 if (Config->get_edit_mode() == Ripple)
4255 pl->ripple (r->position(), -r->length(), boost::shared_ptr<Region>());
4264 list<boost::shared_ptr<Playlist> > foo;
4266 /* the pmap is in the same order as the tracks in which selected regions occured */
4268 for (vector<PlaylistMapping>::iterator i = pmap.begin(); i != pmap.end(); ++i) {
4271 foo.push_back ((*i).pl);
4276 cut_buffer->set (foo);
4280 _last_cut_copy_source_track = 0;
4282 _last_cut_copy_source_track = pmap.front().tv;
4286 for (FreezeList::iterator pl = freezelist.begin(); pl != freezelist.end(); ++pl) {
4289 /* We might have removed regions, which alters other regions' layering_index,
4290 so we need to do a recursive diff here.
4292 vector<Command*> cmds;
4293 (*pl)->rdiff (cmds);
4294 _session->add_commands (cmds);
4296 _session->add_command (new StatefulDiffCommand (*pl));
4301 Editor::cut_copy_ranges (CutCopyOp op)
4303 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4305 /* Sort the track selection now, so that it if is used, the playlists
4306 selected by the calls below to cut_copy_clear are in the order that
4307 their tracks appear in the editor. This makes things like paste
4308 of ranges work properly.
4311 sort_track_selection (ts);
4314 if (!entered_track) {
4317 ts.push_back (entered_track);
4320 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4321 (*i)->cut_copy_clear (*selection, op);
4326 Editor::paste (float times, bool from_context)
4328 DEBUG_TRACE (DEBUG::CutNPaste, "paste to preferred edit pos\n");
4330 paste_internal (get_preferred_edit_position (false, from_context), times);
4334 Editor::mouse_paste ()
4339 if (!mouse_frame (where, ignored)) {
4344 paste_internal (where, 1);
4348 Editor::paste_internal (framepos_t position, float times)
4350 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("apparent paste position is %1\n", position));
4352 if (internal_editing()) {
4353 if (cut_buffer->midi_notes.empty()) {
4357 if (cut_buffer->empty()) {
4362 if (position == max_framepos) {
4363 position = get_preferred_edit_position();
4364 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("preferred edit position is %1\n", position));
4368 TrackViewList::iterator i;
4371 /* get everything in the correct order */
4373 if (_edit_point == Editing::EditAtMouse && entered_track) {
4374 /* With the mouse edit point, paste onto the track under the mouse */
4375 ts.push_back (entered_track);
4376 } else if (!selection->tracks.empty()) {
4377 /* Otherwise, if there are some selected tracks, paste to them */
4378 ts = selection->tracks.filter_to_unique_playlists ();
4379 sort_track_selection (ts);
4380 } else if (_last_cut_copy_source_track) {
4381 /* Otherwise paste to the track that the cut/copy came from;
4382 see discussion in mantis #3333.
4384 ts.push_back (_last_cut_copy_source_track);
4387 if (internal_editing ()) {
4389 /* undo/redo is handled by individual tracks/regions */
4391 for (nth = 0, i = ts.begin(); i != ts.end(); ++i, ++nth) {
4394 RegionSelection::iterator r;
4395 MidiNoteSelection::iterator cb;
4397 get_regions_at (rs, position, ts);
4399 for (cb = cut_buffer->midi_notes.begin(), r = rs.begin();
4400 cb != cut_buffer->midi_notes.end() && r != rs.end(); ++r) {
4401 MidiRegionView* mrv = dynamic_cast<MidiRegionView*> (*r);
4403 mrv->paste (position, times, **cb);
4411 /* we do redo (do you do voodoo?) */
4413 begin_reversible_command (Operations::paste);
4415 for (nth = 0, i = ts.begin(); i != ts.end(); ++i, ++nth) {
4416 (*i)->paste (position, times, *cut_buffer, nth);
4419 commit_reversible_command ();
4424 Editor::duplicate_some_regions (RegionSelection& regions, float times)
4426 boost::shared_ptr<Playlist> playlist;
4427 RegionSelection sel = regions; // clear (below) may clear the argument list if its the current region selection
4428 RegionSelection foo;
4430 framepos_t const start_frame = regions.start ();
4431 framepos_t const end_frame = regions.end_frame ();
4433 begin_reversible_command (Operations::duplicate_region);
4435 selection->clear_regions ();
4437 for (RegionSelection::iterator i = sel.begin(); i != sel.end(); ++i) {
4439 boost::shared_ptr<Region> r ((*i)->region());
4441 TimeAxisView& tv = (*i)->get_time_axis_view();
4442 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (&tv);
4443 latest_regionviews.clear ();
4444 sigc::connection c = rtv->view()->RegionViewAdded.connect (sigc::mem_fun(*this, &Editor::collect_new_region_view));
4446 playlist = (*i)->region()->playlist();
4447 playlist->clear_changes ();
4448 playlist->duplicate (r, end_frame + (r->first_frame() - start_frame), times);
4449 _session->add_command(new StatefulDiffCommand (playlist));
4453 foo.insert (foo.end(), latest_regionviews.begin(), latest_regionviews.end());
4456 commit_reversible_command ();
4459 selection->set (foo);
4464 Editor::duplicate_selection (float times)
4466 if (selection->time.empty() || selection->tracks.empty()) {
4470 boost::shared_ptr<Playlist> playlist;
4471 vector<boost::shared_ptr<Region> > new_regions;
4472 vector<boost::shared_ptr<Region> >::iterator ri;
4474 create_region_from_selection (new_regions);
4476 if (new_regions.empty()) {
4480 begin_reversible_command (_("duplicate selection"));
4482 ri = new_regions.begin();
4484 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4486 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4487 if ((playlist = (*i)->playlist()) == 0) {
4490 playlist->clear_changes ();
4491 playlist->duplicate (*ri, selection->time[clicked_selection].end, times);
4492 _session->add_command (new StatefulDiffCommand (playlist));
4495 if (ri == new_regions.end()) {
4500 commit_reversible_command ();
4503 /** Reset all selected points to the relevant default value */
4505 Editor::reset_point_selection ()
4507 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
4508 ARDOUR::AutomationList::iterator j = (*i)->model ();
4509 (*j)->value = (*i)->line().the_list()->default_value ();
4514 Editor::center_playhead ()
4516 float const page = _visible_canvas_width * samples_per_pixel;
4517 center_screen_internal (playhead_cursor->current_frame (), page);
4521 Editor::center_edit_point ()
4523 float const page = _visible_canvas_width * samples_per_pixel;
4524 center_screen_internal (get_preferred_edit_position(), page);
4527 /** Caller must begin and commit a reversible command */
4529 Editor::clear_playlist (boost::shared_ptr<Playlist> playlist)
4531 playlist->clear_changes ();
4533 _session->add_command (new StatefulDiffCommand (playlist));
4537 Editor::nudge_track (bool use_edit, bool forwards)
4539 boost::shared_ptr<Playlist> playlist;
4540 framepos_t distance;
4541 framepos_t next_distance;
4545 start = get_preferred_edit_position();
4550 if ((distance = get_nudge_distance (start, next_distance)) == 0) {
4554 if (selection->tracks.empty()) {
4558 begin_reversible_command (_("nudge track"));
4560 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4562 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4564 if ((playlist = (*i)->playlist()) == 0) {
4568 playlist->clear_changes ();
4569 playlist->clear_owned_changes ();
4571 playlist->nudge_after (start, distance, forwards);
4573 vector<Command*> cmds;
4575 playlist->rdiff (cmds);
4576 _session->add_commands (cmds);
4578 _session->add_command (new StatefulDiffCommand (playlist));
4581 commit_reversible_command ();
4585 Editor::remove_last_capture ()
4587 vector<string> choices;
4594 if (Config->get_verify_remove_last_capture()) {
4595 prompt = _("Do you really want to destroy the last capture?"
4596 "\n(This is destructive and cannot be undone)");
4598 choices.push_back (_("No, do nothing."));
4599 choices.push_back (_("Yes, destroy it."));
4601 Gtkmm2ext::Choice prompter (_("Destroy last capture"), prompt, choices);
4603 if (prompter.run () == 1) {
4604 _session->remove_last_capture ();
4605 _regions->redisplay ();
4609 _session->remove_last_capture();
4610 _regions->redisplay ();
4615 Editor::normalize_region ()
4621 RegionSelection rs = get_regions_from_selection_and_entered ();
4627 NormalizeDialog dialog (rs.size() > 1);
4629 if (dialog.run () == RESPONSE_CANCEL) {
4633 set_canvas_cursor (_cursors->wait);
4636 /* XXX: should really only count audio regions here */
4637 int const regions = rs.size ();
4639 /* Make a list of the selected audio regions' maximum amplitudes, and also
4640 obtain the maximum amplitude of them all.
4642 list<double> max_amps;
4644 for (RegionSelection::const_iterator i = rs.begin(); i != rs.end(); ++i) {
4645 AudioRegionView const * arv = dynamic_cast<AudioRegionView const *> (*i);
4647 dialog.descend (1.0 / regions);
4648 double const a = arv->audio_region()->maximum_amplitude (&dialog);
4651 /* the user cancelled the operation */
4652 set_canvas_cursor (current_canvas_cursor);
4656 max_amps.push_back (a);
4657 max_amp = max (max_amp, a);
4662 begin_reversible_command (_("normalize"));
4664 list<double>::const_iterator a = max_amps.begin ();
4666 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
4667 AudioRegionView* const arv = dynamic_cast<AudioRegionView*> (*r);
4672 arv->region()->clear_changes ();
4674 double const amp = dialog.normalize_individually() ? *a : max_amp;
4676 arv->audio_region()->normalize (amp, dialog.target ());
4677 _session->add_command (new StatefulDiffCommand (arv->region()));
4682 commit_reversible_command ();
4683 set_canvas_cursor (current_canvas_cursor);
4688 Editor::reset_region_scale_amplitude ()
4694 RegionSelection rs = get_regions_from_selection_and_entered ();
4700 begin_reversible_command ("reset gain");
4702 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
4703 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
4706 arv->region()->clear_changes ();
4707 arv->audio_region()->set_scale_amplitude (1.0f);
4708 _session->add_command (new StatefulDiffCommand (arv->region()));
4711 commit_reversible_command ();
4715 Editor::adjust_region_gain (bool up)
4717 RegionSelection rs = get_regions_from_selection_and_entered ();
4719 if (!_session || rs.empty()) {
4723 begin_reversible_command ("adjust region gain");
4725 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
4726 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
4731 arv->region()->clear_changes ();
4733 double dB = accurate_coefficient_to_dB (arv->audio_region()->scale_amplitude ());
4741 arv->audio_region()->set_scale_amplitude (dB_to_coefficient (dB));
4742 _session->add_command (new StatefulDiffCommand (arv->region()));
4745 commit_reversible_command ();
4750 Editor::reverse_region ()
4756 Reverse rev (*_session);
4757 apply_filter (rev, _("reverse regions"));
4761 Editor::strip_region_silence ()
4767 RegionSelection rs = get_regions_from_selection_and_entered ();
4773 std::list<RegionView*> audio_only;
4775 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
4776 AudioRegionView* const arv = dynamic_cast<AudioRegionView*> (*i);
4778 audio_only.push_back (arv);
4782 StripSilenceDialog d (_session, audio_only);
4783 int const r = d.run ();
4787 if (r == Gtk::RESPONSE_OK) {
4788 ARDOUR::AudioIntervalMap silences;
4789 d.silences (silences);
4790 StripSilence s (*_session, silences, d.fade_length());
4791 apply_filter (s, _("strip silence"), &d);
4796 Editor::apply_midi_note_edit_op_to_region (MidiOperator& op, MidiRegionView& mrv)
4798 Evoral::Sequence<Evoral::MusicalTime>::Notes selected;
4799 mrv.selection_as_notelist (selected, true);
4801 vector<Evoral::Sequence<Evoral::MusicalTime>::Notes> v;
4802 v.push_back (selected);
4804 framepos_t pos_frames = mrv.midi_region()->position() - mrv.midi_region()->start();
4805 double pos_beats = _session->tempo_map().framewalk_to_beats(0, pos_frames);
4807 return op (mrv.midi_region()->model(), pos_beats, v);
4811 Editor::apply_midi_note_edit_op (MidiOperator& op)
4815 RegionSelection rs = get_regions_from_selection_and_entered ();
4821 begin_reversible_command (op.name ());
4823 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
4824 RegionSelection::iterator tmp = r;
4827 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*r);
4830 cmd = apply_midi_note_edit_op_to_region (op, *mrv);
4833 _session->add_command (cmd);
4840 commit_reversible_command ();
4844 Editor::fork_region ()
4846 RegionSelection rs = get_regions_from_selection_and_entered ();
4852 begin_reversible_command (_("Fork Region(s)"));
4854 set_canvas_cursor (_cursors->wait);
4857 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
4858 RegionSelection::iterator tmp = r;
4861 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*>(*r);
4865 boost::shared_ptr<Playlist> playlist = mrv->region()->playlist();
4866 boost::shared_ptr<MidiSource> new_source = _session->create_midi_source_by_stealing_name (mrv->midi_view()->track());
4867 boost::shared_ptr<MidiRegion> newregion = mrv->midi_region()->clone (new_source);
4869 playlist->clear_changes ();
4870 playlist->replace_region (mrv->region(), newregion, mrv->region()->position());
4871 _session->add_command(new StatefulDiffCommand (playlist));
4873 error << string_compose (_("Could not unlink %1"), mrv->region()->name()) << endmsg;
4880 commit_reversible_command ();
4882 set_canvas_cursor (current_canvas_cursor);
4886 Editor::quantize_region ()
4888 int selected_midi_region_cnt = 0;
4894 RegionSelection rs = get_regions_from_selection_and_entered ();
4900 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
4901 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*r);
4903 selected_midi_region_cnt++;
4907 if (selected_midi_region_cnt == 0) {
4911 QuantizeDialog* qd = new QuantizeDialog (*this);
4914 const int r = qd->run ();
4917 if (r == Gtk::RESPONSE_OK) {
4918 Quantize quant (*_session, qd->snap_start(), qd->snap_end(),
4919 qd->start_grid_size(), qd->end_grid_size(),
4920 qd->strength(), qd->swing(), qd->threshold());
4922 apply_midi_note_edit_op (quant);
4927 Editor::insert_patch_change (bool from_context)
4929 RegionSelection rs = get_regions_from_selection_and_entered ();
4935 const framepos_t p = get_preferred_edit_position (false, from_context);
4937 /* XXX: bit of a hack; use the MIDNAM from the first selected region;
4938 there may be more than one, but the PatchChangeDialog can only offer
4939 one set of patch menus.
4941 MidiRegionView* first = dynamic_cast<MidiRegionView*> (rs.front ());
4943 Evoral::PatchChange<Evoral::MusicalTime> empty (0, 0, 0, 0);
4944 PatchChangeDialog d (0, _session, empty, first->instrument_info(), Gtk::Stock::ADD);
4946 if (d.run() == RESPONSE_CANCEL) {
4950 for (RegionSelection::iterator i = rs.begin (); i != rs.end(); ++i) {
4951 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*i);
4953 if (p >= mrv->region()->first_frame() && p <= mrv->region()->last_frame()) {
4954 mrv->add_patch_change (p - mrv->region()->position(), d.patch ());
4961 Editor::apply_filter (Filter& filter, string command, ProgressReporter* progress)
4963 RegionSelection rs = get_regions_from_selection_and_entered ();
4969 begin_reversible_command (command);
4971 set_canvas_cursor (_cursors->wait);
4975 int const N = rs.size ();
4977 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
4978 RegionSelection::iterator tmp = r;
4981 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
4983 boost::shared_ptr<Playlist> playlist = arv->region()->playlist();
4986 progress->descend (1.0 / N);
4989 if (arv->audio_region()->apply (filter, progress) == 0) {
4991 playlist->clear_changes ();
4992 playlist->clear_owned_changes ();
4994 if (filter.results.empty ()) {
4996 /* no regions returned; remove the old one */
4997 playlist->remove_region (arv->region ());
5001 std::vector<boost::shared_ptr<Region> >::iterator res = filter.results.begin ();
5003 /* first region replaces the old one */
5004 playlist->replace_region (arv->region(), *res, (*res)->position());
5008 while (res != filter.results.end()) {
5009 playlist->add_region (*res, (*res)->position());
5015 /* We might have removed regions, which alters other regions' layering_index,
5016 so we need to do a recursive diff here.
5018 vector<Command*> cmds;
5019 playlist->rdiff (cmds);
5020 _session->add_commands (cmds);
5022 _session->add_command(new StatefulDiffCommand (playlist));
5028 progress->ascend ();
5036 commit_reversible_command ();
5039 set_canvas_cursor (current_canvas_cursor);
5043 Editor::external_edit_region ()
5049 Editor::reset_region_gain_envelopes ()
5051 RegionSelection rs = get_regions_from_selection_and_entered ();
5053 if (!_session || rs.empty()) {
5057 _session->begin_reversible_command (_("reset region gain"));
5059 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5060 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
5062 boost::shared_ptr<AutomationList> alist (arv->audio_region()->envelope());
5063 XMLNode& before (alist->get_state());
5065 arv->audio_region()->set_default_envelope ();
5066 _session->add_command (new MementoCommand<AutomationList>(*arv->audio_region()->envelope().get(), &before, &alist->get_state()));
5070 _session->commit_reversible_command ();
5074 Editor::set_region_gain_visibility (RegionView* rv)
5076 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (rv);
5078 arv->update_envelope_visibility();
5083 Editor::set_gain_envelope_visibility ()
5089 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5090 AudioTimeAxisView* v = dynamic_cast<AudioTimeAxisView*>(*i);
5092 v->audio_view()->foreach_regionview (sigc::mem_fun (this, &Editor::set_region_gain_visibility));
5098 Editor::toggle_gain_envelope_active ()
5100 if (_ignore_region_action) {
5104 RegionSelection rs = get_regions_from_selection_and_entered ();
5106 if (!_session || rs.empty()) {
5110 _session->begin_reversible_command (_("region gain envelope active"));
5112 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5113 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
5115 arv->region()->clear_changes ();
5116 arv->audio_region()->set_envelope_active (!arv->audio_region()->envelope_active());
5117 _session->add_command (new StatefulDiffCommand (arv->region()));
5121 _session->commit_reversible_command ();
5125 Editor::toggle_region_lock ()
5127 if (_ignore_region_action) {
5131 RegionSelection rs = get_regions_from_selection_and_entered ();
5133 if (!_session || rs.empty()) {
5137 _session->begin_reversible_command (_("toggle region lock"));
5139 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5140 (*i)->region()->clear_changes ();
5141 (*i)->region()->set_locked (!(*i)->region()->locked());
5142 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5145 _session->commit_reversible_command ();
5149 Editor::toggle_region_video_lock ()
5151 if (_ignore_region_action) {
5155 RegionSelection rs = get_regions_from_selection_and_entered ();
5157 if (!_session || rs.empty()) {
5161 _session->begin_reversible_command (_("Toggle Video Lock"));
5163 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5164 (*i)->region()->clear_changes ();
5165 (*i)->region()->set_video_locked (!(*i)->region()->video_locked());
5166 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5169 _session->commit_reversible_command ();
5173 Editor::toggle_region_lock_style ()
5175 if (_ignore_region_action) {
5179 RegionSelection rs = get_regions_from_selection_and_entered ();
5181 if (!_session || rs.empty()) {
5185 _session->begin_reversible_command (_("region lock style"));
5187 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5188 (*i)->region()->clear_changes ();
5189 PositionLockStyle const ns = (*i)->region()->position_lock_style() == AudioTime ? MusicTime : AudioTime;
5190 (*i)->region()->set_position_lock_style (ns);
5191 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5194 _session->commit_reversible_command ();
5198 Editor::toggle_opaque_region ()
5200 if (_ignore_region_action) {
5204 RegionSelection rs = get_regions_from_selection_and_entered ();
5206 if (!_session || rs.empty()) {
5210 _session->begin_reversible_command (_("change region opacity"));
5212 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5213 (*i)->region()->clear_changes ();
5214 (*i)->region()->set_opaque (!(*i)->region()->opaque());
5215 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5218 _session->commit_reversible_command ();
5222 Editor::toggle_record_enable ()
5224 bool new_state = false;
5226 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5227 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5230 if (!rtav->is_track())
5234 new_state = !rtav->track()->record_enabled();
5238 rtav->track()->set_record_enabled (new_state, this);
5243 Editor::toggle_solo ()
5245 bool new_state = false;
5247 boost::shared_ptr<RouteList> rl (new RouteList);
5249 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5250 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5257 new_state = !rtav->route()->soloed ();
5261 rl->push_back (rtav->route());
5264 _session->set_solo (rl, new_state, Session::rt_cleanup, true);
5268 Editor::toggle_mute ()
5270 bool new_state = false;
5272 boost::shared_ptr<RouteList> rl (new RouteList);
5274 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5275 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5282 new_state = !rtav->route()->muted();
5286 rl->push_back (rtav->route());
5289 _session->set_mute (rl, new_state, Session::rt_cleanup, true);
5293 Editor::toggle_solo_isolate ()
5299 Editor::fade_range ()
5301 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
5303 begin_reversible_command (_("fade range"));
5305 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
5306 (*i)->fade_range (selection->time);
5309 commit_reversible_command ();
5314 Editor::set_fade_length (bool in)
5316 RegionSelection rs = get_regions_from_selection_and_entered ();
5322 /* we need a region to measure the offset from the start */
5324 RegionView* rv = rs.front ();
5326 framepos_t pos = get_preferred_edit_position();
5330 if (pos > rv->region()->last_frame() || pos < rv->region()->first_frame()) {
5331 /* edit point is outside the relevant region */
5336 if (pos <= rv->region()->position()) {
5340 len = pos - rv->region()->position();
5341 cmd = _("set fade in length");
5343 if (pos >= rv->region()->last_frame()) {
5347 len = rv->region()->last_frame() - pos;
5348 cmd = _("set fade out length");
5351 begin_reversible_command (cmd);
5353 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5354 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5360 boost::shared_ptr<AutomationList> alist;
5362 alist = tmp->audio_region()->fade_in();
5364 alist = tmp->audio_region()->fade_out();
5367 XMLNode &before = alist->get_state();
5370 tmp->audio_region()->set_fade_in_length (len);
5371 tmp->audio_region()->set_fade_in_active (true);
5373 tmp->audio_region()->set_fade_out_length (len);
5374 tmp->audio_region()->set_fade_out_active (true);
5377 XMLNode &after = alist->get_state();
5378 _session->add_command(new MementoCommand<AutomationList>(*alist, &before, &after));
5381 commit_reversible_command ();
5385 Editor::set_fade_in_shape (FadeShape shape)
5387 RegionSelection rs = get_regions_from_selection_and_entered ();
5393 begin_reversible_command (_("set fade in shape"));
5395 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5396 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5402 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_in();
5403 XMLNode &before = alist->get_state();
5405 tmp->audio_region()->set_fade_in_shape (shape);
5407 XMLNode &after = alist->get_state();
5408 _session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
5411 commit_reversible_command ();
5416 Editor::set_fade_out_shape (FadeShape shape)
5418 RegionSelection rs = get_regions_from_selection_and_entered ();
5424 begin_reversible_command (_("set fade out shape"));
5426 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5427 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5433 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_out();
5434 XMLNode &before = alist->get_state();
5436 tmp->audio_region()->set_fade_out_shape (shape);
5438 XMLNode &after = alist->get_state();
5439 _session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
5442 commit_reversible_command ();
5446 Editor::set_fade_in_active (bool yn)
5448 RegionSelection rs = get_regions_from_selection_and_entered ();
5454 begin_reversible_command (_("set fade in active"));
5456 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5457 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5464 boost::shared_ptr<AudioRegion> ar (tmp->audio_region());
5466 ar->clear_changes ();
5467 ar->set_fade_in_active (yn);
5468 _session->add_command (new StatefulDiffCommand (ar));
5471 commit_reversible_command ();
5475 Editor::set_fade_out_active (bool yn)
5477 RegionSelection rs = get_regions_from_selection_and_entered ();
5483 begin_reversible_command (_("set fade out active"));
5485 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5486 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5492 boost::shared_ptr<AudioRegion> ar (tmp->audio_region());
5494 ar->clear_changes ();
5495 ar->set_fade_out_active (yn);
5496 _session->add_command(new StatefulDiffCommand (ar));
5499 commit_reversible_command ();
5503 Editor::toggle_region_fades (int dir)
5505 if (_ignore_region_action) {
5509 boost::shared_ptr<AudioRegion> ar;
5512 RegionSelection rs = get_regions_from_selection_and_entered ();
5518 RegionSelection::iterator i;
5519 for (i = rs.begin(); i != rs.end(); ++i) {
5520 if ((ar = boost::dynamic_pointer_cast<AudioRegion>((*i)->region())) != 0) {
5522 yn = ar->fade_out_active ();
5524 yn = ar->fade_in_active ();
5530 if (i == rs.end()) {
5534 /* XXX should this undo-able? */
5536 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5537 if ((ar = boost::dynamic_pointer_cast<AudioRegion>((*i)->region())) == 0) {
5540 if (dir == 1 || dir == 0) {
5541 ar->set_fade_in_active (!yn);
5544 if (dir == -1 || dir == 0) {
5545 ar->set_fade_out_active (!yn);
5551 /** Update region fade visibility after its configuration has been changed */
5553 Editor::update_region_fade_visibility ()
5555 bool _fade_visibility = _session->config.get_show_region_fades ();
5557 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5558 AudioTimeAxisView* v = dynamic_cast<AudioTimeAxisView*>(*i);
5560 if (_fade_visibility) {
5561 v->audio_view()->show_all_fades ();
5563 v->audio_view()->hide_all_fades ();
5570 Editor::set_edit_point ()
5575 if (!mouse_frame (where, ignored)) {
5581 if (selection->markers.empty()) {
5583 mouse_add_new_marker (where);
5588 Location* loc = find_location_from_marker (selection->markers.front(), ignored);
5591 loc->move_to (where);
5597 Editor::set_playhead_cursor ()
5599 if (entered_marker) {
5600 _session->request_locate (entered_marker->position(), _session->transport_rolling());
5605 if (!mouse_frame (where, ignored)) {
5612 _session->request_locate (where, _session->transport_rolling());
5616 if ( Config->get_follow_edits() )
5617 cancel_time_selection();
5621 Editor::split_region ()
5623 if ( !selection->time.empty()) {
5624 separate_regions_between (selection->time);
5628 RegionSelection rs = get_regions_from_selection_and_edit_point ();
5630 framepos_t where = get_preferred_edit_position ();
5636 split_regions_at (where, rs);
5639 struct EditorOrderRouteSorter {
5640 bool operator() (boost::shared_ptr<Route> a, boost::shared_ptr<Route> b) {
5641 return a->order_key () < b->order_key ();
5646 Editor::select_next_route()
5648 if (selection->tracks.empty()) {
5649 selection->set (track_views.front());
5653 TimeAxisView* current = selection->tracks.front();
5657 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5658 if (*i == current) {
5660 if (i != track_views.end()) {
5663 current = (*(track_views.begin()));
5664 //selection->set (*(track_views.begin()));
5669 rui = dynamic_cast<RouteUI *>(current);
5670 } while ( current->hidden() || (rui != NULL && !rui->route()->active()));
5672 selection->set(current);
5674 ensure_time_axis_view_is_visible (*current, false);
5678 Editor::select_prev_route()
5680 if (selection->tracks.empty()) {
5681 selection->set (track_views.front());
5685 TimeAxisView* current = selection->tracks.front();
5689 for (TrackViewList::reverse_iterator i = track_views.rbegin(); i != track_views.rend(); ++i) {
5690 if (*i == current) {
5692 if (i != track_views.rend()) {
5695 current = *(track_views.rbegin());
5700 rui = dynamic_cast<RouteUI *>(current);
5701 } while ( current->hidden() || (rui != NULL && !rui->route()->active()));
5703 selection->set (current);
5705 ensure_time_axis_view_is_visible (*current, false);
5709 Editor::set_loop_from_selection (bool play)
5711 if (_session == 0 || selection->time.empty()) {
5715 framepos_t start = selection->time[clicked_selection].start;
5716 framepos_t end = selection->time[clicked_selection].end;
5718 set_loop_range (start, end, _("set loop range from selection"));
5721 _session->request_locate (start, true);
5722 _session->request_play_loop (true);
5727 Editor::set_loop_from_edit_range (bool play)
5729 if (_session == 0) {
5736 if (!get_edit_op_range (start, end)) {
5740 set_loop_range (start, end, _("set loop range from edit range"));
5743 _session->request_locate (start, true);
5744 _session->request_play_loop (true);
5749 Editor::set_loop_from_region (bool play)
5751 framepos_t start = max_framepos;
5754 RegionSelection rs = get_regions_from_selection_and_entered ();
5760 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5761 if ((*i)->region()->position() < start) {
5762 start = (*i)->region()->position();
5764 if ((*i)->region()->last_frame() + 1 > end) {
5765 end = (*i)->region()->last_frame() + 1;
5769 set_loop_range (start, end, _("set loop range from region"));
5772 _session->request_locate (start, true);
5773 _session->request_play_loop (true);
5778 Editor::set_punch_from_selection ()
5780 if (_session == 0 || selection->time.empty()) {
5784 framepos_t start = selection->time[clicked_selection].start;
5785 framepos_t end = selection->time[clicked_selection].end;
5787 set_punch_range (start, end, _("set punch range from selection"));
5791 Editor::set_punch_from_edit_range ()
5793 if (_session == 0) {
5800 if (!get_edit_op_range (start, end)) {
5804 set_punch_range (start, end, _("set punch range from edit range"));
5808 Editor::set_punch_from_region ()
5810 framepos_t start = max_framepos;
5813 RegionSelection rs = get_regions_from_selection_and_entered ();
5819 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5820 if ((*i)->region()->position() < start) {
5821 start = (*i)->region()->position();
5823 if ((*i)->region()->last_frame() + 1 > end) {
5824 end = (*i)->region()->last_frame() + 1;
5828 set_punch_range (start, end, _("set punch range from region"));
5832 Editor::pitch_shift_region ()
5834 RegionSelection rs = get_regions_from_selection_and_entered ();
5836 RegionSelection audio_rs;
5837 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5838 if (dynamic_cast<AudioRegionView*> (*i)) {
5839 audio_rs.push_back (*i);
5843 if (audio_rs.empty()) {
5847 pitch_shift (audio_rs, 1.2);
5851 Editor::transpose_region ()
5853 RegionSelection rs = get_regions_from_selection_and_entered ();
5855 list<MidiRegionView*> midi_region_views;
5856 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5857 MidiRegionView* mrv = dynamic_cast<MidiRegionView*> (*i);
5859 midi_region_views.push_back (mrv);
5864 int const r = d.run ();
5865 if (r != RESPONSE_ACCEPT) {
5869 for (list<MidiRegionView*>::iterator i = midi_region_views.begin(); i != midi_region_views.end(); ++i) {
5870 (*i)->midi_region()->transpose (d.semitones ());
5875 Editor::set_tempo_from_region ()
5877 RegionSelection rs = get_regions_from_selection_and_entered ();
5879 if (!_session || rs.empty()) {
5883 RegionView* rv = rs.front();
5885 define_one_bar (rv->region()->position(), rv->region()->last_frame() + 1);
5889 Editor::use_range_as_bar ()
5891 framepos_t start, end;
5892 if (get_edit_op_range (start, end)) {
5893 define_one_bar (start, end);
5898 Editor::define_one_bar (framepos_t start, framepos_t end)
5900 framepos_t length = end - start;
5902 const Meter& m (_session->tempo_map().meter_at (start));
5904 /* length = 1 bar */
5906 /* now we want frames per beat.
5907 we have frames per bar, and beats per bar, so ...
5910 /* XXXX METER MATH */
5912 double frames_per_beat = length / m.divisions_per_bar();
5914 /* beats per minute = */
5916 double beats_per_minute = (_session->frame_rate() * 60.0) / frames_per_beat;
5918 /* now decide whether to:
5920 (a) set global tempo
5921 (b) add a new tempo marker
5925 const TempoSection& t (_session->tempo_map().tempo_section_at (start));
5927 bool do_global = false;
5929 if ((_session->tempo_map().n_tempos() == 1) && (_session->tempo_map().n_meters() == 1)) {
5931 /* only 1 tempo & 1 meter: ask if the user wants to set the tempo
5932 at the start, or create a new marker
5935 vector<string> options;
5936 options.push_back (_("Cancel"));
5937 options.push_back (_("Add new marker"));
5938 options.push_back (_("Set global tempo"));
5941 _("Define one bar"),
5942 _("Do you want to set the global tempo or add a new tempo marker?"),
5946 c.set_default_response (2);
5962 /* more than 1 tempo and/or meter section already, go ahead do the "usual":
5963 if the marker is at the region starter, change it, otherwise add
5968 begin_reversible_command (_("set tempo from region"));
5969 XMLNode& before (_session->tempo_map().get_state());
5972 _session->tempo_map().change_initial_tempo (beats_per_minute, t.note_type());
5973 } else if (t.frame() == start) {
5974 _session->tempo_map().change_existing_tempo_at (start, beats_per_minute, t.note_type());
5976 Timecode::BBT_Time bbt;
5977 _session->tempo_map().bbt_time (start, bbt);
5978 _session->tempo_map().add_tempo (Tempo (beats_per_minute, t.note_type()), bbt);
5981 XMLNode& after (_session->tempo_map().get_state());
5983 _session->add_command (new MementoCommand<TempoMap>(_session->tempo_map(), &before, &after));
5984 commit_reversible_command ();
5988 Editor::split_region_at_transients ()
5990 AnalysisFeatureList positions;
5992 RegionSelection rs = get_regions_from_selection_and_entered ();
5994 if (!_session || rs.empty()) {
5998 _session->begin_reversible_command (_("split regions"));
6000 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ) {
6002 RegionSelection::iterator tmp;
6007 boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion> ((*i)->region());
6009 if (ar && (ar->get_transients (positions) == 0)) {
6010 split_region_at_points ((*i)->region(), positions, true);
6017 _session->commit_reversible_command ();
6022 Editor::split_region_at_points (boost::shared_ptr<Region> r, AnalysisFeatureList& positions, bool can_ferret, bool select_new)
6024 bool use_rhythmic_rodent = false;
6026 boost::shared_ptr<Playlist> pl = r->playlist();
6028 list<boost::shared_ptr<Region> > new_regions;
6034 if (positions.empty()) {
6039 if (positions.size() > 20 && can_ferret) {
6040 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);
6041 MessageDialog msg (msgstr,
6044 Gtk::BUTTONS_OK_CANCEL);
6047 msg.add_button (_("Call for the Ferret!"), RESPONSE_APPLY);
6048 msg.set_secondary_text (_("Press OK to continue with this split operation\nor ask the Ferret dialog to tune the analysis"));
6050 msg.set_secondary_text (_("Press OK to continue with this split operation"));
6053 msg.set_title (_("Excessive split?"));
6056 int response = msg.run();
6062 case RESPONSE_APPLY:
6063 use_rhythmic_rodent = true;
6070 if (use_rhythmic_rodent) {
6071 show_rhythm_ferret ();
6075 AnalysisFeatureList::const_iterator x;
6077 pl->clear_changes ();
6078 pl->clear_owned_changes ();
6080 x = positions.begin();
6082 if (x == positions.end()) {
6087 pl->remove_region (r);
6091 while (x != positions.end()) {
6093 /* deal with positons that are out of scope of present region bounds */
6094 if (*x <= 0 || *x > r->length()) {
6099 /* file start = original start + how far we from the initial position ?
6102 framepos_t file_start = r->start() + pos;
6104 /* length = next position - current position
6107 framepos_t len = (*x) - pos;
6109 /* XXX we do we really want to allow even single-sample regions?
6110 shouldn't we have some kind of lower limit on region size?
6119 if (RegionFactory::region_name (new_name, r->name())) {
6123 /* do NOT announce new regions 1 by one, just wait till they are all done */
6127 plist.add (ARDOUR::Properties::start, file_start);
6128 plist.add (ARDOUR::Properties::length, len);
6129 plist.add (ARDOUR::Properties::name, new_name);
6130 plist.add (ARDOUR::Properties::layer, 0);
6132 boost::shared_ptr<Region> nr = RegionFactory::create (r->sources(), plist, false);
6133 /* because we set annouce to false, manually add the new region to the
6136 RegionFactory::map_add (nr);
6138 pl->add_region (nr, r->position() + pos);
6141 new_regions.push_front(nr);
6150 RegionFactory::region_name (new_name, r->name());
6152 /* Add the final region */
6155 plist.add (ARDOUR::Properties::start, r->start() + pos);
6156 plist.add (ARDOUR::Properties::length, r->last_frame() - (r->position() + pos) + 1);
6157 plist.add (ARDOUR::Properties::name, new_name);
6158 plist.add (ARDOUR::Properties::layer, 0);
6160 boost::shared_ptr<Region> nr = RegionFactory::create (r->sources(), plist, false);
6161 /* because we set annouce to false, manually add the new region to the
6164 RegionFactory::map_add (nr);
6165 pl->add_region (nr, r->position() + pos);
6168 new_regions.push_front(nr);
6173 /* We might have removed regions, which alters other regions' layering_index,
6174 so we need to do a recursive diff here.
6176 vector<Command*> cmds;
6178 _session->add_commands (cmds);
6180 _session->add_command (new StatefulDiffCommand (pl));
6184 for (list<boost::shared_ptr<Region> >::iterator i = new_regions.begin(); i != new_regions.end(); ++i){
6185 set_selected_regionview_from_region_list ((*i), Selection::Add);
6191 Editor::place_transient()
6197 RegionSelection rs = get_regions_from_selection_and_edit_point ();
6203 framepos_t where = get_preferred_edit_position();
6205 _session->begin_reversible_command (_("place transient"));
6207 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6208 framepos_t position = (*r)->region()->position();
6209 (*r)->region()->add_transient(where - position);
6212 _session->commit_reversible_command ();
6216 Editor::remove_transient(ArdourCanvas::Item* item)
6222 ArdourCanvas::Line* _line = reinterpret_cast<ArdourCanvas::Line*> (item);
6225 AudioRegionView* _arv = reinterpret_cast<AudioRegionView*> (item->get_data ("regionview"));
6226 _arv->remove_transient (*(float*) _line->get_data ("position"));
6230 Editor::snap_regions_to_grid ()
6232 list <boost::shared_ptr<Playlist > > used_playlists;
6234 RegionSelection rs = get_regions_from_selection_and_entered ();
6236 if (!_session || rs.empty()) {
6240 _session->begin_reversible_command (_("snap regions to grid"));
6242 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6244 boost::shared_ptr<Playlist> pl = (*r)->region()->playlist();
6246 if (!pl->frozen()) {
6247 /* we haven't seen this playlist before */
6249 /* remember used playlists so we can thaw them later */
6250 used_playlists.push_back(pl);
6254 framepos_t start_frame = (*r)->region()->first_frame ();
6255 snap_to (start_frame);
6256 (*r)->region()->set_position (start_frame);
6259 while (used_playlists.size() > 0) {
6260 list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
6262 used_playlists.pop_front();
6265 _session->commit_reversible_command ();
6269 Editor::close_region_gaps ()
6271 list <boost::shared_ptr<Playlist > > used_playlists;
6273 RegionSelection rs = get_regions_from_selection_and_entered ();
6275 if (!_session || rs.empty()) {
6279 Dialog dialog (_("Close Region Gaps"));
6282 table.set_spacings (12);
6283 table.set_border_width (12);
6284 Label* l = manage (left_aligned_label (_("Crossfade length")));
6285 table.attach (*l, 0, 1, 0, 1);
6287 SpinButton spin_crossfade (1, 0);
6288 spin_crossfade.set_range (0, 15);
6289 spin_crossfade.set_increments (1, 1);
6290 spin_crossfade.set_value (5);
6291 table.attach (spin_crossfade, 1, 2, 0, 1);
6293 table.attach (*manage (new Label (_("ms"))), 2, 3, 0, 1);
6295 l = manage (left_aligned_label (_("Pull-back length")));
6296 table.attach (*l, 0, 1, 1, 2);
6298 SpinButton spin_pullback (1, 0);
6299 spin_pullback.set_range (0, 100);
6300 spin_pullback.set_increments (1, 1);
6301 spin_pullback.set_value(30);
6302 table.attach (spin_pullback, 1, 2, 1, 2);
6304 table.attach (*manage (new Label (_("ms"))), 2, 3, 1, 2);
6306 dialog.get_vbox()->pack_start (table);
6307 dialog.add_button (Stock::CANCEL, RESPONSE_CANCEL);
6308 dialog.add_button (_("Ok"), RESPONSE_ACCEPT);
6311 if (dialog.run () == RESPONSE_CANCEL) {
6315 framepos_t crossfade_len = spin_crossfade.get_value();
6316 framepos_t pull_back_frames = spin_pullback.get_value();
6318 crossfade_len = lrintf (crossfade_len * _session->frame_rate()/1000);
6319 pull_back_frames = lrintf (pull_back_frames * _session->frame_rate()/1000);
6321 /* Iterate over the region list and make adjacent regions overlap by crossfade_len_ms */
6323 _session->begin_reversible_command (_("close region gaps"));
6326 boost::shared_ptr<Region> last_region;
6328 rs.sort_by_position_and_track();
6330 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6332 boost::shared_ptr<Playlist> pl = (*r)->region()->playlist();
6334 if (!pl->frozen()) {
6335 /* we haven't seen this playlist before */
6337 /* remember used playlists so we can thaw them later */
6338 used_playlists.push_back(pl);
6342 framepos_t position = (*r)->region()->position();
6344 if (idx == 0 || position < last_region->position()){
6345 last_region = (*r)->region();
6350 (*r)->region()->trim_front( (position - pull_back_frames));
6351 last_region->trim_end( (position - pull_back_frames + crossfade_len));
6353 last_region = (*r)->region();
6358 while (used_playlists.size() > 0) {
6359 list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
6361 used_playlists.pop_front();
6364 _session->commit_reversible_command ();
6368 Editor::tab_to_transient (bool forward)
6370 AnalysisFeatureList positions;
6372 RegionSelection rs = get_regions_from_selection_and_entered ();
6378 framepos_t pos = _session->audible_frame ();
6380 if (!selection->tracks.empty()) {
6382 /* don't waste time searching for transients in duplicate playlists.
6385 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
6387 for (TrackViewList::iterator t = ts.begin(); t != ts.end(); ++t) {
6389 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*t);
6392 boost::shared_ptr<Track> tr = rtv->track();
6394 boost::shared_ptr<Playlist> pl = tr->playlist ();
6396 framepos_t result = pl->find_next_transient (pos, forward ? 1 : -1);
6399 positions.push_back (result);
6412 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6413 (*r)->region()->get_transients (positions);
6417 TransientDetector::cleanup_transients (positions, _session->frame_rate(), 3.0);
6420 AnalysisFeatureList::iterator x;
6422 for (x = positions.begin(); x != positions.end(); ++x) {
6428 if (x != positions.end ()) {
6429 _session->request_locate (*x);
6433 AnalysisFeatureList::reverse_iterator x;
6435 for (x = positions.rbegin(); x != positions.rend(); ++x) {
6441 if (x != positions.rend ()) {
6442 _session->request_locate (*x);
6448 Editor::playhead_forward_to_grid ()
6454 framepos_t pos = playhead_cursor->current_frame ();
6455 if (pos < max_framepos - 1) {
6457 snap_to_internal (pos, 1, false);
6458 _session->request_locate (pos);
6464 Editor::playhead_backward_to_grid ()
6470 framepos_t pos = playhead_cursor->current_frame ();
6473 snap_to_internal (pos, -1, false);
6474 _session->request_locate (pos);
6479 Editor::set_track_height (Height h)
6481 TrackSelection& ts (selection->tracks);
6483 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
6484 (*x)->set_height_enum (h);
6489 Editor::toggle_tracks_active ()
6491 TrackSelection& ts (selection->tracks);
6493 bool target = false;
6499 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
6500 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*x);
6504 target = !rtv->_route->active();
6507 rtv->_route->set_active (target, this);
6513 Editor::remove_tracks ()
6515 TrackSelection& ts (selection->tracks);
6521 vector<string> choices;
6525 const char* trackstr;
6527 vector<boost::shared_ptr<Route> > routes;
6528 bool special_bus = false;
6530 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
6531 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*x);
6535 if (rtv->is_track()) {
6540 routes.push_back (rtv->_route);
6542 if (rtv->route()->is_master() || rtv->route()->is_monitor()) {
6547 if (special_bus && !Config->get_allow_special_bus_removal()) {
6548 MessageDialog msg (_("That would be bad news ...."),
6552 msg.set_secondary_text (string_compose (_(
6553 "Removing the master or monitor bus is such a bad idea\n\
6554 that %1 is not going to allow it.\n\
6556 If you really want to do this sort of thing\n\
6557 edit your ardour.rc file to set the\n\
6558 \"allow-special-bus-removal\" option to be \"yes\""), PROGRAM_NAME));
6565 if (ntracks + nbusses == 0) {
6569 // XXX should be using gettext plural forms, maybe?
6571 trackstr = _("tracks");
6573 trackstr = _("track");
6577 busstr = _("busses");
6584 prompt = string_compose (_("Do you really want to remove %1 %2 and %3 %4?\n"
6585 "(You may also lose the playlists associated with the %2)\n\n"
6586 "This action cannot be undone, and the session file will be overwritten!"),
6587 ntracks, trackstr, nbusses, busstr);
6589 prompt = string_compose (_("Do you really want to remove %1 %2?\n"
6590 "(You may also lose the playlists associated with the %2)\n\n"
6591 "This action cannot be undone, and the session file will be overwritten!"),
6594 } else if (nbusses) {
6595 prompt = string_compose (_("Do you really want to remove %1 %2?\n\n"
6596 "This action cannot be undone, and the session file will be overwritten"),
6600 choices.push_back (_("No, do nothing."));
6601 if (ntracks + nbusses > 1) {
6602 choices.push_back (_("Yes, remove them."));
6604 choices.push_back (_("Yes, remove it."));
6609 title = string_compose (_("Remove %1"), trackstr);
6611 title = string_compose (_("Remove %1"), busstr);
6614 Choice prompter (title, prompt, choices);
6616 if (prompter.run () != 1) {
6621 Session::StateProtector sp (_session);
6622 DisplaySuspender ds;
6623 for (vector<boost::shared_ptr<Route> >::iterator x = routes.begin(); x != routes.end(); ++x) {
6624 _session->remove_route (*x);
6630 Editor::do_insert_time ()
6632 if (selection->tracks.empty()) {
6636 InsertTimeDialog d (*this);
6637 int response = d.run ();
6639 if (response != RESPONSE_OK) {
6643 if (d.distance() == 0) {
6647 InsertTimeOption opt = d.intersected_region_action ();
6650 get_preferred_edit_position(),
6656 d.move_glued_markers(),
6657 d.move_locked_markers(),
6663 Editor::insert_time (
6664 framepos_t pos, framecnt_t frames, InsertTimeOption opt,
6665 bool all_playlists, bool ignore_music_glue, bool markers_too, bool glued_markers_too, bool locked_markers_too, bool tempo_too
6668 bool commit = false;
6670 if (Config->get_edit_mode() == Lock) {
6674 begin_reversible_command (_("insert time"));
6676 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
6678 for (TrackViewList::iterator x = ts.begin(); x != ts.end(); ++x) {
6682 /* don't operate on any playlist more than once, which could
6683 * happen if "all playlists" is enabled, but there is more
6684 * than 1 track using playlists "from" a given track.
6687 set<boost::shared_ptr<Playlist> > pl;
6689 if (all_playlists) {
6690 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*x);
6692 vector<boost::shared_ptr<Playlist> > all = _session->playlists->playlists_for_track (rtav->track ());
6693 for (vector<boost::shared_ptr<Playlist> >::iterator p = all.begin(); p != all.end(); ++p) {
6698 if ((*x)->playlist ()) {
6699 pl.insert ((*x)->playlist ());
6703 for (set<boost::shared_ptr<Playlist> >::iterator i = pl.begin(); i != pl.end(); ++i) {
6705 (*i)->clear_changes ();
6706 (*i)->clear_owned_changes ();
6708 if (opt == SplitIntersected) {
6712 (*i)->shift (pos, frames, (opt == MoveIntersected), ignore_music_glue);
6714 vector<Command*> cmds;
6716 _session->add_commands (cmds);
6718 _session->add_command (new StatefulDiffCommand (*i));
6723 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*x);
6725 rtav->route ()->shift (pos, frames);
6733 XMLNode& before (_session->locations()->get_state());
6734 Locations::LocationList copy (_session->locations()->list());
6736 for (Locations::LocationList::iterator i = copy.begin(); i != copy.end(); ++i) {
6738 Locations::LocationList::const_iterator tmp;
6740 bool const was_locked = (*i)->locked ();
6741 if (locked_markers_too) {
6745 if ((*i)->position_lock_style() == AudioTime || glued_markers_too) {
6747 if ((*i)->start() >= pos) {
6748 (*i)->set_start ((*i)->start() + frames);
6749 if (!(*i)->is_mark()) {
6750 (*i)->set_end ((*i)->end() + frames);
6763 XMLNode& after (_session->locations()->get_state());
6764 _session->add_command (new MementoCommand<Locations>(*_session->locations(), &before, &after));
6769 _session->tempo_map().insert_time (pos, frames);
6773 commit_reversible_command ();
6778 Editor::fit_selected_tracks ()
6780 if (!selection->tracks.empty()) {
6781 fit_tracks (selection->tracks);
6785 /* no selected tracks - use tracks with selected regions */
6787 if (!selection->regions.empty()) {
6788 for (RegionSelection::iterator r = selection->regions.begin(); r != selection->regions.end(); ++r) {
6789 tvl.push_back (&(*r)->get_time_axis_view ());
6795 } else if (internal_editing()) {
6796 /* no selected tracks, or regions, but in internal edit mode, so follow the mouse and use
6799 if (entered_track) {
6800 tvl.push_back (entered_track);
6809 Editor::fit_tracks (TrackViewList & tracks)
6811 if (tracks.empty()) {
6815 uint32_t child_heights = 0;
6816 int visible_tracks = 0;
6818 for (TrackSelection::iterator t = tracks.begin(); t != tracks.end(); ++t) {
6820 if (!(*t)->marked_for_display()) {
6824 child_heights += (*t)->effective_height() - (*t)->current_height();
6828 /* compute the per-track height from:
6830 total canvas visible height -
6831 height that will be taken by visible children of selected
6832 tracks - height of the ruler/hscroll area
6834 uint32_t h = (uint32_t) floor ((trackviews_height() - child_heights) / visible_tracks);
6835 double first_y_pos = DBL_MAX;
6837 if (h < TimeAxisView::preset_height (HeightSmall)) {
6838 MessageDialog msg (*this, _("There are too many tracks to fit in the current window"));
6839 /* too small to be displayed */
6843 undo_visual_stack.push_back (current_visual_state (true));
6844 no_save_visual = true;
6846 /* build a list of all tracks, including children */
6849 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
6851 TimeAxisView::Children c = (*i)->get_child_list ();
6852 for (TimeAxisView::Children::iterator j = c.begin(); j != c.end(); ++j) {
6853 all.push_back (j->get());
6857 bool prev_was_selected = false;
6858 bool is_selected = tracks.contains (all.front());
6859 bool next_is_selected;
6861 for (TrackViewList::iterator t = all.begin(); t != all.end(); ++t) {
6863 TrackViewList::iterator next;
6868 if (next != all.end()) {
6869 next_is_selected = tracks.contains (*next);
6871 next_is_selected = false;
6874 if ((*t)->marked_for_display ()) {
6876 (*t)->set_height (h);
6877 first_y_pos = std::min ((*t)->y_position (), first_y_pos);
6879 if (prev_was_selected && next_is_selected) {
6880 hide_track_in_display (*t);
6885 prev_was_selected = is_selected;
6886 is_selected = next_is_selected;
6890 set the controls_layout height now, because waiting for its size
6891 request signal handler will cause the vertical adjustment setting to fail
6894 controls_layout.property_height () = _full_canvas_height;
6895 vertical_adjustment.set_value (first_y_pos);
6897 redo_visual_stack.push_back (current_visual_state (true));
6899 visible_tracks_selector.set_text (_("Sel"));
6903 Editor::save_visual_state (uint32_t n)
6905 while (visual_states.size() <= n) {
6906 visual_states.push_back (0);
6909 if (visual_states[n] != 0) {
6910 delete visual_states[n];
6913 visual_states[n] = current_visual_state (true);
6918 Editor::goto_visual_state (uint32_t n)
6920 if (visual_states.size() <= n) {
6924 if (visual_states[n] == 0) {
6928 use_visual_state (*visual_states[n]);
6932 Editor::start_visual_state_op (uint32_t n)
6934 save_visual_state (n);
6936 PopUp* pup = new PopUp (WIN_POS_MOUSE, 1000, true);
6938 snprintf (buf, sizeof (buf), _("Saved view %u"), n+1);
6939 pup->set_text (buf);
6944 Editor::cancel_visual_state_op (uint32_t n)
6946 goto_visual_state (n);
6950 Editor::toggle_region_mute ()
6952 if (_ignore_region_action) {
6956 RegionSelection rs = get_regions_from_selection_and_entered ();
6962 if (rs.size() > 1) {
6963 begin_reversible_command (_("mute regions"));
6965 begin_reversible_command (_("mute region"));
6968 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
6970 (*i)->region()->playlist()->clear_changes ();
6971 (*i)->region()->set_muted (!(*i)->region()->muted ());
6972 _session->add_command (new StatefulDiffCommand ((*i)->region()->playlist()));
6976 commit_reversible_command ();
6980 Editor::combine_regions ()
6982 /* foreach track with selected regions, take all selected regions
6983 and join them into a new region containing the subregions (as a
6987 typedef set<RouteTimeAxisView*> RTVS;
6990 if (selection->regions.empty()) {
6994 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
6995 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(&(*i)->get_time_axis_view());
6998 tracks.insert (rtv);
7002 begin_reversible_command (_("combine regions"));
7004 vector<RegionView*> new_selection;
7006 for (RTVS::iterator i = tracks.begin(); i != tracks.end(); ++i) {
7009 if ((rv = (*i)->combine_regions ()) != 0) {
7010 new_selection.push_back (rv);
7014 selection->clear_regions ();
7015 for (vector<RegionView*>::iterator i = new_selection.begin(); i != new_selection.end(); ++i) {
7016 selection->add (*i);
7019 commit_reversible_command ();
7023 Editor::uncombine_regions ()
7025 typedef set<RouteTimeAxisView*> RTVS;
7028 if (selection->regions.empty()) {
7032 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
7033 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(&(*i)->get_time_axis_view());
7036 tracks.insert (rtv);
7040 begin_reversible_command (_("uncombine regions"));
7042 for (RTVS::iterator i = tracks.begin(); i != tracks.end(); ++i) {
7043 (*i)->uncombine_regions ();
7046 commit_reversible_command ();
7050 Editor::toggle_midi_input_active (bool flip_others)
7053 boost::shared_ptr<RouteList> rl (new RouteList);
7055 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
7056 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
7062 boost::shared_ptr<MidiTrack> mt = rtav->midi_track();
7065 rl->push_back (rtav->route());
7066 onoff = !mt->input_active();
7070 _session->set_exclusive_input_active (rl, onoff, flip_others);
7077 lock_dialog = new Gtk::Dialog (string_compose (_("%1: Locked"), PROGRAM_NAME), true);
7079 Gtk::Image* padlock = manage (new Gtk::Image (ARDOUR_UI_UTILS::get_icon ("padlock_closed")));
7080 lock_dialog->get_vbox()->pack_start (*padlock);
7082 ArdourButton* b = manage (new ArdourButton);
7083 b->set_name ("lock button");
7084 b->set_text (_("Click to unlock"));
7085 b->signal_clicked.connect (sigc::mem_fun (*this, &Editor::unlock));
7086 lock_dialog->get_vbox()->pack_start (*b);
7088 lock_dialog->get_vbox()->show_all ();
7089 lock_dialog->set_size_request (200, 200);
7093 /* The global menu bar continues to be accessible to applications
7094 with modal dialogs, which means that we need to desensitize
7095 all items in the menu bar. Since those items are really just
7096 proxies for actions, that means disabling all actions.
7098 ActionManager::disable_all_actions ();
7100 lock_dialog->present ();
7106 lock_dialog->hide ();
7109 ActionManager::pop_action_state ();
7112 if (ARDOUR_UI::config()->get_lock_gui_after_seconds()) {
7113 start_lock_event_timing ();
7118 Editor::bring_in_callback (Gtk::Label* label, uint32_t n, uint32_t total, string name)
7120 Gtkmm2ext::UI::instance()->call_slot (invalidator (*this), boost::bind (&Editor::update_bring_in_message, this, label, n, total, name));
7124 Editor::update_bring_in_message (Gtk::Label* label, uint32_t n, uint32_t total, string name)
7126 label->set_text (string_compose ("Copying %1, %2 of %3", name, n, total));
7127 Gtkmm2ext::UI::instance()->flush_pending ();
7131 Editor::bring_all_sources_into_session ()
7138 ArdourDialog w (_("Moving embedded files into session folder"));
7139 w.get_vbox()->pack_start (msg);
7142 /* flush all pending GUI events because we're about to start copying
7146 Gtkmm2ext::UI::instance()->flush_pending ();
7150 _session->bring_all_sources_into_session (boost::bind (&Editor::bring_in_callback, this, &msg, _1, _2, _3));