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.rend();
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 this is the upper-most visible trackview, we want to display
1381 the one above it (next)
1384 res = (*t)->covers_y_position (top_of_trackviews);
1392 /* move to the track below the first one that covers the */
1394 if (next != track_views.rend()) {
1395 ensure_time_axis_view_is_visible (**next, true);
1403 Editor::scroll_up_one_track ()
1405 TrackViewList::iterator prev = track_views.end();
1406 std::pair<TimeAxisView*,double> res;
1407 double top_of_trackviews = vertical_adjustment.get_value ();
1409 for (TrackViewList::iterator t = track_views.begin(); t != track_views.end(); ++t) {
1411 if ((*t)->hidden()) {
1415 /* find the trackview at the top of the trackview group */
1416 res = (*t)->covers_y_position (top_of_trackviews);
1425 if (prev != track_views.end()) {
1426 ensure_time_axis_view_is_visible (**prev, true);
1436 Editor::tav_zoom_step (bool coarser)
1438 DisplaySuspender ds;
1442 if (selection->tracks.empty()) {
1445 ts = &selection->tracks;
1448 for (TrackViewList::iterator i = ts->begin(); i != ts->end(); ++i) {
1449 TimeAxisView *tv = (static_cast<TimeAxisView*>(*i));
1450 tv->step_height (coarser);
1455 Editor::tav_zoom_smooth (bool coarser, bool force_all)
1457 DisplaySuspender ds;
1461 if (selection->tracks.empty() || force_all) {
1464 ts = &selection->tracks;
1467 for (TrackViewList::iterator i = ts->begin(); i != ts->end(); ++i) {
1468 TimeAxisView *tv = (static_cast<TimeAxisView*>(*i));
1469 uint32_t h = tv->current_height ();
1474 if (h >= TimeAxisView::preset_height (HeightSmall)) {
1479 tv->set_height (h + 5);
1486 Editor::temporal_zoom_step (bool coarser)
1488 ENSURE_GUI_THREAD (*this, &Editor::temporal_zoom_step, coarser)
1490 framecnt_t nspp = samples_per_pixel;
1498 temporal_zoom (nspp);
1502 Editor::temporal_zoom (framecnt_t fpp)
1508 framepos_t current_page = current_page_samples();
1509 framepos_t current_leftmost = leftmost_frame;
1510 framepos_t current_rightmost;
1511 framepos_t current_center;
1512 framepos_t new_page_size;
1513 framepos_t half_page_size;
1514 framepos_t leftmost_after_zoom = 0;
1516 bool in_track_canvas;
1520 if (fpp == samples_per_pixel) {
1524 // Imposing an arbitrary limit to zoom out as too much zoom out produces
1525 // segfaults for lack of memory. If somebody decides this is not high enough I
1526 // believe it can be raisen to higher values but some limit must be in place.
1528 // This constant represents 1 day @ 48kHz on a 1600 pixel wide display
1529 // all of which is used for the editor track displays. The whole day
1530 // would be 4147200000 samples, so 2592000 samples per pixel.
1532 nfpp = min (fpp, (framecnt_t) 2592000);
1533 nfpp = max ((framecnt_t) 1, fpp);
1535 new_page_size = (framepos_t) floor (_visible_canvas_width * nfpp);
1536 half_page_size = new_page_size / 2;
1538 switch (zoom_focus) {
1540 leftmost_after_zoom = current_leftmost;
1543 case ZoomFocusRight:
1544 current_rightmost = leftmost_frame + current_page;
1545 if (current_rightmost < new_page_size) {
1546 leftmost_after_zoom = 0;
1548 leftmost_after_zoom = current_rightmost - new_page_size;
1552 case ZoomFocusCenter:
1553 current_center = current_leftmost + (current_page/2);
1554 if (current_center < half_page_size) {
1555 leftmost_after_zoom = 0;
1557 leftmost_after_zoom = current_center - half_page_size;
1561 case ZoomFocusPlayhead:
1562 /* centre playhead */
1563 l = playhead_cursor->current_frame () - (new_page_size * 0.5);
1566 leftmost_after_zoom = 0;
1567 } else if (l > max_framepos) {
1568 leftmost_after_zoom = max_framepos - new_page_size;
1570 leftmost_after_zoom = (framepos_t) l;
1574 case ZoomFocusMouse:
1575 /* try to keep the mouse over the same point in the display */
1577 if (!mouse_frame (where, in_track_canvas)) {
1578 /* use playhead instead */
1579 where = playhead_cursor->current_frame ();
1581 if (where < half_page_size) {
1582 leftmost_after_zoom = 0;
1584 leftmost_after_zoom = where - half_page_size;
1589 l = - ((new_page_size * ((where - current_leftmost)/(double)current_page)) - where);
1592 leftmost_after_zoom = 0;
1593 } else if (l > max_framepos) {
1594 leftmost_after_zoom = max_framepos - new_page_size;
1596 leftmost_after_zoom = (framepos_t) l;
1603 /* try to keep the edit point in the same place */
1604 where = get_preferred_edit_position ();
1608 double l = - ((new_page_size * ((where - current_leftmost)/(double)current_page)) - where);
1611 leftmost_after_zoom = 0;
1612 } else if (l > max_framepos) {
1613 leftmost_after_zoom = max_framepos - new_page_size;
1615 leftmost_after_zoom = (framepos_t) l;
1619 /* edit point not defined */
1626 // leftmost_after_zoom = min (leftmost_after_zoom, _session->current_end_frame());
1628 reposition_and_zoom (leftmost_after_zoom, nfpp);
1632 Editor::calc_extra_zoom_edges(framepos_t &start, framepos_t &end)
1634 /* this func helps make sure we leave a little space
1635 at each end of the editor so that the zoom doesn't fit the region
1636 precisely to the screen.
1639 GdkScreen* screen = gdk_screen_get_default ();
1640 const gint pixwidth = gdk_screen_get_width (screen);
1641 const gint mmwidth = gdk_screen_get_width_mm (screen);
1642 const double pix_per_mm = (double) pixwidth/ (double) mmwidth;
1643 const double one_centimeter_in_pixels = pix_per_mm * 10.0;
1645 const framepos_t range = end - start;
1646 const framecnt_t new_fpp = (framecnt_t) ceil ((double) range / (double) _visible_canvas_width);
1647 const framepos_t extra_samples = (framepos_t) floor (one_centimeter_in_pixels * new_fpp);
1649 if (start > extra_samples) {
1650 start -= extra_samples;
1655 if (max_framepos - extra_samples > end) {
1656 end += extra_samples;
1663 Editor::temporal_zoom_region (bool both_axes)
1665 framepos_t start = max_framepos;
1667 set<TimeAxisView*> tracks;
1669 RegionSelection rs = get_regions_from_selection_and_entered ();
1675 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
1677 if ((*i)->region()->position() < start) {
1678 start = (*i)->region()->position();
1681 if ((*i)->region()->last_frame() + 1 > end) {
1682 end = (*i)->region()->last_frame() + 1;
1685 tracks.insert (&((*i)->get_time_axis_view()));
1688 if ((start == 0 && end == 0) || end < start) {
1692 calc_extra_zoom_edges (start, end);
1694 /* if we're zooming on both axes we need to save track heights etc.
1697 undo_visual_stack.push_back (current_visual_state (both_axes));
1699 PBD::Unwinder<bool> nsv (no_save_visual, true);
1701 temporal_zoom_by_frame (start, end);
1704 uint32_t per_track_height = (uint32_t) floor ((_visible_canvas_height - 10.0) / tracks.size());
1706 /* set visible track heights appropriately */
1708 for (set<TimeAxisView*>::iterator t = tracks.begin(); t != tracks.end(); ++t) {
1709 (*t)->set_height (per_track_height);
1712 /* hide irrelevant tracks */
1714 DisplaySuspender ds;
1716 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1717 if (find (tracks.begin(), tracks.end(), (*i)) == tracks.end()) {
1718 hide_track_in_display (*i);
1722 vertical_adjustment.set_value (0.0);
1725 redo_visual_stack.push_back (current_visual_state (both_axes));
1729 Editor::zoom_to_region (bool both_axes)
1731 temporal_zoom_region (both_axes);
1735 Editor::temporal_zoom_selection (bool both_axes)
1737 if (!selection) return;
1739 //if a range is selected, zoom to that
1740 if (!selection->time.empty()) {
1742 framepos_t start = selection->time.start();
1743 framepos_t end = selection->time.end_frame();
1745 calc_extra_zoom_edges(start, end);
1747 temporal_zoom_by_frame (start, end);
1750 fit_selected_tracks();
1753 temporal_zoom_region (both_axes);
1760 Editor::temporal_zoom_session ()
1762 ENSURE_GUI_THREAD (*this, &Editor::temporal_zoom_session)
1765 framecnt_t start = _session->current_start_frame();
1766 framecnt_t end = _session->current_end_frame();
1768 if (_session->actively_recording () ) {
1769 framepos_t cur = playhead_cursor->current_frame ();
1771 /* recording beyond the end marker; zoom out
1772 * by 5 seconds more so that if 'follow
1773 * playhead' is active we don't immediately
1776 end = cur + _session->frame_rate() * 5;
1780 if ((start == 0 && end == 0) || end < start) {
1784 calc_extra_zoom_edges(start, end);
1786 temporal_zoom_by_frame (start, end);
1791 Editor::temporal_zoom_by_frame (framepos_t start, framepos_t end)
1793 if (!_session) return;
1795 if ((start == 0 && end == 0) || end < start) {
1799 framepos_t range = end - start;
1801 const framecnt_t new_fpp = (framecnt_t) ceil ((double) range / (double) _visible_canvas_width);
1803 framepos_t new_page = range;
1804 framepos_t middle = (framepos_t) floor ((double) start + ((double) range / 2.0f));
1805 framepos_t new_leftmost = (framepos_t) floor ((double) middle - ((double) new_page / 2.0f));
1807 if (new_leftmost > middle) {
1811 if (new_leftmost < 0) {
1815 reposition_and_zoom (new_leftmost, new_fpp);
1819 Editor::temporal_zoom_to_frame (bool coarser, framepos_t frame)
1825 framecnt_t range_before = frame - leftmost_frame;
1829 if (samples_per_pixel <= 1) {
1832 new_spp = samples_per_pixel + (samples_per_pixel/2);
1834 range_before += range_before/2;
1836 if (samples_per_pixel >= 1) {
1837 new_spp = samples_per_pixel - (samples_per_pixel/2);
1839 /* could bail out here since we cannot zoom any finer,
1840 but leave that to the equality test below
1842 new_spp = samples_per_pixel;
1845 range_before -= range_before/2;
1848 if (new_spp == samples_per_pixel) {
1852 /* zoom focus is automatically taken as @param frame when this
1856 framepos_t new_leftmost = frame - (framepos_t)range_before;
1858 if (new_leftmost > frame) {
1862 if (new_leftmost < 0) {
1866 reposition_and_zoom (new_leftmost, new_spp);
1871 Editor::choose_new_marker_name(string &name) {
1873 if (!Config->get_name_new_markers()) {
1874 /* don't prompt user for a new name */
1878 ArdourPrompter dialog (true);
1880 dialog.set_prompt (_("New Name:"));
1882 dialog.set_title (_("New Location Marker"));
1884 dialog.set_name ("MarkNameWindow");
1885 dialog.set_size_request (250, -1);
1886 dialog.set_position (Gtk::WIN_POS_MOUSE);
1888 dialog.add_button (Stock::OK, RESPONSE_ACCEPT);
1889 dialog.set_initial_text (name);
1893 switch (dialog.run ()) {
1894 case RESPONSE_ACCEPT:
1900 dialog.get_result(name);
1907 Editor::add_location_from_selection ()
1911 if (selection->time.empty()) {
1915 if (_session == 0 || clicked_axisview == 0) {
1919 framepos_t start = selection->time[clicked_selection].start;
1920 framepos_t end = selection->time[clicked_selection].end;
1922 _session->locations()->next_available_name(rangename,"selection");
1923 Location *location = new Location (*_session, start, end, rangename, Location::IsRangeMarker);
1925 _session->begin_reversible_command (_("add marker"));
1926 XMLNode &before = _session->locations()->get_state();
1927 _session->locations()->add (location, true);
1928 XMLNode &after = _session->locations()->get_state();
1929 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
1930 _session->commit_reversible_command ();
1934 Editor::add_location_mark (framepos_t where)
1938 select_new_marker = true;
1940 _session->locations()->next_available_name(markername,"mark");
1941 if (!choose_new_marker_name(markername)) {
1944 Location *location = new Location (*_session, where, where, markername, Location::IsMark);
1945 _session->begin_reversible_command (_("add marker"));
1946 XMLNode &before = _session->locations()->get_state();
1947 _session->locations()->add (location, true);
1948 XMLNode &after = _session->locations()->get_state();
1949 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
1950 _session->commit_reversible_command ();
1954 Editor::add_location_from_playhead_cursor ()
1956 add_location_mark (_session->audible_frame());
1960 Editor::remove_location_at_playhead_cursor ()
1965 _session->begin_reversible_command (_("remove marker"));
1966 XMLNode &before = _session->locations()->get_state();
1967 bool removed = false;
1969 //find location(s) at this time
1970 Locations::LocationList locs;
1971 _session->locations()->find_all_between (_session->audible_frame(), _session->audible_frame()+1, locs, Location::Flags(0));
1972 for (Locations::LocationList::iterator i = locs.begin(); i != locs.end(); ++i) {
1973 if ((*i)->is_mark()) {
1974 _session->locations()->remove (*i);
1981 XMLNode &after = _session->locations()->get_state();
1982 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
1983 _session->commit_reversible_command ();
1988 /** Add a range marker around each selected region */
1990 Editor::add_locations_from_region ()
1992 RegionSelection rs = get_regions_from_selection_and_entered ();
1998 _session->begin_reversible_command (selection->regions.size () > 1 ? _("add markers") : _("add marker"));
1999 XMLNode &before = _session->locations()->get_state();
2001 for (RegionSelection::iterator i = rs.begin (); i != rs.end (); ++i) {
2003 boost::shared_ptr<Region> region = (*i)->region ();
2005 Location *location = new Location (*_session, region->position(), region->last_frame(), region->name(), Location::IsRangeMarker);
2007 _session->locations()->add (location, true);
2010 XMLNode &after = _session->locations()->get_state();
2011 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2012 _session->commit_reversible_command ();
2015 /** Add a single range marker around all selected regions */
2017 Editor::add_location_from_region ()
2019 RegionSelection rs = get_regions_from_selection_and_entered ();
2025 _session->begin_reversible_command (_("add marker"));
2026 XMLNode &before = _session->locations()->get_state();
2030 if (rs.size() > 1) {
2031 _session->locations()->next_available_name(markername, "regions");
2033 RegionView* rv = *(rs.begin());
2034 boost::shared_ptr<Region> region = rv->region();
2035 markername = region->name();
2038 if (!choose_new_marker_name(markername)) {
2042 // single range spanning all selected
2043 Location *location = new Location (*_session, selection->regions.start(), selection->regions.end_frame(), markername, Location::IsRangeMarker);
2044 _session->locations()->add (location, true);
2046 XMLNode &after = _session->locations()->get_state();
2047 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2048 _session->commit_reversible_command ();
2054 Editor::jump_forward_to_mark ()
2060 framepos_t pos = _session->locations()->first_mark_after (playhead_cursor->current_frame());
2066 _session->request_locate (pos, _session->transport_rolling());
2070 Editor::jump_backward_to_mark ()
2076 framepos_t pos = _session->locations()->first_mark_before (playhead_cursor->current_frame());
2082 _session->request_locate (pos, _session->transport_rolling());
2088 framepos_t const pos = _session->audible_frame ();
2091 _session->locations()->next_available_name (markername, "mark");
2093 if (!choose_new_marker_name (markername)) {
2097 _session->locations()->add (new Location (*_session, pos, 0, markername, Location::IsMark), true);
2101 Editor::clear_markers ()
2104 _session->begin_reversible_command (_("clear markers"));
2105 XMLNode &before = _session->locations()->get_state();
2106 _session->locations()->clear_markers ();
2107 XMLNode &after = _session->locations()->get_state();
2108 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2109 _session->commit_reversible_command ();
2114 Editor::clear_ranges ()
2117 _session->begin_reversible_command (_("clear ranges"));
2118 XMLNode &before = _session->locations()->get_state();
2120 _session->locations()->clear_ranges ();
2122 XMLNode &after = _session->locations()->get_state();
2123 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2124 _session->commit_reversible_command ();
2129 Editor::clear_locations ()
2131 _session->begin_reversible_command (_("clear locations"));
2132 XMLNode &before = _session->locations()->get_state();
2133 _session->locations()->clear ();
2134 XMLNode &after = _session->locations()->get_state();
2135 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2136 _session->commit_reversible_command ();
2137 _session->locations()->clear ();
2141 Editor::unhide_markers ()
2143 for (LocationMarkerMap::iterator i = location_markers.begin(); i != location_markers.end(); ++i) {
2144 Location *l = (*i).first;
2145 if (l->is_hidden() && l->is_mark()) {
2146 l->set_hidden(false, this);
2152 Editor::unhide_ranges ()
2154 for (LocationMarkerMap::iterator i = location_markers.begin(); i != location_markers.end(); ++i) {
2155 Location *l = (*i).first;
2156 if (l->is_hidden() && l->is_range_marker()) {
2157 l->set_hidden(false, this);
2162 /* INSERT/REPLACE */
2165 Editor::insert_region_list_selection (float times)
2167 RouteTimeAxisView *tv = 0;
2168 boost::shared_ptr<Playlist> playlist;
2170 if (clicked_routeview != 0) {
2171 tv = clicked_routeview;
2172 } else if (!selection->tracks.empty()) {
2173 if ((tv = dynamic_cast<RouteTimeAxisView*>(selection->tracks.front())) == 0) {
2176 } else if (entered_track != 0) {
2177 if ((tv = dynamic_cast<RouteTimeAxisView*>(entered_track)) == 0) {
2184 if ((playlist = tv->playlist()) == 0) {
2188 boost::shared_ptr<Region> region = _regions->get_single_selection ();
2193 begin_reversible_command (_("insert region"));
2194 playlist->clear_changes ();
2195 playlist->add_region ((RegionFactory::create (region, true)), get_preferred_edit_position(), times);
2196 if (Config->get_edit_mode() == Ripple)
2197 playlist->ripple (get_preferred_edit_position(), region->length() * times, boost::shared_ptr<Region>());
2199 _session->add_command(new StatefulDiffCommand (playlist));
2200 commit_reversible_command ();
2203 /* BUILT-IN EFFECTS */
2206 Editor::reverse_selection ()
2211 /* GAIN ENVELOPE EDITING */
2214 Editor::edit_envelope ()
2221 Editor::transition_to_rolling (bool fwd)
2227 if (_session->config.get_external_sync()) {
2228 switch (Config->get_sync_source()) {
2232 /* transport controlled by the master */
2237 if (_session->is_auditioning()) {
2238 _session->cancel_audition ();
2242 _session->request_transport_speed (fwd ? 1.0f : -1.0f);
2246 Editor::play_from_start ()
2248 _session->request_locate (_session->current_start_frame(), true);
2252 Editor::play_from_edit_point ()
2254 _session->request_locate (get_preferred_edit_position(), true);
2258 Editor::play_from_edit_point_and_return ()
2260 framepos_t start_frame;
2261 framepos_t return_frame;
2263 start_frame = get_preferred_edit_position (true);
2265 if (_session->transport_rolling()) {
2266 _session->request_locate (start_frame, false);
2270 /* don't reset the return frame if its already set */
2272 if ((return_frame = _session->requested_return_frame()) < 0) {
2273 return_frame = _session->audible_frame();
2276 if (start_frame >= 0) {
2277 _session->request_roll_at_and_return (start_frame, return_frame);
2282 Editor::play_selection ()
2284 if (selection->time.empty()) {
2288 _session->request_play_range (&selection->time, true);
2292 Editor::get_preroll ()
2294 return 1.0 /*Config->get_edit_preroll_seconds()*/ * _session->frame_rate();
2299 Editor::maybe_locate_with_edit_preroll ( framepos_t location )
2301 if ( _session->transport_rolling() || !Config->get_follow_edits() || _ignore_follow_edits )
2304 location -= get_preroll();
2306 //don't try to locate before the beginning of time
2310 //if follow_playhead is on, keep the playhead on the screen
2311 if ( _follow_playhead )
2312 if ( location < leftmost_frame )
2313 location = leftmost_frame;
2315 _session->request_locate( location );
2319 Editor::play_with_preroll ()
2321 if (selection->time.empty()) {
2324 framepos_t preroll = get_preroll();
2326 framepos_t start = 0;
2327 if (selection->time[clicked_selection].start > preroll)
2328 start = selection->time[clicked_selection].start - preroll;
2330 framepos_t end = selection->time[clicked_selection].end + preroll;
2332 AudioRange ar (start, end, 0);
2333 list<AudioRange> lar;
2336 _session->request_play_range (&lar, true);
2341 Editor::play_location (Location& location)
2343 if (location.start() <= location.end()) {
2347 _session->request_bounded_roll (location.start(), location.end());
2351 Editor::loop_location (Location& location)
2353 if (location.start() <= location.end()) {
2359 if ((tll = transport_loop_location()) != 0) {
2360 tll->set (location.start(), location.end());
2362 // enable looping, reposition and start rolling
2363 _session->request_locate (tll->start(), true);
2364 _session->request_play_loop (true);
2369 Editor::do_layer_operation (LayerOperation op)
2371 if (selection->regions.empty ()) {
2375 bool const multiple = selection->regions.size() > 1;
2379 begin_reversible_command (_("raise regions"));
2381 begin_reversible_command (_("raise region"));
2387 begin_reversible_command (_("raise regions to top"));
2389 begin_reversible_command (_("raise region to top"));
2395 begin_reversible_command (_("lower regions"));
2397 begin_reversible_command (_("lower region"));
2403 begin_reversible_command (_("lower regions to bottom"));
2405 begin_reversible_command (_("lower region"));
2410 set<boost::shared_ptr<Playlist> > playlists = selection->regions.playlists ();
2411 for (set<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
2412 (*i)->clear_owned_changes ();
2415 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
2416 boost::shared_ptr<Region> r = (*i)->region ();
2428 r->lower_to_bottom ();
2432 for (set<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
2433 vector<Command*> cmds;
2435 _session->add_commands (cmds);
2438 commit_reversible_command ();
2442 Editor::raise_region ()
2444 do_layer_operation (Raise);
2448 Editor::raise_region_to_top ()
2450 do_layer_operation (RaiseToTop);
2454 Editor::lower_region ()
2456 do_layer_operation (Lower);
2460 Editor::lower_region_to_bottom ()
2462 do_layer_operation (LowerToBottom);
2465 /** Show the region editor for the selected regions */
2467 Editor::show_region_properties ()
2469 selection->foreach_regionview (&RegionView::show_region_editor);
2472 /** Show the midi list editor for the selected MIDI regions */
2474 Editor::show_midi_list_editor ()
2476 selection->foreach_midi_regionview (&MidiRegionView::show_list_editor);
2480 Editor::rename_region ()
2482 RegionSelection rs = get_regions_from_selection_and_entered ();
2488 ArdourDialog d (*this, _("Rename Region"), true, false);
2490 Label label (_("New name:"));
2493 hbox.set_spacing (6);
2494 hbox.pack_start (label, false, false);
2495 hbox.pack_start (entry, true, true);
2497 d.get_vbox()->set_border_width (12);
2498 d.get_vbox()->pack_start (hbox, false, false);
2500 d.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
2501 d.add_button(Gtk::Stock::OK, Gtk::RESPONSE_OK);
2503 d.set_size_request (300, -1);
2505 entry.set_text (rs.front()->region()->name());
2506 entry.select_region (0, -1);
2508 entry.signal_activate().connect (sigc::bind (sigc::mem_fun (d, &Dialog::response), RESPONSE_OK));
2514 int const ret = d.run();
2518 if (ret != RESPONSE_OK) {
2522 std::string str = entry.get_text();
2523 strip_whitespace_edges (str);
2525 rs.front()->region()->set_name (str);
2526 _regions->redisplay ();
2531 Editor::audition_playlist_region_via_route (boost::shared_ptr<Region> region, Route& route)
2533 if (_session->is_auditioning()) {
2534 _session->cancel_audition ();
2537 // note: some potential for creativity here, because region doesn't
2538 // have to belong to the playlist that Route is handling
2540 // bool was_soloed = route.soloed();
2542 route.set_solo (true, this);
2544 _session->request_bounded_roll (region->position(), region->position() + region->length());
2546 /* XXX how to unset the solo state ? */
2549 /** Start an audition of the first selected region */
2551 Editor::play_edit_range ()
2553 framepos_t start, end;
2555 if (get_edit_op_range (start, end)) {
2556 _session->request_bounded_roll (start, end);
2561 Editor::play_selected_region ()
2563 framepos_t start = max_framepos;
2566 RegionSelection rs = get_regions_from_selection_and_entered ();
2572 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
2573 if ((*i)->region()->position() < start) {
2574 start = (*i)->region()->position();
2576 if ((*i)->region()->last_frame() + 1 > end) {
2577 end = (*i)->region()->last_frame() + 1;
2581 _session->request_bounded_roll (start, end);
2585 Editor::audition_playlist_region_standalone (boost::shared_ptr<Region> region)
2587 _session->audition_region (region);
2591 Editor::region_from_selection ()
2593 if (clicked_axisview == 0) {
2597 if (selection->time.empty()) {
2601 framepos_t start = selection->time[clicked_selection].start;
2602 framepos_t end = selection->time[clicked_selection].end;
2604 TrackViewList tracks = get_tracks_for_range_action ();
2606 framepos_t selection_cnt = end - start + 1;
2608 for (TrackSelection::iterator i = tracks.begin(); i != tracks.end(); ++i) {
2609 boost::shared_ptr<Region> current;
2610 boost::shared_ptr<Playlist> pl;
2611 framepos_t internal_start;
2614 if ((pl = (*i)->playlist()) == 0) {
2618 if ((current = pl->top_region_at (start)) == 0) {
2622 internal_start = start - current->position();
2623 RegionFactory::region_name (new_name, current->name(), true);
2627 plist.add (ARDOUR::Properties::start, current->start() + internal_start);
2628 plist.add (ARDOUR::Properties::length, selection_cnt);
2629 plist.add (ARDOUR::Properties::name, new_name);
2630 plist.add (ARDOUR::Properties::layer, 0);
2632 boost::shared_ptr<Region> region (RegionFactory::create (current, plist));
2637 Editor::create_region_from_selection (vector<boost::shared_ptr<Region> >& new_regions)
2639 if (selection->time.empty() || selection->tracks.empty()) {
2643 framepos_t start = selection->time[clicked_selection].start;
2644 framepos_t end = selection->time[clicked_selection].end;
2646 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
2647 sort_track_selection (ts);
2649 for (TrackSelection::iterator i = ts.begin(); i != ts.end(); ++i) {
2650 boost::shared_ptr<Region> current;
2651 boost::shared_ptr<Playlist> playlist;
2652 framepos_t internal_start;
2655 if ((playlist = (*i)->playlist()) == 0) {
2659 if ((current = playlist->top_region_at(start)) == 0) {
2663 internal_start = start - current->position();
2664 RegionFactory::region_name (new_name, current->name(), true);
2668 plist.add (ARDOUR::Properties::start, current->start() + internal_start);
2669 plist.add (ARDOUR::Properties::length, end - start + 1);
2670 plist.add (ARDOUR::Properties::name, new_name);
2672 new_regions.push_back (RegionFactory::create (current, plist));
2677 Editor::split_multichannel_region ()
2679 RegionSelection rs = get_regions_from_selection_and_entered ();
2685 vector< boost::shared_ptr<Region> > v;
2687 for (list<RegionView*>::iterator x = rs.begin(); x != rs.end(); ++x) {
2688 (*x)->region()->separate_by_channel (*_session, v);
2693 Editor::new_region_from_selection ()
2695 region_from_selection ();
2696 cancel_selection ();
2700 add_if_covered (RegionView* rv, const AudioRange* ar, RegionSelection* rs)
2702 switch (rv->region()->coverage (ar->start, ar->end - 1)) {
2703 case Evoral::OverlapNone:
2711 * - selected tracks, or if there are none...
2712 * - tracks containing selected regions, or if there are none...
2717 Editor::get_tracks_for_range_action () const
2721 if (selection->tracks.empty()) {
2723 /* use tracks with selected regions */
2725 RegionSelection rs = selection->regions;
2727 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
2728 TimeAxisView* tv = &(*i)->get_time_axis_view();
2730 if (!t.contains (tv)) {
2736 /* no regions and no tracks: use all tracks */
2742 t = selection->tracks;
2745 return t.filter_to_unique_playlists();
2749 Editor::separate_regions_between (const TimeSelection& ts)
2751 bool in_command = false;
2752 boost::shared_ptr<Playlist> playlist;
2753 RegionSelection new_selection;
2755 TrackViewList tmptracks = get_tracks_for_range_action ();
2756 sort_track_selection (tmptracks);
2758 for (TrackSelection::iterator i = tmptracks.begin(); i != tmptracks.end(); ++i) {
2760 RouteTimeAxisView* rtv;
2762 if ((rtv = dynamic_cast<RouteTimeAxisView*> ((*i))) != 0) {
2764 if (rtv->is_track()) {
2766 /* no edits to destructive tracks */
2768 if (rtv->track()->destructive()) {
2772 if ((playlist = rtv->playlist()) != 0) {
2774 playlist->clear_changes ();
2776 /* XXX need to consider musical time selections here at some point */
2778 double speed = rtv->track()->speed();
2781 for (list<AudioRange>::const_iterator t = ts.begin(); t != ts.end(); ++t) {
2783 sigc::connection c = rtv->view()->RegionViewAdded.connect (
2784 sigc::mem_fun(*this, &Editor::collect_new_region_view));
2786 latest_regionviews.clear ();
2788 playlist->partition ((framepos_t)((*t).start * speed),
2789 (framepos_t)((*t).end * speed), false);
2793 if (!latest_regionviews.empty()) {
2795 rtv->view()->foreach_regionview (sigc::bind (
2796 sigc::ptr_fun (add_if_covered),
2797 &(*t), &new_selection));
2800 begin_reversible_command (_("separate"));
2804 /* pick up changes to existing regions */
2806 vector<Command*> cmds;
2807 playlist->rdiff (cmds);
2808 _session->add_commands (cmds);
2810 /* pick up changes to the playlist itself (adds/removes)
2813 _session->add_command(new StatefulDiffCommand (playlist));
2822 // selection->set (new_selection);
2824 commit_reversible_command ();
2828 struct PlaylistState {
2829 boost::shared_ptr<Playlist> playlist;
2833 /** Take tracks from get_tracks_for_range_action and cut any regions
2834 * on those tracks so that the tracks are empty over the time
2838 Editor::separate_region_from_selection ()
2840 /* preferentially use *all* ranges in the time selection if we're in range mode
2841 to allow discontiguous operation, since get_edit_op_range() currently
2842 returns a single range.
2845 if (!selection->time.empty()) {
2847 separate_regions_between (selection->time);
2854 if (get_edit_op_range (start, end)) {
2856 AudioRange ar (start, end, 1);
2860 separate_regions_between (ts);
2866 Editor::separate_region_from_punch ()
2868 Location* loc = _session->locations()->auto_punch_location();
2870 separate_regions_using_location (*loc);
2875 Editor::separate_region_from_loop ()
2877 Location* loc = _session->locations()->auto_loop_location();
2879 separate_regions_using_location (*loc);
2884 Editor::separate_regions_using_location (Location& loc)
2886 if (loc.is_mark()) {
2890 AudioRange ar (loc.start(), loc.end(), 1);
2895 separate_regions_between (ts);
2898 /** Separate regions under the selected region */
2900 Editor::separate_under_selected_regions ()
2902 vector<PlaylistState> playlists;
2906 rs = get_regions_from_selection_and_entered();
2908 if (!_session || rs.empty()) {
2912 begin_reversible_command (_("separate region under"));
2914 list<boost::shared_ptr<Region> > regions_to_remove;
2916 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
2917 // we can't just remove the region(s) in this loop because
2918 // this removes them from the RegionSelection, and they thus
2919 // disappear from underneath the iterator, and the ++i above
2920 // SEGVs in a puzzling fashion.
2922 // so, first iterate over the regions to be removed from rs and
2923 // add them to the regions_to_remove list, and then
2924 // iterate over the list to actually remove them.
2926 regions_to_remove.push_back ((*i)->region());
2929 for (list<boost::shared_ptr<Region> >::iterator rl = regions_to_remove.begin(); rl != regions_to_remove.end(); ++rl) {
2931 boost::shared_ptr<Playlist> playlist = (*rl)->playlist();
2934 // is this check necessary?
2938 vector<PlaylistState>::iterator i;
2940 //only take state if this is a new playlist.
2941 for (i = playlists.begin(); i != playlists.end(); ++i) {
2942 if ((*i).playlist == playlist) {
2947 if (i == playlists.end()) {
2949 PlaylistState before;
2950 before.playlist = playlist;
2951 before.before = &playlist->get_state();
2953 playlist->freeze ();
2954 playlists.push_back(before);
2957 //Partition on the region bounds
2958 playlist->partition ((*rl)->first_frame() - 1, (*rl)->last_frame() + 1, true);
2960 //Re-add region that was just removed due to the partition operation
2961 playlist->add_region( (*rl), (*rl)->first_frame() );
2964 vector<PlaylistState>::iterator pl;
2966 for (pl = playlists.begin(); pl != playlists.end(); ++pl) {
2967 (*pl).playlist->thaw ();
2968 _session->add_command(new MementoCommand<Playlist>(*(*pl).playlist, (*pl).before, &(*pl).playlist->get_state()));
2971 commit_reversible_command ();
2975 Editor::crop_region_to_selection ()
2977 if (!selection->time.empty()) {
2979 crop_region_to (selection->time.start(), selection->time.end_frame());
2986 if (get_edit_op_range (start, end)) {
2987 crop_region_to (start, end);
2994 Editor::crop_region_to (framepos_t start, framepos_t end)
2996 vector<boost::shared_ptr<Playlist> > playlists;
2997 boost::shared_ptr<Playlist> playlist;
3000 if (selection->tracks.empty()) {
3001 ts = track_views.filter_to_unique_playlists();
3003 ts = selection->tracks.filter_to_unique_playlists ();
3006 sort_track_selection (ts);
3008 for (TrackSelection::iterator i = ts.begin(); i != ts.end(); ++i) {
3010 RouteTimeAxisView* rtv;
3012 if ((rtv = dynamic_cast<RouteTimeAxisView*> ((*i))) != 0) {
3014 boost::shared_ptr<Track> t = rtv->track();
3016 if (t != 0 && ! t->destructive()) {
3018 if ((playlist = rtv->playlist()) != 0) {
3019 playlists.push_back (playlist);
3025 if (playlists.empty()) {
3029 framepos_t the_start;
3033 begin_reversible_command (_("trim to selection"));
3035 for (vector<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
3037 boost::shared_ptr<Region> region;
3041 if ((region = (*i)->top_region_at(the_start)) == 0) {
3045 /* now adjust lengths to that we do the right thing
3046 if the selection extends beyond the region
3049 the_start = max (the_start, (framepos_t) region->position());
3050 if (max_framepos - the_start < region->length()) {
3051 the_end = the_start + region->length() - 1;
3053 the_end = max_framepos;
3055 the_end = min (end, the_end);
3056 cnt = the_end - the_start + 1;
3058 region->clear_changes ();
3059 region->trim_to (the_start, cnt);
3060 _session->add_command (new StatefulDiffCommand (region));
3063 commit_reversible_command ();
3067 Editor::region_fill_track ()
3069 RegionSelection rs = get_regions_from_selection_and_entered ();
3071 if (!_session || rs.empty()) {
3075 framepos_t const end = _session->current_end_frame ();
3077 begin_reversible_command (Operations::region_fill);
3079 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3081 boost::shared_ptr<Region> region ((*i)->region());
3083 boost::shared_ptr<Playlist> pl = region->playlist();
3085 if (end <= region->last_frame()) {
3089 double times = (double) (end - region->last_frame()) / (double) region->length();
3095 pl->clear_changes ();
3096 pl->add_region (RegionFactory::create (region, true), region->last_frame(), times);
3097 _session->add_command (new StatefulDiffCommand (pl));
3100 commit_reversible_command ();
3104 Editor::region_fill_selection ()
3106 if (clicked_routeview == 0 || !clicked_routeview->is_audio_track()) {
3110 if (selection->time.empty()) {
3114 boost::shared_ptr<Region> region = _regions->get_single_selection ();
3119 framepos_t start = selection->time[clicked_selection].start;
3120 framepos_t end = selection->time[clicked_selection].end;
3122 boost::shared_ptr<Playlist> playlist;
3124 if (selection->tracks.empty()) {
3128 framepos_t selection_length = end - start;
3129 float times = (float)selection_length / region->length();
3131 begin_reversible_command (Operations::fill_selection);
3133 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
3135 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
3137 if ((playlist = (*i)->playlist()) == 0) {
3141 playlist->clear_changes ();
3142 playlist->add_region (RegionFactory::create (region, true), start, times);
3143 _session->add_command (new StatefulDiffCommand (playlist));
3146 commit_reversible_command ();
3150 Editor::set_region_sync_position ()
3152 set_sync_point (get_preferred_edit_position (), get_regions_from_selection_and_edit_point ());
3156 Editor::set_sync_point (framepos_t where, const RegionSelection& rs)
3158 bool in_command = false;
3160 for (RegionSelection::const_iterator r = rs.begin(); r != rs.end(); ++r) {
3162 if (!(*r)->region()->covers (where)) {
3166 boost::shared_ptr<Region> region ((*r)->region());
3169 begin_reversible_command (_("set sync point"));
3173 region->clear_changes ();
3174 region->set_sync_position (where);
3175 _session->add_command(new StatefulDiffCommand (region));
3179 commit_reversible_command ();
3183 /** Remove the sync positions of the selection */
3185 Editor::remove_region_sync ()
3187 RegionSelection rs = get_regions_from_selection_and_entered ();
3193 begin_reversible_command (_("remove region sync"));
3195 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3197 (*i)->region()->clear_changes ();
3198 (*i)->region()->clear_sync_position ();
3199 _session->add_command(new StatefulDiffCommand ((*i)->region()));
3202 commit_reversible_command ();
3206 Editor::naturalize_region ()
3208 RegionSelection rs = get_regions_from_selection_and_entered ();
3214 if (rs.size() > 1) {
3215 begin_reversible_command (_("move regions to original position"));
3217 begin_reversible_command (_("move region to original position"));
3220 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3221 (*i)->region()->clear_changes ();
3222 (*i)->region()->move_to_natural_position ();
3223 _session->add_command (new StatefulDiffCommand ((*i)->region()));
3226 commit_reversible_command ();
3230 Editor::align_regions (RegionPoint what)
3232 RegionSelection const rs = get_regions_from_selection_and_edit_point ();
3238 begin_reversible_command (_("align selection"));
3240 framepos_t const position = get_preferred_edit_position ();
3242 for (RegionSelection::const_iterator i = rs.begin(); i != rs.end(); ++i) {
3243 align_region_internal ((*i)->region(), what, position);
3246 commit_reversible_command ();
3249 struct RegionSortByTime {
3250 bool operator() (const RegionView* a, const RegionView* b) {
3251 return a->region()->position() < b->region()->position();
3256 Editor::align_regions_relative (RegionPoint point)
3258 RegionSelection const rs = get_regions_from_selection_and_edit_point ();
3264 framepos_t const position = get_preferred_edit_position ();
3266 framepos_t distance = 0;
3270 list<RegionView*> sorted;
3271 rs.by_position (sorted);
3273 boost::shared_ptr<Region> r ((*sorted.begin())->region());
3278 if (position > r->position()) {
3279 distance = position - r->position();
3281 distance = r->position() - position;
3287 if (position > r->last_frame()) {
3288 distance = position - r->last_frame();
3289 pos = r->position() + distance;
3291 distance = r->last_frame() - position;
3292 pos = r->position() - distance;
3298 pos = r->adjust_to_sync (position);
3299 if (pos > r->position()) {
3300 distance = pos - r->position();
3302 distance = r->position() - pos;
3308 if (pos == r->position()) {
3312 begin_reversible_command (_("align selection (relative)"));
3314 /* move first one specially */
3316 r->clear_changes ();
3317 r->set_position (pos);
3318 _session->add_command(new StatefulDiffCommand (r));
3320 /* move rest by the same amount */
3324 for (list<RegionView*>::iterator i = sorted.begin(); i != sorted.end(); ++i) {
3326 boost::shared_ptr<Region> region ((*i)->region());
3328 region->clear_changes ();
3331 region->set_position (region->position() + distance);
3333 region->set_position (region->position() - distance);
3336 _session->add_command(new StatefulDiffCommand (region));
3340 commit_reversible_command ();
3344 Editor::align_region (boost::shared_ptr<Region> region, RegionPoint point, framepos_t position)
3346 begin_reversible_command (_("align region"));
3347 align_region_internal (region, point, position);
3348 commit_reversible_command ();
3352 Editor::align_region_internal (boost::shared_ptr<Region> region, RegionPoint point, framepos_t position)
3354 region->clear_changes ();
3358 region->set_position (region->adjust_to_sync (position));
3362 if (position > region->length()) {
3363 region->set_position (position - region->length());
3368 region->set_position (position);
3372 _session->add_command(new StatefulDiffCommand (region));
3376 Editor::trim_region_front ()
3382 Editor::trim_region_back ()
3384 trim_region (false);
3388 Editor::trim_region (bool front)
3390 framepos_t where = get_preferred_edit_position();
3391 RegionSelection rs = get_regions_from_selection_and_edit_point ();
3397 begin_reversible_command (front ? _("trim front") : _("trim back"));
3399 for (list<RegionView*>::const_iterator i = rs.by_layer().begin(); i != rs.by_layer().end(); ++i) {
3400 if (!(*i)->region()->locked()) {
3402 (*i)->region()->clear_changes ();
3405 (*i)->region()->trim_front (where);
3406 maybe_locate_with_edit_preroll ( where );
3408 (*i)->region()->trim_end (where);
3409 maybe_locate_with_edit_preroll ( where );
3412 _session->add_command (new StatefulDiffCommand ((*i)->region()));
3416 commit_reversible_command ();
3419 /** Trim the end of the selected regions to the position of the edit cursor */
3421 Editor::trim_region_to_loop ()
3423 Location* loc = _session->locations()->auto_loop_location();
3427 trim_region_to_location (*loc, _("trim to loop"));
3431 Editor::trim_region_to_punch ()
3433 Location* loc = _session->locations()->auto_punch_location();
3437 trim_region_to_location (*loc, _("trim to punch"));
3441 Editor::trim_region_to_location (const Location& loc, const char* str)
3443 RegionSelection rs = get_regions_from_selection_and_entered ();
3445 begin_reversible_command (str);
3447 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
3448 RegionView* rv = (*x);
3450 /* require region to span proposed trim */
3451 switch (rv->region()->coverage (loc.start(), loc.end())) {
3452 case Evoral::OverlapInternal:
3458 RouteTimeAxisView* tav = dynamic_cast<RouteTimeAxisView*> (&rv->get_time_axis_view());
3467 if (tav->track() != 0) {
3468 speed = tav->track()->speed();
3471 start = session_frame_to_track_frame (loc.start(), speed);
3472 end = session_frame_to_track_frame (loc.end(), speed);
3474 rv->region()->clear_changes ();
3475 rv->region()->trim_to (start, (end - start));
3476 _session->add_command(new StatefulDiffCommand (rv->region()));
3479 commit_reversible_command ();
3483 Editor::trim_region_to_previous_region_end ()
3485 return trim_to_region(false);
3489 Editor::trim_region_to_next_region_start ()
3491 return trim_to_region(true);
3495 Editor::trim_to_region(bool forward)
3497 RegionSelection rs = get_regions_from_selection_and_entered ();
3499 begin_reversible_command (_("trim to region"));
3501 boost::shared_ptr<Region> next_region;
3503 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
3505 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*x);
3511 AudioTimeAxisView* atav = dynamic_cast<AudioTimeAxisView*> (&arv->get_time_axis_view());
3519 if (atav->track() != 0) {
3520 speed = atav->track()->speed();
3524 boost::shared_ptr<Region> region = arv->region();
3525 boost::shared_ptr<Playlist> playlist (region->playlist());
3527 region->clear_changes ();
3531 next_region = playlist->find_next_region (region->first_frame(), Start, 1);
3537 region->trim_end((framepos_t) ( (next_region->first_frame() - 1) * speed));
3538 arv->region_changed (PropertyChange (ARDOUR::Properties::length));
3542 next_region = playlist->find_next_region (region->first_frame(), Start, 0);
3548 region->trim_front((framepos_t) ((next_region->last_frame() + 1) * speed));
3550 arv->region_changed (ARDOUR::bounds_change);
3553 _session->add_command(new StatefulDiffCommand (region));
3556 commit_reversible_command ();
3560 Editor::unfreeze_route ()
3562 if (clicked_routeview == 0 || !clicked_routeview->is_track()) {
3566 clicked_routeview->track()->unfreeze ();
3570 Editor::_freeze_thread (void* arg)
3572 return static_cast<Editor*>(arg)->freeze_thread ();
3576 Editor::freeze_thread ()
3578 /* create event pool because we may need to talk to the session */
3579 SessionEvent::create_per_thread_pool ("freeze events", 64);
3580 /* create per-thread buffers for process() tree to use */
3581 clicked_routeview->audio_track()->freeze_me (*current_interthread_info);
3582 current_interthread_info->done = true;
3587 Editor::freeze_route ()
3593 /* stop transport before we start. this is important */
3595 _session->request_transport_speed (0.0);
3597 /* wait for just a little while, because the above call is asynchronous */
3599 Glib::usleep (250000);
3601 if (clicked_routeview == 0 || !clicked_routeview->is_audio_track()) {
3605 if (!clicked_routeview->track()->bounceable (clicked_routeview->track()->main_outs(), true)) {
3607 _("This track/bus cannot be frozen because the signal adds or loses channels before reaching the outputs.\n"
3608 "This is typically caused by plugins that generate stereo output from mono input or vice versa.")
3610 d.set_title (_("Cannot freeze"));
3615 if (clicked_routeview->track()->has_external_redirects()) {
3616 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"
3617 "Freezing will only process the signal as far as the first send/insert/return."),
3618 clicked_routeview->track()->name()), true, MESSAGE_INFO, BUTTONS_NONE, true);
3620 d.add_button (_("Freeze anyway"), Gtk::RESPONSE_OK);
3621 d.add_button (_("Don't freeze"), Gtk::RESPONSE_CANCEL);
3622 d.set_title (_("Freeze Limits"));
3624 int response = d.run ();
3627 case Gtk::RESPONSE_CANCEL:
3634 InterThreadInfo itt;
3635 current_interthread_info = &itt;
3637 InterthreadProgressWindow ipw (current_interthread_info, _("Freeze"), _("Cancel Freeze"));
3639 pthread_create_and_store (X_("freezer"), &itt.thread, _freeze_thread, this);
3641 set_canvas_cursor (_cursors->wait);
3643 while (!itt.done && !itt.cancel) {
3644 gtk_main_iteration ();
3647 current_interthread_info = 0;
3648 set_canvas_cursor (current_canvas_cursor);
3652 Editor::bounce_range_selection (bool replace, bool enable_processing)
3654 if (selection->time.empty()) {
3658 TrackSelection views = selection->tracks;
3660 for (TrackViewList::iterator i = views.begin(); i != views.end(); ++i) {
3662 if (enable_processing) {
3664 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*i);
3666 if (rtv && rtv->track() && replace && enable_processing && !rtv->track()->bounceable (rtv->track()->main_outs(), false)) {
3668 _("You can't perform this operation because the processing of the signal "
3669 "will cause one or more of the tracks to end up with a region with more channels than this track has inputs.\n\n"
3670 "You can do this without processing, which is a different operation.")
3672 d.set_title (_("Cannot bounce"));
3679 framepos_t start = selection->time[clicked_selection].start;
3680 framepos_t end = selection->time[clicked_selection].end;
3681 framepos_t cnt = end - start + 1;
3683 begin_reversible_command (_("bounce range"));
3685 for (TrackViewList::iterator i = views.begin(); i != views.end(); ++i) {
3687 RouteTimeAxisView* rtv;
3689 if ((rtv = dynamic_cast<RouteTimeAxisView*> (*i)) == 0) {
3693 boost::shared_ptr<Playlist> playlist;
3695 if ((playlist = rtv->playlist()) == 0) {
3699 InterThreadInfo itt;
3701 playlist->clear_changes ();
3702 playlist->clear_owned_changes ();
3704 boost::shared_ptr<Region> r;
3706 if (enable_processing) {
3707 r = rtv->track()->bounce_range (start, start+cnt, itt, rtv->track()->main_outs(), false);
3709 r = rtv->track()->bounce_range (start, start+cnt, itt, boost::shared_ptr<Processor>(), false);
3717 list<AudioRange> ranges;
3718 ranges.push_back (AudioRange (start, start+cnt, 0));
3719 playlist->cut (ranges); // discard result
3720 playlist->add_region (r, start);
3723 vector<Command*> cmds;
3724 playlist->rdiff (cmds);
3725 _session->add_commands (cmds);
3727 _session->add_command (new StatefulDiffCommand (playlist));
3730 commit_reversible_command ();
3733 /** Delete selected regions, automation points or a time range */
3737 //special case: if the user is pointing in the editor/mixer strip, they may be trying to delete a plugin.
3738 //we need this because the editor-mixer strip is in the editor window, so it doesn't get the bindings from the mix window
3739 bool deleted = false;
3740 if ( current_mixer_strip && current_mixer_strip == MixerStrip::entered_mixer_strip() )
3741 deleted = current_mixer_strip->delete_processors ();
3747 /** Cut selected regions, automation points or a time range */
3754 /** Copy selected regions, automation points or a time range */
3762 /** @return true if a Cut, Copy or Clear is possible */
3764 Editor::can_cut_copy () const
3766 if (!selection->time.empty() || !selection->regions.empty() || !selection->points.empty())
3773 /** Cut, copy or clear selected regions, automation points or a time range.
3774 * @param op Operation (Delete, Cut, Copy or Clear)
3777 Editor::cut_copy (CutCopyOp op)
3779 /* only cancel selection if cut/copy is successful.*/
3785 opname = _("delete");
3794 opname = _("clear");
3798 /* if we're deleting something, and the mouse is still pressed,
3799 the thing we started a drag for will be gone when we release
3800 the mouse button(s). avoid this. see part 2 at the end of
3804 if (op == Delete || op == Cut || op == Clear) {
3805 if (_drags->active ()) {
3810 if ( op != Delete ) //"Delete" doesn't change copy/paste buf
3811 cut_buffer->clear ();
3813 if (entered_marker) {
3815 /* cut/delete op while pointing at a marker */
3818 Location* loc = find_location_from_marker (entered_marker, ignored);
3820 if (_session && loc) {
3821 Glib::signal_idle().connect (sigc::bind (sigc::mem_fun(*this, &Editor::really_remove_marker), loc));
3828 if (internal_editing()) {
3830 switch (effective_mouse_mode()) {
3833 begin_reversible_command (opname + ' ' + X_("MIDI"));
3835 commit_reversible_command ();
3844 bool did_edit = false;
3846 if (!selection->points.empty()) {
3847 begin_reversible_command (opname + _(" points"));
3849 cut_copy_points (op);
3850 if (op == Cut || op == Delete) {
3851 selection->clear_points ();
3853 } else if (!selection->regions.empty() || !selection->points.empty()) {
3857 if (selection->regions.empty()) {
3858 thing_name = _("points");
3859 } else if (selection->points.empty()) {
3860 thing_name = _("regions");
3862 thing_name = _("objects");
3865 begin_reversible_command (opname + ' ' + thing_name);
3868 if (!selection->regions.empty()) {
3869 cut_copy_regions (op, selection->regions);
3871 if (op == Cut || op == Delete) {
3872 selection->clear_regions ();
3876 if (!selection->points.empty()) {
3877 cut_copy_points (op);
3879 if (op == Cut || op == Delete) {
3880 selection->clear_points ();
3883 } else if (selection->time.empty()) {
3884 framepos_t start, end;
3885 /* no time selection, see if we can get an edit range
3888 if (get_edit_op_range (start, end)) {
3889 selection->set (start, end);
3891 } else if (!selection->time.empty()) {
3892 begin_reversible_command (opname + _(" range"));
3895 cut_copy_ranges (op);
3897 if (op == Cut || op == Delete) {
3898 selection->clear_time ();
3903 commit_reversible_command ();
3906 if (op == Delete || op == Cut || op == Clear) {
3911 struct AutomationRecord {
3912 AutomationRecord () : state (0) {}
3913 AutomationRecord (XMLNode* s) : state (s) {}
3915 XMLNode* state; ///< state before any operation
3916 boost::shared_ptr<Evoral::ControlList> copy; ///< copied events for the cut buffer
3919 /** Cut, copy or clear selected automation points.
3920 * @param op Operation (Cut, Copy or Clear)
3923 Editor::cut_copy_points (CutCopyOp op)
3925 if (selection->points.empty ()) {
3929 /* XXX: not ideal, as there may be more than one track involved in the point selection */
3930 _last_cut_copy_source_track = &selection->points.front()->line().trackview;
3932 /* Keep a record of the AutomationLists that we end up using in this operation */
3933 typedef std::map<boost::shared_ptr<AutomationList>, AutomationRecord> Lists;
3936 /* Go through all selected points, making an AutomationRecord for each distinct AutomationList */
3937 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
3938 boost::shared_ptr<AutomationList> al = (*i)->line().the_list();
3939 if (lists.find (al) == lists.end ()) {
3940 /* We haven't seen this list yet, so make a record for it. This includes
3941 taking a copy of its current state, in case this is needed for undo later.
3943 lists[al] = AutomationRecord (&al->get_state ());
3947 if (op == Cut || op == Copy) {
3948 /* This operation will involve putting things in the cut buffer, so create an empty
3949 ControlList for each of our source lists to put the cut buffer data in.
3951 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
3952 i->second.copy = i->first->create (i->first->parameter ());
3955 /* Add all selected points to the relevant copy ControlLists */
3956 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
3957 boost::shared_ptr<AutomationList> al = (*i)->line().the_list();
3958 AutomationList::const_iterator j = (*i)->model ();
3959 lists[al].copy->add ((*j)->when, (*j)->value);
3962 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
3963 /* Correct this copy list so that it starts at time 0 */
3964 double const start = i->second.copy->front()->when;
3965 for (AutomationList::iterator j = i->second.copy->begin(); j != i->second.copy->end(); ++j) {
3966 (*j)->when -= start;
3969 /* And add it to the cut buffer */
3970 cut_buffer->add (i->second.copy);
3974 if (op == Delete || op == Cut) {
3975 /* This operation needs to remove things from the main AutomationList, so do that now */
3977 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
3978 i->first->freeze ();
3981 /* Remove each selected point from its AutomationList */
3982 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
3983 boost::shared_ptr<AutomationList> al = (*i)->line().the_list();
3984 al->erase ((*i)->model ());
3987 /* Thaw the lists and add undo records for them */
3988 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
3989 boost::shared_ptr<AutomationList> al = i->first;
3991 _session->add_command (new MementoCommand<AutomationList> (*al.get(), i->second.state, &(al->get_state ())));
3996 /** Cut, copy or clear selected automation points.
3997 * @param op Operation (Cut, Copy or Clear)
4000 Editor::cut_copy_midi (CutCopyOp op)
4002 for (MidiRegionSelection::iterator i = selection->midi_regions.begin(); i != selection->midi_regions.end(); ++i) {
4003 MidiRegionView* mrv = *i;
4004 mrv->cut_copy_clear (op);
4010 struct lt_playlist {
4011 bool operator () (const PlaylistState& a, const PlaylistState& b) {
4012 return a.playlist < b.playlist;
4016 struct PlaylistMapping {
4018 boost::shared_ptr<Playlist> pl;
4020 PlaylistMapping (TimeAxisView* tvp) : tv (tvp) {}
4023 /** Remove `clicked_regionview' */
4025 Editor::remove_clicked_region ()
4027 if (clicked_routeview == 0 || clicked_regionview == 0) {
4031 boost::shared_ptr<Playlist> playlist = clicked_routeview->playlist();
4033 playlist->clear_changes ();
4034 playlist->clear_owned_changes ();
4035 playlist->remove_region (clicked_regionview->region());
4036 if (Config->get_edit_mode() == Ripple)
4037 playlist->ripple (clicked_regionview->region()->position(), -clicked_regionview->region()->length(), boost::shared_ptr<Region>());
4039 /* We might have removed regions, which alters other regions' layering_index,
4040 so we need to do a recursive diff here.
4042 vector<Command*> cmds;
4043 playlist->rdiff (cmds);
4044 _session->add_commands (cmds);
4046 _session->add_command(new StatefulDiffCommand (playlist));
4047 commit_reversible_command ();
4051 /** Remove the selected regions */
4053 Editor::remove_selected_regions ()
4055 RegionSelection rs = get_regions_from_selection_and_entered ();
4057 if (!_session || rs.empty()) {
4061 begin_reversible_command (_("remove region"));
4063 list<boost::shared_ptr<Region> > regions_to_remove;
4065 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
4066 // we can't just remove the region(s) in this loop because
4067 // this removes them from the RegionSelection, and they thus
4068 // disappear from underneath the iterator, and the ++i above
4069 // SEGVs in a puzzling fashion.
4071 // so, first iterate over the regions to be removed from rs and
4072 // add them to the regions_to_remove list, and then
4073 // iterate over the list to actually remove them.
4075 regions_to_remove.push_back ((*i)->region());
4078 vector<boost::shared_ptr<Playlist> > playlists;
4080 for (list<boost::shared_ptr<Region> >::iterator rl = regions_to_remove.begin(); rl != regions_to_remove.end(); ++rl) {
4082 boost::shared_ptr<Playlist> playlist = (*rl)->playlist();
4085 // is this check necessary?
4089 /* get_regions_from_selection_and_entered() guarantees that
4090 the playlists involved are unique, so there is no need
4094 playlists.push_back (playlist);
4096 playlist->clear_changes ();
4097 playlist->clear_owned_changes ();
4098 playlist->freeze ();
4099 playlist->remove_region (*rl);
4100 if (Config->get_edit_mode() == Ripple)
4101 playlist->ripple ((*rl)->position(), -(*rl)->length(), boost::shared_ptr<Region>());
4105 vector<boost::shared_ptr<Playlist> >::iterator pl;
4107 for (pl = playlists.begin(); pl != playlists.end(); ++pl) {
4110 /* We might have removed regions, which alters other regions' layering_index,
4111 so we need to do a recursive diff here.
4113 vector<Command*> cmds;
4114 (*pl)->rdiff (cmds);
4115 _session->add_commands (cmds);
4117 _session->add_command(new StatefulDiffCommand (*pl));
4120 commit_reversible_command ();
4123 /** Cut, copy or clear selected regions.
4124 * @param op Operation (Cut, Copy or Clear)
4127 Editor::cut_copy_regions (CutCopyOp op, RegionSelection& rs)
4129 /* we can't use a std::map here because the ordering is important, and we can't trivially sort
4130 a map when we want ordered access to both elements. i think.
4133 vector<PlaylistMapping> pmap;
4135 framepos_t first_position = max_framepos;
4137 typedef set<boost::shared_ptr<Playlist> > FreezeList;
4138 FreezeList freezelist;
4140 /* get ordering correct before we cut/copy */
4142 rs.sort_by_position_and_track ();
4144 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
4146 first_position = min ((framepos_t) (*x)->region()->position(), first_position);
4148 if (op == Cut || op == Clear || op == Delete) {
4149 boost::shared_ptr<Playlist> pl = (*x)->region()->playlist();
4152 FreezeList::iterator fl;
4154 // only take state if this is a new playlist.
4155 for (fl = freezelist.begin(); fl != freezelist.end(); ++fl) {
4161 if (fl == freezelist.end()) {
4162 pl->clear_changes();
4163 pl->clear_owned_changes ();
4165 freezelist.insert (pl);
4170 TimeAxisView* tv = &(*x)->get_time_axis_view();
4171 vector<PlaylistMapping>::iterator z;
4173 for (z = pmap.begin(); z != pmap.end(); ++z) {
4174 if ((*z).tv == tv) {
4179 if (z == pmap.end()) {
4180 pmap.push_back (PlaylistMapping (tv));
4184 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ) {
4186 boost::shared_ptr<Playlist> pl = (*x)->region()->playlist();
4189 /* region not yet associated with a playlist (e.g. unfinished
4196 TimeAxisView& tv = (*x)->get_time_axis_view();
4197 boost::shared_ptr<Playlist> npl;
4198 RegionSelection::iterator tmp;
4205 vector<PlaylistMapping>::iterator z;
4207 for (z = pmap.begin(); z != pmap.end(); ++z) {
4208 if ((*z).tv == &tv) {
4213 assert (z != pmap.end());
4216 npl = PlaylistFactory::create (pl->data_type(), *_session, "cutlist", true);
4224 boost::shared_ptr<Region> r = (*x)->region();
4225 boost::shared_ptr<Region> _xx;
4231 pl->remove_region (r);
4232 if (Config->get_edit_mode() == Ripple)
4233 pl->ripple (r->position(), -r->length(), boost::shared_ptr<Region>());
4237 _xx = RegionFactory::create (r);
4238 npl->add_region (_xx, r->position() - first_position);
4239 pl->remove_region (r);
4240 if (Config->get_edit_mode() == Ripple)
4241 pl->ripple (r->position(), -r->length(), boost::shared_ptr<Region>());
4245 /* copy region before adding, so we're not putting same object into two different playlists */
4246 npl->add_region (RegionFactory::create (r), r->position() - first_position);
4250 pl->remove_region (r);
4251 if (Config->get_edit_mode() == Ripple)
4252 pl->ripple (r->position(), -r->length(), boost::shared_ptr<Region>());
4261 list<boost::shared_ptr<Playlist> > foo;
4263 /* the pmap is in the same order as the tracks in which selected regions occured */
4265 for (vector<PlaylistMapping>::iterator i = pmap.begin(); i != pmap.end(); ++i) {
4268 foo.push_back ((*i).pl);
4273 cut_buffer->set (foo);
4277 _last_cut_copy_source_track = 0;
4279 _last_cut_copy_source_track = pmap.front().tv;
4283 for (FreezeList::iterator pl = freezelist.begin(); pl != freezelist.end(); ++pl) {
4286 /* We might have removed regions, which alters other regions' layering_index,
4287 so we need to do a recursive diff here.
4289 vector<Command*> cmds;
4290 (*pl)->rdiff (cmds);
4291 _session->add_commands (cmds);
4293 _session->add_command (new StatefulDiffCommand (*pl));
4298 Editor::cut_copy_ranges (CutCopyOp op)
4300 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4302 /* Sort the track selection now, so that it if is used, the playlists
4303 selected by the calls below to cut_copy_clear are in the order that
4304 their tracks appear in the editor. This makes things like paste
4305 of ranges work properly.
4308 sort_track_selection (ts);
4311 if (!entered_track) {
4314 ts.push_back (entered_track);
4317 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4318 (*i)->cut_copy_clear (*selection, op);
4323 Editor::paste (float times, bool from_context)
4325 DEBUG_TRACE (DEBUG::CutNPaste, "paste to preferred edit pos\n");
4327 paste_internal (get_preferred_edit_position (false, from_context), times);
4331 Editor::mouse_paste ()
4336 if (!mouse_frame (where, ignored)) {
4341 paste_internal (where, 1);
4345 Editor::paste_internal (framepos_t position, float times)
4347 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("apparent paste position is %1\n", position));
4349 if (internal_editing()) {
4350 if (cut_buffer->midi_notes.empty()) {
4354 if (cut_buffer->empty()) {
4359 if (position == max_framepos) {
4360 position = get_preferred_edit_position();
4361 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("preferred edit position is %1\n", position));
4365 TrackViewList::iterator i;
4368 /* get everything in the correct order */
4370 if (_edit_point == Editing::EditAtMouse && entered_track) {
4371 /* With the mouse edit point, paste onto the track under the mouse */
4372 ts.push_back (entered_track);
4373 } else if (!selection->tracks.empty()) {
4374 /* Otherwise, if there are some selected tracks, paste to them */
4375 ts = selection->tracks.filter_to_unique_playlists ();
4376 sort_track_selection (ts);
4377 } else if (_last_cut_copy_source_track) {
4378 /* Otherwise paste to the track that the cut/copy came from;
4379 see discussion in mantis #3333.
4381 ts.push_back (_last_cut_copy_source_track);
4384 if (internal_editing ()) {
4386 /* undo/redo is handled by individual tracks/regions */
4388 for (nth = 0, i = ts.begin(); i != ts.end(); ++i, ++nth) {
4391 RegionSelection::iterator r;
4392 MidiNoteSelection::iterator cb;
4394 get_regions_at (rs, position, ts);
4396 for (cb = cut_buffer->midi_notes.begin(), r = rs.begin();
4397 cb != cut_buffer->midi_notes.end() && r != rs.end(); ++r) {
4398 MidiRegionView* mrv = dynamic_cast<MidiRegionView*> (*r);
4400 mrv->paste (position, times, **cb);
4408 /* we do redo (do you do voodoo?) */
4410 begin_reversible_command (Operations::paste);
4412 for (nth = 0, i = ts.begin(); i != ts.end(); ++i, ++nth) {
4413 (*i)->paste (position, times, *cut_buffer, nth);
4416 commit_reversible_command ();
4421 Editor::duplicate_some_regions (RegionSelection& regions, float times)
4423 boost::shared_ptr<Playlist> playlist;
4424 RegionSelection sel = regions; // clear (below) may clear the argument list if its the current region selection
4425 RegionSelection foo;
4427 framepos_t const start_frame = regions.start ();
4428 framepos_t const end_frame = regions.end_frame ();
4430 begin_reversible_command (Operations::duplicate_region);
4432 selection->clear_regions ();
4434 for (RegionSelection::iterator i = sel.begin(); i != sel.end(); ++i) {
4436 boost::shared_ptr<Region> r ((*i)->region());
4438 TimeAxisView& tv = (*i)->get_time_axis_view();
4439 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (&tv);
4440 latest_regionviews.clear ();
4441 sigc::connection c = rtv->view()->RegionViewAdded.connect (sigc::mem_fun(*this, &Editor::collect_new_region_view));
4443 playlist = (*i)->region()->playlist();
4444 playlist->clear_changes ();
4445 playlist->duplicate (r, end_frame + (r->first_frame() - start_frame), times);
4446 _session->add_command(new StatefulDiffCommand (playlist));
4450 foo.insert (foo.end(), latest_regionviews.begin(), latest_regionviews.end());
4453 commit_reversible_command ();
4456 selection->set (foo);
4461 Editor::duplicate_selection (float times)
4463 if (selection->time.empty() || selection->tracks.empty()) {
4467 boost::shared_ptr<Playlist> playlist;
4468 vector<boost::shared_ptr<Region> > new_regions;
4469 vector<boost::shared_ptr<Region> >::iterator ri;
4471 create_region_from_selection (new_regions);
4473 if (new_regions.empty()) {
4477 begin_reversible_command (_("duplicate selection"));
4479 ri = new_regions.begin();
4481 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4483 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4484 if ((playlist = (*i)->playlist()) == 0) {
4487 playlist->clear_changes ();
4488 playlist->duplicate (*ri, selection->time[clicked_selection].end, times);
4489 _session->add_command (new StatefulDiffCommand (playlist));
4492 if (ri == new_regions.end()) {
4497 commit_reversible_command ();
4500 /** Reset all selected points to the relevant default value */
4502 Editor::reset_point_selection ()
4504 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
4505 ARDOUR::AutomationList::iterator j = (*i)->model ();
4506 (*j)->value = (*i)->line().the_list()->default_value ();
4511 Editor::center_playhead ()
4513 float const page = _visible_canvas_width * samples_per_pixel;
4514 center_screen_internal (playhead_cursor->current_frame (), page);
4518 Editor::center_edit_point ()
4520 float const page = _visible_canvas_width * samples_per_pixel;
4521 center_screen_internal (get_preferred_edit_position(), page);
4524 /** Caller must begin and commit a reversible command */
4526 Editor::clear_playlist (boost::shared_ptr<Playlist> playlist)
4528 playlist->clear_changes ();
4530 _session->add_command (new StatefulDiffCommand (playlist));
4534 Editor::nudge_track (bool use_edit, bool forwards)
4536 boost::shared_ptr<Playlist> playlist;
4537 framepos_t distance;
4538 framepos_t next_distance;
4542 start = get_preferred_edit_position();
4547 if ((distance = get_nudge_distance (start, next_distance)) == 0) {
4551 if (selection->tracks.empty()) {
4555 begin_reversible_command (_("nudge track"));
4557 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4559 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4561 if ((playlist = (*i)->playlist()) == 0) {
4565 playlist->clear_changes ();
4566 playlist->clear_owned_changes ();
4568 playlist->nudge_after (start, distance, forwards);
4570 vector<Command*> cmds;
4572 playlist->rdiff (cmds);
4573 _session->add_commands (cmds);
4575 _session->add_command (new StatefulDiffCommand (playlist));
4578 commit_reversible_command ();
4582 Editor::remove_last_capture ()
4584 vector<string> choices;
4591 if (Config->get_verify_remove_last_capture()) {
4592 prompt = _("Do you really want to destroy the last capture?"
4593 "\n(This is destructive and cannot be undone)");
4595 choices.push_back (_("No, do nothing."));
4596 choices.push_back (_("Yes, destroy it."));
4598 Gtkmm2ext::Choice prompter (_("Destroy last capture"), prompt, choices);
4600 if (prompter.run () == 1) {
4601 _session->remove_last_capture ();
4602 _regions->redisplay ();
4606 _session->remove_last_capture();
4607 _regions->redisplay ();
4612 Editor::normalize_region ()
4618 RegionSelection rs = get_regions_from_selection_and_entered ();
4624 NormalizeDialog dialog (rs.size() > 1);
4626 if (dialog.run () == RESPONSE_CANCEL) {
4630 set_canvas_cursor (_cursors->wait);
4633 /* XXX: should really only count audio regions here */
4634 int const regions = rs.size ();
4636 /* Make a list of the selected audio regions' maximum amplitudes, and also
4637 obtain the maximum amplitude of them all.
4639 list<double> max_amps;
4641 for (RegionSelection::const_iterator i = rs.begin(); i != rs.end(); ++i) {
4642 AudioRegionView const * arv = dynamic_cast<AudioRegionView const *> (*i);
4644 dialog.descend (1.0 / regions);
4645 double const a = arv->audio_region()->maximum_amplitude (&dialog);
4648 /* the user cancelled the operation */
4649 set_canvas_cursor (current_canvas_cursor);
4653 max_amps.push_back (a);
4654 max_amp = max (max_amp, a);
4659 begin_reversible_command (_("normalize"));
4661 list<double>::const_iterator a = max_amps.begin ();
4663 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
4664 AudioRegionView* const arv = dynamic_cast<AudioRegionView*> (*r);
4669 arv->region()->clear_changes ();
4671 double const amp = dialog.normalize_individually() ? *a : max_amp;
4673 arv->audio_region()->normalize (amp, dialog.target ());
4674 _session->add_command (new StatefulDiffCommand (arv->region()));
4679 commit_reversible_command ();
4680 set_canvas_cursor (current_canvas_cursor);
4685 Editor::reset_region_scale_amplitude ()
4691 RegionSelection rs = get_regions_from_selection_and_entered ();
4697 begin_reversible_command ("reset gain");
4699 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
4700 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
4703 arv->region()->clear_changes ();
4704 arv->audio_region()->set_scale_amplitude (1.0f);
4705 _session->add_command (new StatefulDiffCommand (arv->region()));
4708 commit_reversible_command ();
4712 Editor::adjust_region_gain (bool up)
4714 RegionSelection rs = get_regions_from_selection_and_entered ();
4716 if (!_session || rs.empty()) {
4720 begin_reversible_command ("adjust region gain");
4722 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
4723 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
4728 arv->region()->clear_changes ();
4730 double dB = accurate_coefficient_to_dB (arv->audio_region()->scale_amplitude ());
4738 arv->audio_region()->set_scale_amplitude (dB_to_coefficient (dB));
4739 _session->add_command (new StatefulDiffCommand (arv->region()));
4742 commit_reversible_command ();
4747 Editor::reverse_region ()
4753 Reverse rev (*_session);
4754 apply_filter (rev, _("reverse regions"));
4758 Editor::strip_region_silence ()
4764 RegionSelection rs = get_regions_from_selection_and_entered ();
4770 std::list<RegionView*> audio_only;
4772 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
4773 AudioRegionView* const arv = dynamic_cast<AudioRegionView*> (*i);
4775 audio_only.push_back (arv);
4779 StripSilenceDialog d (_session, audio_only);
4780 int const r = d.run ();
4784 if (r == Gtk::RESPONSE_OK) {
4785 ARDOUR::AudioIntervalMap silences;
4786 d.silences (silences);
4787 StripSilence s (*_session, silences, d.fade_length());
4788 apply_filter (s, _("strip silence"), &d);
4793 Editor::apply_midi_note_edit_op_to_region (MidiOperator& op, MidiRegionView& mrv)
4795 Evoral::Sequence<Evoral::MusicalTime>::Notes selected;
4796 mrv.selection_as_notelist (selected, true);
4798 vector<Evoral::Sequence<Evoral::MusicalTime>::Notes> v;
4799 v.push_back (selected);
4801 framepos_t pos_frames = mrv.midi_region()->position() - mrv.midi_region()->start();
4802 double pos_beats = _session->tempo_map().framewalk_to_beats(0, pos_frames);
4804 return op (mrv.midi_region()->model(), pos_beats, v);
4808 Editor::apply_midi_note_edit_op (MidiOperator& op)
4812 RegionSelection rs = get_regions_from_selection_and_entered ();
4818 begin_reversible_command (op.name ());
4820 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
4821 RegionSelection::iterator tmp = r;
4824 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*r);
4827 cmd = apply_midi_note_edit_op_to_region (op, *mrv);
4830 _session->add_command (cmd);
4837 commit_reversible_command ();
4841 Editor::fork_region ()
4843 RegionSelection rs = get_regions_from_selection_and_entered ();
4849 begin_reversible_command (_("Fork Region(s)"));
4851 set_canvas_cursor (_cursors->wait);
4854 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
4855 RegionSelection::iterator tmp = r;
4858 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*>(*r);
4862 boost::shared_ptr<Playlist> playlist = mrv->region()->playlist();
4863 boost::shared_ptr<MidiSource> new_source = _session->create_midi_source_by_stealing_name (mrv->midi_view()->track());
4864 boost::shared_ptr<MidiRegion> newregion = mrv->midi_region()->clone (new_source);
4866 playlist->clear_changes ();
4867 playlist->replace_region (mrv->region(), newregion, mrv->region()->position());
4868 _session->add_command(new StatefulDiffCommand (playlist));
4870 error << string_compose (_("Could not unlink %1"), mrv->region()->name()) << endmsg;
4877 commit_reversible_command ();
4879 set_canvas_cursor (current_canvas_cursor);
4883 Editor::quantize_region ()
4885 int selected_midi_region_cnt = 0;
4891 RegionSelection rs = get_regions_from_selection_and_entered ();
4897 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
4898 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*r);
4900 selected_midi_region_cnt++;
4904 if (selected_midi_region_cnt == 0) {
4908 QuantizeDialog* qd = new QuantizeDialog (*this);
4911 const int r = qd->run ();
4914 if (r == Gtk::RESPONSE_OK) {
4915 Quantize quant (*_session, qd->snap_start(), qd->snap_end(),
4916 qd->start_grid_size(), qd->end_grid_size(),
4917 qd->strength(), qd->swing(), qd->threshold());
4919 apply_midi_note_edit_op (quant);
4924 Editor::insert_patch_change (bool from_context)
4926 RegionSelection rs = get_regions_from_selection_and_entered ();
4932 const framepos_t p = get_preferred_edit_position (false, from_context);
4934 /* XXX: bit of a hack; use the MIDNAM from the first selected region;
4935 there may be more than one, but the PatchChangeDialog can only offer
4936 one set of patch menus.
4938 MidiRegionView* first = dynamic_cast<MidiRegionView*> (rs.front ());
4940 Evoral::PatchChange<Evoral::MusicalTime> empty (0, 0, 0, 0);
4941 PatchChangeDialog d (0, _session, empty, first->instrument_info(), Gtk::Stock::ADD);
4943 if (d.run() == RESPONSE_CANCEL) {
4947 for (RegionSelection::iterator i = rs.begin (); i != rs.end(); ++i) {
4948 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*i);
4950 if (p >= mrv->region()->first_frame() && p <= mrv->region()->last_frame()) {
4951 mrv->add_patch_change (p - mrv->region()->position(), d.patch ());
4958 Editor::apply_filter (Filter& filter, string command, ProgressReporter* progress)
4960 RegionSelection rs = get_regions_from_selection_and_entered ();
4966 begin_reversible_command (command);
4968 set_canvas_cursor (_cursors->wait);
4972 int const N = rs.size ();
4974 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
4975 RegionSelection::iterator tmp = r;
4978 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
4980 boost::shared_ptr<Playlist> playlist = arv->region()->playlist();
4983 progress->descend (1.0 / N);
4986 if (arv->audio_region()->apply (filter, progress) == 0) {
4988 playlist->clear_changes ();
4989 playlist->clear_owned_changes ();
4991 if (filter.results.empty ()) {
4993 /* no regions returned; remove the old one */
4994 playlist->remove_region (arv->region ());
4998 std::vector<boost::shared_ptr<Region> >::iterator res = filter.results.begin ();
5000 /* first region replaces the old one */
5001 playlist->replace_region (arv->region(), *res, (*res)->position());
5005 while (res != filter.results.end()) {
5006 playlist->add_region (*res, (*res)->position());
5012 /* We might have removed regions, which alters other regions' layering_index,
5013 so we need to do a recursive diff here.
5015 vector<Command*> cmds;
5016 playlist->rdiff (cmds);
5017 _session->add_commands (cmds);
5019 _session->add_command(new StatefulDiffCommand (playlist));
5025 progress->ascend ();
5033 commit_reversible_command ();
5036 set_canvas_cursor (current_canvas_cursor);
5040 Editor::external_edit_region ()
5046 Editor::reset_region_gain_envelopes ()
5048 RegionSelection rs = get_regions_from_selection_and_entered ();
5050 if (!_session || rs.empty()) {
5054 _session->begin_reversible_command (_("reset region gain"));
5056 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5057 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
5059 boost::shared_ptr<AutomationList> alist (arv->audio_region()->envelope());
5060 XMLNode& before (alist->get_state());
5062 arv->audio_region()->set_default_envelope ();
5063 _session->add_command (new MementoCommand<AutomationList>(*arv->audio_region()->envelope().get(), &before, &alist->get_state()));
5067 _session->commit_reversible_command ();
5071 Editor::set_region_gain_visibility (RegionView* rv)
5073 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (rv);
5075 arv->update_envelope_visibility();
5080 Editor::set_gain_envelope_visibility ()
5086 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5087 AudioTimeAxisView* v = dynamic_cast<AudioTimeAxisView*>(*i);
5089 v->audio_view()->foreach_regionview (sigc::mem_fun (this, &Editor::set_region_gain_visibility));
5095 Editor::toggle_gain_envelope_active ()
5097 if (_ignore_region_action) {
5101 RegionSelection rs = get_regions_from_selection_and_entered ();
5103 if (!_session || rs.empty()) {
5107 _session->begin_reversible_command (_("region gain envelope active"));
5109 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5110 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
5112 arv->region()->clear_changes ();
5113 arv->audio_region()->set_envelope_active (!arv->audio_region()->envelope_active());
5114 _session->add_command (new StatefulDiffCommand (arv->region()));
5118 _session->commit_reversible_command ();
5122 Editor::toggle_region_lock ()
5124 if (_ignore_region_action) {
5128 RegionSelection rs = get_regions_from_selection_and_entered ();
5130 if (!_session || rs.empty()) {
5134 _session->begin_reversible_command (_("toggle region lock"));
5136 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5137 (*i)->region()->clear_changes ();
5138 (*i)->region()->set_locked (!(*i)->region()->locked());
5139 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5142 _session->commit_reversible_command ();
5146 Editor::toggle_region_video_lock ()
5148 if (_ignore_region_action) {
5152 RegionSelection rs = get_regions_from_selection_and_entered ();
5154 if (!_session || rs.empty()) {
5158 _session->begin_reversible_command (_("Toggle Video Lock"));
5160 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5161 (*i)->region()->clear_changes ();
5162 (*i)->region()->set_video_locked (!(*i)->region()->video_locked());
5163 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5166 _session->commit_reversible_command ();
5170 Editor::toggle_region_lock_style ()
5172 if (_ignore_region_action) {
5176 RegionSelection rs = get_regions_from_selection_and_entered ();
5178 if (!_session || rs.empty()) {
5182 _session->begin_reversible_command (_("region lock style"));
5184 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5185 (*i)->region()->clear_changes ();
5186 PositionLockStyle const ns = (*i)->region()->position_lock_style() == AudioTime ? MusicTime : AudioTime;
5187 (*i)->region()->set_position_lock_style (ns);
5188 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5191 _session->commit_reversible_command ();
5195 Editor::toggle_opaque_region ()
5197 if (_ignore_region_action) {
5201 RegionSelection rs = get_regions_from_selection_and_entered ();
5203 if (!_session || rs.empty()) {
5207 _session->begin_reversible_command (_("change region opacity"));
5209 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5210 (*i)->region()->clear_changes ();
5211 (*i)->region()->set_opaque (!(*i)->region()->opaque());
5212 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5215 _session->commit_reversible_command ();
5219 Editor::toggle_record_enable ()
5221 bool new_state = false;
5223 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5224 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5227 if (!rtav->is_track())
5231 new_state = !rtav->track()->record_enabled();
5235 rtav->track()->set_record_enabled (new_state, this);
5240 Editor::toggle_solo ()
5242 bool new_state = false;
5244 boost::shared_ptr<RouteList> rl (new RouteList);
5246 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5247 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5254 new_state = !rtav->route()->soloed ();
5258 rl->push_back (rtav->route());
5261 _session->set_solo (rl, new_state, Session::rt_cleanup, true);
5265 Editor::toggle_mute ()
5267 bool new_state = false;
5269 boost::shared_ptr<RouteList> rl (new RouteList);
5271 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5272 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5279 new_state = !rtav->route()->muted();
5283 rl->push_back (rtav->route());
5286 _session->set_mute (rl, new_state, Session::rt_cleanup, true);
5290 Editor::toggle_solo_isolate ()
5296 Editor::fade_range ()
5298 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
5300 begin_reversible_command (_("fade range"));
5302 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
5303 (*i)->fade_range (selection->time);
5306 commit_reversible_command ();
5311 Editor::set_fade_length (bool in)
5313 RegionSelection rs = get_regions_from_selection_and_entered ();
5319 /* we need a region to measure the offset from the start */
5321 RegionView* rv = rs.front ();
5323 framepos_t pos = get_preferred_edit_position();
5327 if (pos > rv->region()->last_frame() || pos < rv->region()->first_frame()) {
5328 /* edit point is outside the relevant region */
5333 if (pos <= rv->region()->position()) {
5337 len = pos - rv->region()->position();
5338 cmd = _("set fade in length");
5340 if (pos >= rv->region()->last_frame()) {
5344 len = rv->region()->last_frame() - pos;
5345 cmd = _("set fade out length");
5348 begin_reversible_command (cmd);
5350 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5351 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5357 boost::shared_ptr<AutomationList> alist;
5359 alist = tmp->audio_region()->fade_in();
5361 alist = tmp->audio_region()->fade_out();
5364 XMLNode &before = alist->get_state();
5367 tmp->audio_region()->set_fade_in_length (len);
5368 tmp->audio_region()->set_fade_in_active (true);
5370 tmp->audio_region()->set_fade_out_length (len);
5371 tmp->audio_region()->set_fade_out_active (true);
5374 XMLNode &after = alist->get_state();
5375 _session->add_command(new MementoCommand<AutomationList>(*alist, &before, &after));
5378 commit_reversible_command ();
5382 Editor::set_fade_in_shape (FadeShape shape)
5384 RegionSelection rs = get_regions_from_selection_and_entered ();
5390 begin_reversible_command (_("set fade in shape"));
5392 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5393 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5399 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_in();
5400 XMLNode &before = alist->get_state();
5402 tmp->audio_region()->set_fade_in_shape (shape);
5404 XMLNode &after = alist->get_state();
5405 _session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
5408 commit_reversible_command ();
5413 Editor::set_fade_out_shape (FadeShape shape)
5415 RegionSelection rs = get_regions_from_selection_and_entered ();
5421 begin_reversible_command (_("set fade out shape"));
5423 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5424 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5430 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_out();
5431 XMLNode &before = alist->get_state();
5433 tmp->audio_region()->set_fade_out_shape (shape);
5435 XMLNode &after = alist->get_state();
5436 _session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
5439 commit_reversible_command ();
5443 Editor::set_fade_in_active (bool yn)
5445 RegionSelection rs = get_regions_from_selection_and_entered ();
5451 begin_reversible_command (_("set fade in active"));
5453 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5454 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5461 boost::shared_ptr<AudioRegion> ar (tmp->audio_region());
5463 ar->clear_changes ();
5464 ar->set_fade_in_active (yn);
5465 _session->add_command (new StatefulDiffCommand (ar));
5468 commit_reversible_command ();
5472 Editor::set_fade_out_active (bool yn)
5474 RegionSelection rs = get_regions_from_selection_and_entered ();
5480 begin_reversible_command (_("set fade out active"));
5482 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5483 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5489 boost::shared_ptr<AudioRegion> ar (tmp->audio_region());
5491 ar->clear_changes ();
5492 ar->set_fade_out_active (yn);
5493 _session->add_command(new StatefulDiffCommand (ar));
5496 commit_reversible_command ();
5500 Editor::toggle_region_fades (int dir)
5502 if (_ignore_region_action) {
5506 boost::shared_ptr<AudioRegion> ar;
5509 RegionSelection rs = get_regions_from_selection_and_entered ();
5515 RegionSelection::iterator i;
5516 for (i = rs.begin(); i != rs.end(); ++i) {
5517 if ((ar = boost::dynamic_pointer_cast<AudioRegion>((*i)->region())) != 0) {
5519 yn = ar->fade_out_active ();
5521 yn = ar->fade_in_active ();
5527 if (i == rs.end()) {
5531 /* XXX should this undo-able? */
5533 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5534 if ((ar = boost::dynamic_pointer_cast<AudioRegion>((*i)->region())) == 0) {
5537 if (dir == 1 || dir == 0) {
5538 ar->set_fade_in_active (!yn);
5541 if (dir == -1 || dir == 0) {
5542 ar->set_fade_out_active (!yn);
5548 /** Update region fade visibility after its configuration has been changed */
5550 Editor::update_region_fade_visibility ()
5552 bool _fade_visibility = _session->config.get_show_region_fades ();
5554 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5555 AudioTimeAxisView* v = dynamic_cast<AudioTimeAxisView*>(*i);
5557 if (_fade_visibility) {
5558 v->audio_view()->show_all_fades ();
5560 v->audio_view()->hide_all_fades ();
5567 Editor::set_edit_point ()
5572 if (!mouse_frame (where, ignored)) {
5578 if (selection->markers.empty()) {
5580 mouse_add_new_marker (where);
5585 Location* loc = find_location_from_marker (selection->markers.front(), ignored);
5588 loc->move_to (where);
5594 Editor::set_playhead_cursor ()
5596 if (entered_marker) {
5597 _session->request_locate (entered_marker->position(), _session->transport_rolling());
5602 if (!mouse_frame (where, ignored)) {
5609 _session->request_locate (where, _session->transport_rolling());
5613 if ( Config->get_follow_edits() )
5614 cancel_time_selection();
5618 Editor::split_region ()
5620 if ( !selection->time.empty()) {
5621 separate_regions_between (selection->time);
5625 RegionSelection rs = get_regions_from_selection_and_edit_point ();
5627 framepos_t where = get_preferred_edit_position ();
5633 split_regions_at (where, rs);
5636 struct EditorOrderRouteSorter {
5637 bool operator() (boost::shared_ptr<Route> a, boost::shared_ptr<Route> b) {
5638 return a->order_key () < b->order_key ();
5643 Editor::select_next_route()
5645 if (selection->tracks.empty()) {
5646 selection->set (track_views.front());
5650 TimeAxisView* current = selection->tracks.front();
5654 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5655 if (*i == current) {
5657 if (i != track_views.end()) {
5660 current = (*(track_views.begin()));
5661 //selection->set (*(track_views.begin()));
5666 rui = dynamic_cast<RouteUI *>(current);
5667 } while ( current->hidden() || (rui != NULL && !rui->route()->active()));
5669 selection->set(current);
5671 ensure_time_axis_view_is_visible (*current, false);
5675 Editor::select_prev_route()
5677 if (selection->tracks.empty()) {
5678 selection->set (track_views.front());
5682 TimeAxisView* current = selection->tracks.front();
5686 for (TrackViewList::reverse_iterator i = track_views.rbegin(); i != track_views.rend(); ++i) {
5687 if (*i == current) {
5689 if (i != track_views.rend()) {
5692 current = *(track_views.rbegin());
5697 rui = dynamic_cast<RouteUI *>(current);
5698 } while ( current->hidden() || (rui != NULL && !rui->route()->active()));
5700 selection->set (current);
5702 ensure_time_axis_view_is_visible (*current, false);
5706 Editor::set_loop_from_selection (bool play)
5708 if (_session == 0 || selection->time.empty()) {
5712 framepos_t start = selection->time[clicked_selection].start;
5713 framepos_t end = selection->time[clicked_selection].end;
5715 set_loop_range (start, end, _("set loop range from selection"));
5718 _session->request_locate (start, true);
5719 _session->request_play_loop (true);
5724 Editor::set_loop_from_edit_range (bool play)
5726 if (_session == 0) {
5733 if (!get_edit_op_range (start, end)) {
5737 set_loop_range (start, end, _("set loop range from edit range"));
5740 _session->request_locate (start, true);
5741 _session->request_play_loop (true);
5746 Editor::set_loop_from_region (bool play)
5748 framepos_t start = max_framepos;
5751 RegionSelection rs = get_regions_from_selection_and_entered ();
5757 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5758 if ((*i)->region()->position() < start) {
5759 start = (*i)->region()->position();
5761 if ((*i)->region()->last_frame() + 1 > end) {
5762 end = (*i)->region()->last_frame() + 1;
5766 set_loop_range (start, end, _("set loop range from region"));
5769 _session->request_locate (start, true);
5770 _session->request_play_loop (true);
5775 Editor::set_punch_from_selection ()
5777 if (_session == 0 || selection->time.empty()) {
5781 framepos_t start = selection->time[clicked_selection].start;
5782 framepos_t end = selection->time[clicked_selection].end;
5784 set_punch_range (start, end, _("set punch range from selection"));
5788 Editor::set_punch_from_edit_range ()
5790 if (_session == 0) {
5797 if (!get_edit_op_range (start, end)) {
5801 set_punch_range (start, end, _("set punch range from edit range"));
5805 Editor::set_punch_from_region ()
5807 framepos_t start = max_framepos;
5810 RegionSelection rs = get_regions_from_selection_and_entered ();
5816 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5817 if ((*i)->region()->position() < start) {
5818 start = (*i)->region()->position();
5820 if ((*i)->region()->last_frame() + 1 > end) {
5821 end = (*i)->region()->last_frame() + 1;
5825 set_punch_range (start, end, _("set punch range from region"));
5829 Editor::pitch_shift_region ()
5831 RegionSelection rs = get_regions_from_selection_and_entered ();
5833 RegionSelection audio_rs;
5834 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5835 if (dynamic_cast<AudioRegionView*> (*i)) {
5836 audio_rs.push_back (*i);
5840 if (audio_rs.empty()) {
5844 pitch_shift (audio_rs, 1.2);
5848 Editor::transpose_region ()
5850 RegionSelection rs = get_regions_from_selection_and_entered ();
5852 list<MidiRegionView*> midi_region_views;
5853 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5854 MidiRegionView* mrv = dynamic_cast<MidiRegionView*> (*i);
5856 midi_region_views.push_back (mrv);
5861 int const r = d.run ();
5862 if (r != RESPONSE_ACCEPT) {
5866 for (list<MidiRegionView*>::iterator i = midi_region_views.begin(); i != midi_region_views.end(); ++i) {
5867 (*i)->midi_region()->transpose (d.semitones ());
5872 Editor::set_tempo_from_region ()
5874 RegionSelection rs = get_regions_from_selection_and_entered ();
5876 if (!_session || rs.empty()) {
5880 RegionView* rv = rs.front();
5882 define_one_bar (rv->region()->position(), rv->region()->last_frame() + 1);
5886 Editor::use_range_as_bar ()
5888 framepos_t start, end;
5889 if (get_edit_op_range (start, end)) {
5890 define_one_bar (start, end);
5895 Editor::define_one_bar (framepos_t start, framepos_t end)
5897 framepos_t length = end - start;
5899 const Meter& m (_session->tempo_map().meter_at (start));
5901 /* length = 1 bar */
5903 /* now we want frames per beat.
5904 we have frames per bar, and beats per bar, so ...
5907 /* XXXX METER MATH */
5909 double frames_per_beat = length / m.divisions_per_bar();
5911 /* beats per minute = */
5913 double beats_per_minute = (_session->frame_rate() * 60.0) / frames_per_beat;
5915 /* now decide whether to:
5917 (a) set global tempo
5918 (b) add a new tempo marker
5922 const TempoSection& t (_session->tempo_map().tempo_section_at (start));
5924 bool do_global = false;
5926 if ((_session->tempo_map().n_tempos() == 1) && (_session->tempo_map().n_meters() == 1)) {
5928 /* only 1 tempo & 1 meter: ask if the user wants to set the tempo
5929 at the start, or create a new marker
5932 vector<string> options;
5933 options.push_back (_("Cancel"));
5934 options.push_back (_("Add new marker"));
5935 options.push_back (_("Set global tempo"));
5938 _("Define one bar"),
5939 _("Do you want to set the global tempo or add a new tempo marker?"),
5943 c.set_default_response (2);
5959 /* more than 1 tempo and/or meter section already, go ahead do the "usual":
5960 if the marker is at the region starter, change it, otherwise add
5965 begin_reversible_command (_("set tempo from region"));
5966 XMLNode& before (_session->tempo_map().get_state());
5969 _session->tempo_map().change_initial_tempo (beats_per_minute, t.note_type());
5970 } else if (t.frame() == start) {
5971 _session->tempo_map().change_existing_tempo_at (start, beats_per_minute, t.note_type());
5973 Timecode::BBT_Time bbt;
5974 _session->tempo_map().bbt_time (start, bbt);
5975 _session->tempo_map().add_tempo (Tempo (beats_per_minute, t.note_type()), bbt);
5978 XMLNode& after (_session->tempo_map().get_state());
5980 _session->add_command (new MementoCommand<TempoMap>(_session->tempo_map(), &before, &after));
5981 commit_reversible_command ();
5985 Editor::split_region_at_transients ()
5987 AnalysisFeatureList positions;
5989 RegionSelection rs = get_regions_from_selection_and_entered ();
5991 if (!_session || rs.empty()) {
5995 _session->begin_reversible_command (_("split regions"));
5997 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ) {
5999 RegionSelection::iterator tmp;
6004 boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion> ((*i)->region());
6006 if (ar && (ar->get_transients (positions) == 0)) {
6007 split_region_at_points ((*i)->region(), positions, true);
6014 _session->commit_reversible_command ();
6019 Editor::split_region_at_points (boost::shared_ptr<Region> r, AnalysisFeatureList& positions, bool can_ferret, bool select_new)
6021 bool use_rhythmic_rodent = false;
6023 boost::shared_ptr<Playlist> pl = r->playlist();
6025 list<boost::shared_ptr<Region> > new_regions;
6031 if (positions.empty()) {
6036 if (positions.size() > 20 && can_ferret) {
6037 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);
6038 MessageDialog msg (msgstr,
6041 Gtk::BUTTONS_OK_CANCEL);
6044 msg.add_button (_("Call for the Ferret!"), RESPONSE_APPLY);
6045 msg.set_secondary_text (_("Press OK to continue with this split operation\nor ask the Ferret dialog to tune the analysis"));
6047 msg.set_secondary_text (_("Press OK to continue with this split operation"));
6050 msg.set_title (_("Excessive split?"));
6053 int response = msg.run();
6059 case RESPONSE_APPLY:
6060 use_rhythmic_rodent = true;
6067 if (use_rhythmic_rodent) {
6068 show_rhythm_ferret ();
6072 AnalysisFeatureList::const_iterator x;
6074 pl->clear_changes ();
6075 pl->clear_owned_changes ();
6077 x = positions.begin();
6079 if (x == positions.end()) {
6084 pl->remove_region (r);
6088 while (x != positions.end()) {
6090 /* deal with positons that are out of scope of present region bounds */
6091 if (*x <= 0 || *x > r->length()) {
6096 /* file start = original start + how far we from the initial position ?
6099 framepos_t file_start = r->start() + pos;
6101 /* length = next position - current position
6104 framepos_t len = (*x) - pos;
6106 /* XXX we do we really want to allow even single-sample regions?
6107 shouldn't we have some kind of lower limit on region size?
6116 if (RegionFactory::region_name (new_name, r->name())) {
6120 /* do NOT announce new regions 1 by one, just wait till they are all done */
6124 plist.add (ARDOUR::Properties::start, file_start);
6125 plist.add (ARDOUR::Properties::length, len);
6126 plist.add (ARDOUR::Properties::name, new_name);
6127 plist.add (ARDOUR::Properties::layer, 0);
6129 boost::shared_ptr<Region> nr = RegionFactory::create (r->sources(), plist, false);
6130 /* because we set annouce to false, manually add the new region to the
6133 RegionFactory::map_add (nr);
6135 pl->add_region (nr, r->position() + pos);
6138 new_regions.push_front(nr);
6147 RegionFactory::region_name (new_name, r->name());
6149 /* Add the final region */
6152 plist.add (ARDOUR::Properties::start, r->start() + pos);
6153 plist.add (ARDOUR::Properties::length, r->last_frame() - (r->position() + pos) + 1);
6154 plist.add (ARDOUR::Properties::name, new_name);
6155 plist.add (ARDOUR::Properties::layer, 0);
6157 boost::shared_ptr<Region> nr = RegionFactory::create (r->sources(), plist, false);
6158 /* because we set annouce to false, manually add the new region to the
6161 RegionFactory::map_add (nr);
6162 pl->add_region (nr, r->position() + pos);
6165 new_regions.push_front(nr);
6170 /* We might have removed regions, which alters other regions' layering_index,
6171 so we need to do a recursive diff here.
6173 vector<Command*> cmds;
6175 _session->add_commands (cmds);
6177 _session->add_command (new StatefulDiffCommand (pl));
6181 for (list<boost::shared_ptr<Region> >::iterator i = new_regions.begin(); i != new_regions.end(); ++i){
6182 set_selected_regionview_from_region_list ((*i), Selection::Add);
6188 Editor::place_transient()
6194 RegionSelection rs = get_regions_from_selection_and_edit_point ();
6200 framepos_t where = get_preferred_edit_position();
6202 _session->begin_reversible_command (_("place transient"));
6204 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6205 framepos_t position = (*r)->region()->position();
6206 (*r)->region()->add_transient(where - position);
6209 _session->commit_reversible_command ();
6213 Editor::remove_transient(ArdourCanvas::Item* item)
6219 ArdourCanvas::Line* _line = reinterpret_cast<ArdourCanvas::Line*> (item);
6222 AudioRegionView* _arv = reinterpret_cast<AudioRegionView*> (item->get_data ("regionview"));
6223 _arv->remove_transient (*(float*) _line->get_data ("position"));
6227 Editor::snap_regions_to_grid ()
6229 list <boost::shared_ptr<Playlist > > used_playlists;
6231 RegionSelection rs = get_regions_from_selection_and_entered ();
6233 if (!_session || rs.empty()) {
6237 _session->begin_reversible_command (_("snap regions to grid"));
6239 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6241 boost::shared_ptr<Playlist> pl = (*r)->region()->playlist();
6243 if (!pl->frozen()) {
6244 /* we haven't seen this playlist before */
6246 /* remember used playlists so we can thaw them later */
6247 used_playlists.push_back(pl);
6251 framepos_t start_frame = (*r)->region()->first_frame ();
6252 snap_to (start_frame);
6253 (*r)->region()->set_position (start_frame);
6256 while (used_playlists.size() > 0) {
6257 list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
6259 used_playlists.pop_front();
6262 _session->commit_reversible_command ();
6266 Editor::close_region_gaps ()
6268 list <boost::shared_ptr<Playlist > > used_playlists;
6270 RegionSelection rs = get_regions_from_selection_and_entered ();
6272 if (!_session || rs.empty()) {
6276 Dialog dialog (_("Close Region Gaps"));
6279 table.set_spacings (12);
6280 table.set_border_width (12);
6281 Label* l = manage (left_aligned_label (_("Crossfade length")));
6282 table.attach (*l, 0, 1, 0, 1);
6284 SpinButton spin_crossfade (1, 0);
6285 spin_crossfade.set_range (0, 15);
6286 spin_crossfade.set_increments (1, 1);
6287 spin_crossfade.set_value (5);
6288 table.attach (spin_crossfade, 1, 2, 0, 1);
6290 table.attach (*manage (new Label (_("ms"))), 2, 3, 0, 1);
6292 l = manage (left_aligned_label (_("Pull-back length")));
6293 table.attach (*l, 0, 1, 1, 2);
6295 SpinButton spin_pullback (1, 0);
6296 spin_pullback.set_range (0, 100);
6297 spin_pullback.set_increments (1, 1);
6298 spin_pullback.set_value(30);
6299 table.attach (spin_pullback, 1, 2, 1, 2);
6301 table.attach (*manage (new Label (_("ms"))), 2, 3, 1, 2);
6303 dialog.get_vbox()->pack_start (table);
6304 dialog.add_button (Stock::CANCEL, RESPONSE_CANCEL);
6305 dialog.add_button (_("Ok"), RESPONSE_ACCEPT);
6308 if (dialog.run () == RESPONSE_CANCEL) {
6312 framepos_t crossfade_len = spin_crossfade.get_value();
6313 framepos_t pull_back_frames = spin_pullback.get_value();
6315 crossfade_len = lrintf (crossfade_len * _session->frame_rate()/1000);
6316 pull_back_frames = lrintf (pull_back_frames * _session->frame_rate()/1000);
6318 /* Iterate over the region list and make adjacent regions overlap by crossfade_len_ms */
6320 _session->begin_reversible_command (_("close region gaps"));
6323 boost::shared_ptr<Region> last_region;
6325 rs.sort_by_position_and_track();
6327 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6329 boost::shared_ptr<Playlist> pl = (*r)->region()->playlist();
6331 if (!pl->frozen()) {
6332 /* we haven't seen this playlist before */
6334 /* remember used playlists so we can thaw them later */
6335 used_playlists.push_back(pl);
6339 framepos_t position = (*r)->region()->position();
6341 if (idx == 0 || position < last_region->position()){
6342 last_region = (*r)->region();
6347 (*r)->region()->trim_front( (position - pull_back_frames));
6348 last_region->trim_end( (position - pull_back_frames + crossfade_len));
6350 last_region = (*r)->region();
6355 while (used_playlists.size() > 0) {
6356 list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
6358 used_playlists.pop_front();
6361 _session->commit_reversible_command ();
6365 Editor::tab_to_transient (bool forward)
6367 AnalysisFeatureList positions;
6369 RegionSelection rs = get_regions_from_selection_and_entered ();
6375 framepos_t pos = _session->audible_frame ();
6377 if (!selection->tracks.empty()) {
6379 /* don't waste time searching for transients in duplicate playlists.
6382 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
6384 for (TrackViewList::iterator t = ts.begin(); t != ts.end(); ++t) {
6386 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*t);
6389 boost::shared_ptr<Track> tr = rtv->track();
6391 boost::shared_ptr<Playlist> pl = tr->playlist ();
6393 framepos_t result = pl->find_next_transient (pos, forward ? 1 : -1);
6396 positions.push_back (result);
6409 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6410 (*r)->region()->get_transients (positions);
6414 TransientDetector::cleanup_transients (positions, _session->frame_rate(), 3.0);
6417 AnalysisFeatureList::iterator x;
6419 for (x = positions.begin(); x != positions.end(); ++x) {
6425 if (x != positions.end ()) {
6426 _session->request_locate (*x);
6430 AnalysisFeatureList::reverse_iterator x;
6432 for (x = positions.rbegin(); x != positions.rend(); ++x) {
6438 if (x != positions.rend ()) {
6439 _session->request_locate (*x);
6445 Editor::playhead_forward_to_grid ()
6451 framepos_t pos = playhead_cursor->current_frame ();
6452 if (pos < max_framepos - 1) {
6454 snap_to_internal (pos, 1, false);
6455 _session->request_locate (pos);
6461 Editor::playhead_backward_to_grid ()
6467 framepos_t pos = playhead_cursor->current_frame ();
6470 snap_to_internal (pos, -1, false);
6471 _session->request_locate (pos);
6476 Editor::set_track_height (Height h)
6478 TrackSelection& ts (selection->tracks);
6480 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
6481 (*x)->set_height_enum (h);
6486 Editor::toggle_tracks_active ()
6488 TrackSelection& ts (selection->tracks);
6490 bool target = false;
6496 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
6497 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*x);
6501 target = !rtv->_route->active();
6504 rtv->_route->set_active (target, this);
6510 Editor::remove_tracks ()
6512 TrackSelection& ts (selection->tracks);
6518 vector<string> choices;
6522 const char* trackstr;
6524 vector<boost::shared_ptr<Route> > routes;
6525 bool special_bus = false;
6527 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
6528 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*x);
6532 if (rtv->is_track()) {
6537 routes.push_back (rtv->_route);
6539 if (rtv->route()->is_master() || rtv->route()->is_monitor()) {
6544 if (special_bus && !Config->get_allow_special_bus_removal()) {
6545 MessageDialog msg (_("That would be bad news ...."),
6549 msg.set_secondary_text (string_compose (_(
6550 "Removing the master or monitor bus is such a bad idea\n\
6551 that %1 is not going to allow it.\n\
6553 If you really want to do this sort of thing\n\
6554 edit your ardour.rc file to set the\n\
6555 \"allow-special-bus-removal\" option to be \"yes\""), PROGRAM_NAME));
6562 if (ntracks + nbusses == 0) {
6566 // XXX should be using gettext plural forms, maybe?
6568 trackstr = _("tracks");
6570 trackstr = _("track");
6574 busstr = _("busses");
6581 prompt = string_compose (_("Do you really want to remove %1 %2 and %3 %4?\n"
6582 "(You may also lose the playlists associated with the %2)\n\n"
6583 "This action cannot be undone, and the session file will be overwritten!"),
6584 ntracks, trackstr, nbusses, busstr);
6586 prompt = string_compose (_("Do you really want to remove %1 %2?\n"
6587 "(You may also lose the playlists associated with the %2)\n\n"
6588 "This action cannot be undone, and the session file will be overwritten!"),
6591 } else if (nbusses) {
6592 prompt = string_compose (_("Do you really want to remove %1 %2?\n\n"
6593 "This action cannot be undone, and the session file will be overwritten"),
6597 choices.push_back (_("No, do nothing."));
6598 if (ntracks + nbusses > 1) {
6599 choices.push_back (_("Yes, remove them."));
6601 choices.push_back (_("Yes, remove it."));
6606 title = string_compose (_("Remove %1"), trackstr);
6608 title = string_compose (_("Remove %1"), busstr);
6611 Choice prompter (title, prompt, choices);
6613 if (prompter.run () != 1) {
6618 Session::StateProtector sp (_session);
6619 DisplaySuspender ds;
6620 for (vector<boost::shared_ptr<Route> >::iterator x = routes.begin(); x != routes.end(); ++x) {
6621 _session->remove_route (*x);
6627 Editor::do_insert_time ()
6629 if (selection->tracks.empty()) {
6633 InsertTimeDialog d (*this);
6634 int response = d.run ();
6636 if (response != RESPONSE_OK) {
6640 if (d.distance() == 0) {
6644 InsertTimeOption opt = d.intersected_region_action ();
6647 get_preferred_edit_position(),
6653 d.move_glued_markers(),
6654 d.move_locked_markers(),
6660 Editor::insert_time (
6661 framepos_t pos, framecnt_t frames, InsertTimeOption opt,
6662 bool all_playlists, bool ignore_music_glue, bool markers_too, bool glued_markers_too, bool locked_markers_too, bool tempo_too
6665 bool commit = false;
6667 if (Config->get_edit_mode() == Lock) {
6671 begin_reversible_command (_("insert time"));
6673 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
6675 for (TrackViewList::iterator x = ts.begin(); x != ts.end(); ++x) {
6679 /* don't operate on any playlist more than once, which could
6680 * happen if "all playlists" is enabled, but there is more
6681 * than 1 track using playlists "from" a given track.
6684 set<boost::shared_ptr<Playlist> > pl;
6686 if (all_playlists) {
6687 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*x);
6689 vector<boost::shared_ptr<Playlist> > all = _session->playlists->playlists_for_track (rtav->track ());
6690 for (vector<boost::shared_ptr<Playlist> >::iterator p = all.begin(); p != all.end(); ++p) {
6695 if ((*x)->playlist ()) {
6696 pl.insert ((*x)->playlist ());
6700 for (set<boost::shared_ptr<Playlist> >::iterator i = pl.begin(); i != pl.end(); ++i) {
6702 (*i)->clear_changes ();
6703 (*i)->clear_owned_changes ();
6705 if (opt == SplitIntersected) {
6709 (*i)->shift (pos, frames, (opt == MoveIntersected), ignore_music_glue);
6711 vector<Command*> cmds;
6713 _session->add_commands (cmds);
6715 _session->add_command (new StatefulDiffCommand (*i));
6720 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*x);
6722 rtav->route ()->shift (pos, frames);
6730 XMLNode& before (_session->locations()->get_state());
6731 Locations::LocationList copy (_session->locations()->list());
6733 for (Locations::LocationList::iterator i = copy.begin(); i != copy.end(); ++i) {
6735 Locations::LocationList::const_iterator tmp;
6737 bool const was_locked = (*i)->locked ();
6738 if (locked_markers_too) {
6742 if ((*i)->position_lock_style() == AudioTime || glued_markers_too) {
6744 if ((*i)->start() >= pos) {
6745 (*i)->set_start ((*i)->start() + frames);
6746 if (!(*i)->is_mark()) {
6747 (*i)->set_end ((*i)->end() + frames);
6760 XMLNode& after (_session->locations()->get_state());
6761 _session->add_command (new MementoCommand<Locations>(*_session->locations(), &before, &after));
6766 _session->tempo_map().insert_time (pos, frames);
6770 commit_reversible_command ();
6775 Editor::fit_selected_tracks ()
6777 if (!selection->tracks.empty()) {
6778 fit_tracks (selection->tracks);
6782 /* no selected tracks - use tracks with selected regions */
6784 if (!selection->regions.empty()) {
6785 for (RegionSelection::iterator r = selection->regions.begin(); r != selection->regions.end(); ++r) {
6786 tvl.push_back (&(*r)->get_time_axis_view ());
6792 } else if (internal_editing()) {
6793 /* no selected tracks, or regions, but in internal edit mode, so follow the mouse and use
6796 if (entered_track) {
6797 tvl.push_back (entered_track);
6806 Editor::fit_tracks (TrackViewList & tracks)
6808 if (tracks.empty()) {
6812 uint32_t child_heights = 0;
6813 int visible_tracks = 0;
6815 for (TrackSelection::iterator t = tracks.begin(); t != tracks.end(); ++t) {
6817 if (!(*t)->marked_for_display()) {
6821 child_heights += (*t)->effective_height() - (*t)->current_height();
6825 /* compute the per-track height from:
6827 total canvas visible height -
6828 height that will be taken by visible children of selected
6829 tracks - height of the ruler/hscroll area
6831 uint32_t h = (uint32_t) floor ((trackviews_height() - child_heights) / visible_tracks);
6832 double first_y_pos = DBL_MAX;
6834 if (h < TimeAxisView::preset_height (HeightSmall)) {
6835 MessageDialog msg (*this, _("There are too many tracks to fit in the current window"));
6836 /* too small to be displayed */
6840 undo_visual_stack.push_back (current_visual_state (true));
6841 no_save_visual = true;
6843 /* build a list of all tracks, including children */
6846 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
6848 TimeAxisView::Children c = (*i)->get_child_list ();
6849 for (TimeAxisView::Children::iterator j = c.begin(); j != c.end(); ++j) {
6850 all.push_back (j->get());
6854 bool prev_was_selected = false;
6855 bool is_selected = tracks.contains (all.front());
6856 bool next_is_selected;
6858 for (TrackViewList::iterator t = all.begin(); t != all.end(); ++t) {
6860 TrackViewList::iterator next;
6865 if (next != all.end()) {
6866 next_is_selected = tracks.contains (*next);
6868 next_is_selected = false;
6871 if ((*t)->marked_for_display ()) {
6873 (*t)->set_height (h);
6874 first_y_pos = std::min ((*t)->y_position (), first_y_pos);
6876 if (prev_was_selected && next_is_selected) {
6877 hide_track_in_display (*t);
6882 prev_was_selected = is_selected;
6883 is_selected = next_is_selected;
6887 set the controls_layout height now, because waiting for its size
6888 request signal handler will cause the vertical adjustment setting to fail
6891 controls_layout.property_height () = _full_canvas_height;
6892 vertical_adjustment.set_value (first_y_pos);
6894 redo_visual_stack.push_back (current_visual_state (true));
6896 visible_tracks_selector.set_text (_("Sel"));
6900 Editor::save_visual_state (uint32_t n)
6902 while (visual_states.size() <= n) {
6903 visual_states.push_back (0);
6906 if (visual_states[n] != 0) {
6907 delete visual_states[n];
6910 visual_states[n] = current_visual_state (true);
6915 Editor::goto_visual_state (uint32_t n)
6917 if (visual_states.size() <= n) {
6921 if (visual_states[n] == 0) {
6925 use_visual_state (*visual_states[n]);
6929 Editor::start_visual_state_op (uint32_t n)
6931 save_visual_state (n);
6933 PopUp* pup = new PopUp (WIN_POS_MOUSE, 1000, true);
6935 snprintf (buf, sizeof (buf), _("Saved view %u"), n+1);
6936 pup->set_text (buf);
6941 Editor::cancel_visual_state_op (uint32_t n)
6943 goto_visual_state (n);
6947 Editor::toggle_region_mute ()
6949 if (_ignore_region_action) {
6953 RegionSelection rs = get_regions_from_selection_and_entered ();
6959 if (rs.size() > 1) {
6960 begin_reversible_command (_("mute regions"));
6962 begin_reversible_command (_("mute region"));
6965 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
6967 (*i)->region()->playlist()->clear_changes ();
6968 (*i)->region()->set_muted (!(*i)->region()->muted ());
6969 _session->add_command (new StatefulDiffCommand ((*i)->region()->playlist()));
6973 commit_reversible_command ();
6977 Editor::combine_regions ()
6979 /* foreach track with selected regions, take all selected regions
6980 and join them into a new region containing the subregions (as a
6984 typedef set<RouteTimeAxisView*> RTVS;
6987 if (selection->regions.empty()) {
6991 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
6992 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(&(*i)->get_time_axis_view());
6995 tracks.insert (rtv);
6999 begin_reversible_command (_("combine regions"));
7001 vector<RegionView*> new_selection;
7003 for (RTVS::iterator i = tracks.begin(); i != tracks.end(); ++i) {
7006 if ((rv = (*i)->combine_regions ()) != 0) {
7007 new_selection.push_back (rv);
7011 selection->clear_regions ();
7012 for (vector<RegionView*>::iterator i = new_selection.begin(); i != new_selection.end(); ++i) {
7013 selection->add (*i);
7016 commit_reversible_command ();
7020 Editor::uncombine_regions ()
7022 typedef set<RouteTimeAxisView*> RTVS;
7025 if (selection->regions.empty()) {
7029 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
7030 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(&(*i)->get_time_axis_view());
7033 tracks.insert (rtv);
7037 begin_reversible_command (_("uncombine regions"));
7039 for (RTVS::iterator i = tracks.begin(); i != tracks.end(); ++i) {
7040 (*i)->uncombine_regions ();
7043 commit_reversible_command ();
7047 Editor::toggle_midi_input_active (bool flip_others)
7050 boost::shared_ptr<RouteList> rl (new RouteList);
7052 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
7053 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
7059 boost::shared_ptr<MidiTrack> mt = rtav->midi_track();
7062 rl->push_back (rtav->route());
7063 onoff = !mt->input_active();
7067 _session->set_exclusive_input_active (rl, onoff, flip_others);
7074 lock_dialog = new Gtk::Dialog (string_compose (_("%1: Locked"), PROGRAM_NAME), true);
7076 Gtk::Image* padlock = manage (new Gtk::Image (ARDOUR_UI_UTILS::get_icon ("padlock_closed")));
7077 lock_dialog->get_vbox()->pack_start (*padlock);
7079 ArdourButton* b = manage (new ArdourButton);
7080 b->set_name ("lock button");
7081 b->set_text (_("Click to unlock"));
7082 b->signal_clicked.connect (sigc::mem_fun (*this, &Editor::unlock));
7083 lock_dialog->get_vbox()->pack_start (*b);
7085 lock_dialog->get_vbox()->show_all ();
7086 lock_dialog->set_size_request (200, 200);
7090 /* The global menu bar continues to be accessible to applications
7091 with modal dialogs, which means that we need to desensitize
7092 all items in the menu bar. Since those items are really just
7093 proxies for actions, that means disabling all actions.
7095 ActionManager::disable_all_actions ();
7097 lock_dialog->present ();
7103 lock_dialog->hide ();
7106 ActionManager::pop_action_state ();
7109 if (ARDOUR_UI::config()->get_lock_gui_after_seconds()) {
7110 start_lock_event_timing ();
7115 Editor::bring_in_callback (Gtk::Label* label, uint32_t n, uint32_t total, string name)
7117 Gtkmm2ext::UI::instance()->call_slot (invalidator (*this), boost::bind (&Editor::update_bring_in_message, this, label, n, total, name));
7121 Editor::update_bring_in_message (Gtk::Label* label, uint32_t n, uint32_t total, string name)
7123 label->set_text (string_compose ("Copying %1, %2 of %3", name, n, total));
7124 Gtkmm2ext::UI::instance()->flush_pending ();
7128 Editor::bring_all_sources_into_session ()
7135 ArdourDialog w (_("Moving embedded files into session folder"));
7136 w.get_vbox()->pack_start (msg);
7139 /* flush all pending GUI events because we're about to start copying
7143 Gtkmm2ext::UI::instance()->flush_pending ();
7147 _session->bring_all_sources_into_session (boost::bind (&Editor::bring_in_callback, this, &msg, _1, _2, _3));