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;
649 abort(); /*NOTREACHED*/
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 /* reset repeated paste state */
3906 commit_reversible_command ();
3909 if (op == Delete || op == Cut || op == Clear) {
3914 struct AutomationRecord {
3915 AutomationRecord () : state (0) {}
3916 AutomationRecord (XMLNode* s) : state (s) {}
3918 XMLNode* state; ///< state before any operation
3919 boost::shared_ptr<Evoral::ControlList> copy; ///< copied events for the cut buffer
3922 /** Cut, copy or clear selected automation points.
3923 * @param op Operation (Cut, Copy or Clear)
3926 Editor::cut_copy_points (CutCopyOp op)
3928 if (selection->points.empty ()) {
3932 /* XXX: not ideal, as there may be more than one track involved in the point selection */
3933 _last_cut_copy_source_track = &selection->points.front()->line().trackview;
3935 /* Keep a record of the AutomationLists that we end up using in this operation */
3936 typedef std::map<boost::shared_ptr<AutomationList>, AutomationRecord> Lists;
3939 /* Go through all selected points, making an AutomationRecord for each distinct AutomationList */
3940 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
3941 boost::shared_ptr<AutomationList> al = (*i)->line().the_list();
3942 if (lists.find (al) == lists.end ()) {
3943 /* We haven't seen this list yet, so make a record for it. This includes
3944 taking a copy of its current state, in case this is needed for undo later.
3946 lists[al] = AutomationRecord (&al->get_state ());
3950 if (op == Cut || op == Copy) {
3951 /* This operation will involve putting things in the cut buffer, so create an empty
3952 ControlList for each of our source lists to put the cut buffer data in.
3954 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
3955 i->second.copy = i->first->create (i->first->parameter ());
3958 /* Add all selected points to the relevant copy ControlLists */
3959 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
3960 boost::shared_ptr<AutomationList> al = (*i)->line().the_list();
3961 AutomationList::const_iterator j = (*i)->model ();
3962 lists[al].copy->add ((*j)->when, (*j)->value);
3965 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
3966 /* Correct this copy list so that it starts at time 0 */
3967 double const start = i->second.copy->front()->when;
3968 for (AutomationList::iterator j = i->second.copy->begin(); j != i->second.copy->end(); ++j) {
3969 (*j)->when -= start;
3972 /* And add it to the cut buffer */
3973 cut_buffer->add (i->second.copy);
3977 if (op == Delete || op == Cut) {
3978 /* This operation needs to remove things from the main AutomationList, so do that now */
3980 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
3981 i->first->freeze ();
3984 /* Remove each selected point from its AutomationList */
3985 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
3986 boost::shared_ptr<AutomationList> al = (*i)->line().the_list();
3987 al->erase ((*i)->model ());
3990 /* Thaw the lists and add undo records for them */
3991 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
3992 boost::shared_ptr<AutomationList> al = i->first;
3994 _session->add_command (new MementoCommand<AutomationList> (*al.get(), i->second.state, &(al->get_state ())));
3999 /** Cut, copy or clear selected automation points.
4000 * @param op Operation (Cut, Copy or Clear)
4003 Editor::cut_copy_midi (CutCopyOp op)
4005 for (MidiRegionSelection::iterator i = selection->midi_regions.begin(); i != selection->midi_regions.end(); ++i) {
4006 MidiRegionView* mrv = dynamic_cast<MidiRegionView*>(*i);
4008 mrv->cut_copy_clear (op);
4010 /* XXX: not ideal, as there may be more than one track involved in the selection */
4011 _last_cut_copy_source_track = &mrv->get_time_axis_view();
4016 struct lt_playlist {
4017 bool operator () (const PlaylistState& a, const PlaylistState& b) {
4018 return a.playlist < b.playlist;
4022 struct PlaylistMapping {
4024 boost::shared_ptr<Playlist> pl;
4026 PlaylistMapping (TimeAxisView* tvp) : tv (tvp) {}
4029 /** Remove `clicked_regionview' */
4031 Editor::remove_clicked_region ()
4033 if (clicked_routeview == 0 || clicked_regionview == 0) {
4037 boost::shared_ptr<Playlist> playlist = clicked_routeview->playlist();
4039 playlist->clear_changes ();
4040 playlist->clear_owned_changes ();
4041 playlist->remove_region (clicked_regionview->region());
4042 if (Config->get_edit_mode() == Ripple)
4043 playlist->ripple (clicked_regionview->region()->position(), -clicked_regionview->region()->length(), boost::shared_ptr<Region>());
4045 /* We might have removed regions, which alters other regions' layering_index,
4046 so we need to do a recursive diff here.
4048 vector<Command*> cmds;
4049 playlist->rdiff (cmds);
4050 _session->add_commands (cmds);
4052 _session->add_command(new StatefulDiffCommand (playlist));
4053 commit_reversible_command ();
4057 /** Remove the selected regions */
4059 Editor::remove_selected_regions ()
4061 RegionSelection rs = get_regions_from_selection_and_entered ();
4063 if (!_session || rs.empty()) {
4067 begin_reversible_command (_("remove region"));
4069 list<boost::shared_ptr<Region> > regions_to_remove;
4071 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
4072 // we can't just remove the region(s) in this loop because
4073 // this removes them from the RegionSelection, and they thus
4074 // disappear from underneath the iterator, and the ++i above
4075 // SEGVs in a puzzling fashion.
4077 // so, first iterate over the regions to be removed from rs and
4078 // add them to the regions_to_remove list, and then
4079 // iterate over the list to actually remove them.
4081 regions_to_remove.push_back ((*i)->region());
4084 vector<boost::shared_ptr<Playlist> > playlists;
4086 for (list<boost::shared_ptr<Region> >::iterator rl = regions_to_remove.begin(); rl != regions_to_remove.end(); ++rl) {
4088 boost::shared_ptr<Playlist> playlist = (*rl)->playlist();
4091 // is this check necessary?
4095 /* get_regions_from_selection_and_entered() guarantees that
4096 the playlists involved are unique, so there is no need
4100 playlists.push_back (playlist);
4102 playlist->clear_changes ();
4103 playlist->clear_owned_changes ();
4104 playlist->freeze ();
4105 playlist->remove_region (*rl);
4106 if (Config->get_edit_mode() == Ripple)
4107 playlist->ripple ((*rl)->position(), -(*rl)->length(), boost::shared_ptr<Region>());
4111 vector<boost::shared_ptr<Playlist> >::iterator pl;
4113 for (pl = playlists.begin(); pl != playlists.end(); ++pl) {
4116 /* We might have removed regions, which alters other regions' layering_index,
4117 so we need to do a recursive diff here.
4119 vector<Command*> cmds;
4120 (*pl)->rdiff (cmds);
4121 _session->add_commands (cmds);
4123 _session->add_command(new StatefulDiffCommand (*pl));
4126 commit_reversible_command ();
4129 /** Cut, copy or clear selected regions.
4130 * @param op Operation (Cut, Copy or Clear)
4133 Editor::cut_copy_regions (CutCopyOp op, RegionSelection& rs)
4135 /* we can't use a std::map here because the ordering is important, and we can't trivially sort
4136 a map when we want ordered access to both elements. i think.
4139 vector<PlaylistMapping> pmap;
4141 framepos_t first_position = max_framepos;
4143 typedef set<boost::shared_ptr<Playlist> > FreezeList;
4144 FreezeList freezelist;
4146 /* get ordering correct before we cut/copy */
4148 rs.sort_by_position_and_track ();
4150 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
4152 first_position = min ((framepos_t) (*x)->region()->position(), first_position);
4154 if (op == Cut || op == Clear || op == Delete) {
4155 boost::shared_ptr<Playlist> pl = (*x)->region()->playlist();
4158 FreezeList::iterator fl;
4160 // only take state if this is a new playlist.
4161 for (fl = freezelist.begin(); fl != freezelist.end(); ++fl) {
4167 if (fl == freezelist.end()) {
4168 pl->clear_changes();
4169 pl->clear_owned_changes ();
4171 freezelist.insert (pl);
4176 TimeAxisView* tv = &(*x)->get_time_axis_view();
4177 vector<PlaylistMapping>::iterator z;
4179 for (z = pmap.begin(); z != pmap.end(); ++z) {
4180 if ((*z).tv == tv) {
4185 if (z == pmap.end()) {
4186 pmap.push_back (PlaylistMapping (tv));
4190 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ) {
4192 boost::shared_ptr<Playlist> pl = (*x)->region()->playlist();
4195 /* region not yet associated with a playlist (e.g. unfinished
4202 TimeAxisView& tv = (*x)->get_time_axis_view();
4203 boost::shared_ptr<Playlist> npl;
4204 RegionSelection::iterator tmp;
4211 vector<PlaylistMapping>::iterator z;
4213 for (z = pmap.begin(); z != pmap.end(); ++z) {
4214 if ((*z).tv == &tv) {
4219 assert (z != pmap.end());
4222 npl = PlaylistFactory::create (pl->data_type(), *_session, "cutlist", true);
4230 boost::shared_ptr<Region> r = (*x)->region();
4231 boost::shared_ptr<Region> _xx;
4237 pl->remove_region (r);
4238 if (Config->get_edit_mode() == Ripple)
4239 pl->ripple (r->position(), -r->length(), boost::shared_ptr<Region>());
4243 _xx = RegionFactory::create (r);
4244 npl->add_region (_xx, r->position() - first_position);
4245 pl->remove_region (r);
4246 if (Config->get_edit_mode() == Ripple)
4247 pl->ripple (r->position(), -r->length(), boost::shared_ptr<Region>());
4251 /* copy region before adding, so we're not putting same object into two different playlists */
4252 npl->add_region (RegionFactory::create (r), r->position() - first_position);
4256 pl->remove_region (r);
4257 if (Config->get_edit_mode() == Ripple)
4258 pl->ripple (r->position(), -r->length(), boost::shared_ptr<Region>());
4267 list<boost::shared_ptr<Playlist> > foo;
4269 /* the pmap is in the same order as the tracks in which selected regions occured */
4271 for (vector<PlaylistMapping>::iterator i = pmap.begin(); i != pmap.end(); ++i) {
4274 foo.push_back ((*i).pl);
4279 cut_buffer->set (foo);
4283 _last_cut_copy_source_track = 0;
4285 _last_cut_copy_source_track = pmap.front().tv;
4289 for (FreezeList::iterator pl = freezelist.begin(); pl != freezelist.end(); ++pl) {
4292 /* We might have removed regions, which alters other regions' layering_index,
4293 so we need to do a recursive diff here.
4295 vector<Command*> cmds;
4296 (*pl)->rdiff (cmds);
4297 _session->add_commands (cmds);
4299 _session->add_command (new StatefulDiffCommand (*pl));
4304 Editor::cut_copy_ranges (CutCopyOp op)
4306 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4308 /* Sort the track selection now, so that it if is used, the playlists
4309 selected by the calls below to cut_copy_clear are in the order that
4310 their tracks appear in the editor. This makes things like paste
4311 of ranges work properly.
4314 sort_track_selection (ts);
4317 if (!entered_track) {
4320 ts.push_back (entered_track);
4323 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4324 (*i)->cut_copy_clear (*selection, op);
4329 Editor::paste (float times, bool from_context)
4331 DEBUG_TRACE (DEBUG::CutNPaste, "paste to preferred edit pos\n");
4333 paste_internal (get_preferred_edit_position (false, from_context), times);
4337 Editor::mouse_paste ()
4342 if (!mouse_frame (where, ignored)) {
4347 paste_internal (where, 1);
4351 Editor::paste_internal (framepos_t position, float times)
4353 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("apparent paste position is %1\n", position));
4355 if (internal_editing()) {
4356 if (cut_buffer->midi_notes.empty()) {
4360 if (cut_buffer->empty()) {
4365 if (position == max_framepos) {
4366 position = get_preferred_edit_position();
4367 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("preferred edit position is %1\n", position));
4370 if (position == last_paste_pos) {
4371 /* repeated paste in the same position */
4374 /* paste in new location, reset repeated paste state */
4376 last_paste_pos = position;
4380 TrackViewList::iterator i;
4383 /* get everything in the correct order */
4385 if (_edit_point == Editing::EditAtMouse && entered_track) {
4386 /* With the mouse edit point, paste onto the track under the mouse */
4387 ts.push_back (entered_track);
4388 } else if (_edit_point == Editing::EditAtMouse && entered_regionview) {
4389 /* With the mouse edit point, paste onto the track of the region under the mouse */
4390 ts.push_back (&entered_regionview->get_time_axis_view());
4391 } else if (!selection->tracks.empty()) {
4392 /* Otherwise, if there are some selected tracks, paste to them */
4393 ts = selection->tracks.filter_to_unique_playlists ();
4394 sort_track_selection (ts);
4395 } else if (_last_cut_copy_source_track) {
4396 /* Otherwise paste to the track that the cut/copy came from;
4397 see discussion in mantis #3333.
4399 ts.push_back (_last_cut_copy_source_track);
4402 if (internal_editing ()) {
4404 /* undo/redo is handled by individual tracks/regions */
4407 RegionSelection::iterator r;
4408 MidiNoteSelection::iterator cb;
4410 get_regions_at (rs, position, ts);
4412 for (cb = cut_buffer->midi_notes.begin(), r = rs.begin();
4413 cb != cut_buffer->midi_notes.end() && r != rs.end(); ++r) {
4414 MidiRegionView* mrv = dynamic_cast<MidiRegionView*> (*r);
4416 mrv->paste (position, paste_count, times, **cb);
4423 /* we do redo (do you do voodoo?) */
4425 begin_reversible_command (Operations::paste);
4427 for (nth = 0, i = ts.begin(); i != ts.end(); ++i, ++nth) {
4428 (*i)->paste (position, paste_count, times, *cut_buffer, nth);
4431 commit_reversible_command ();
4436 Editor::duplicate_some_regions (RegionSelection& regions, float times)
4438 boost::shared_ptr<Playlist> playlist;
4439 RegionSelection sel = regions; // clear (below) may clear the argument list if its the current region selection
4440 RegionSelection foo;
4442 framepos_t const start_frame = regions.start ();
4443 framepos_t const end_frame = regions.end_frame ();
4445 begin_reversible_command (Operations::duplicate_region);
4447 selection->clear_regions ();
4449 for (RegionSelection::iterator i = sel.begin(); i != sel.end(); ++i) {
4451 boost::shared_ptr<Region> r ((*i)->region());
4453 TimeAxisView& tv = (*i)->get_time_axis_view();
4454 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (&tv);
4455 latest_regionviews.clear ();
4456 sigc::connection c = rtv->view()->RegionViewAdded.connect (sigc::mem_fun(*this, &Editor::collect_new_region_view));
4458 playlist = (*i)->region()->playlist();
4459 playlist->clear_changes ();
4460 playlist->duplicate (r, end_frame + (r->first_frame() - start_frame), times);
4461 _session->add_command(new StatefulDiffCommand (playlist));
4465 foo.insert (foo.end(), latest_regionviews.begin(), latest_regionviews.end());
4468 commit_reversible_command ();
4471 selection->set (foo);
4476 Editor::duplicate_selection (float times)
4478 if (selection->time.empty() || selection->tracks.empty()) {
4482 boost::shared_ptr<Playlist> playlist;
4483 vector<boost::shared_ptr<Region> > new_regions;
4484 vector<boost::shared_ptr<Region> >::iterator ri;
4486 create_region_from_selection (new_regions);
4488 if (new_regions.empty()) {
4492 begin_reversible_command (_("duplicate selection"));
4494 ri = new_regions.begin();
4496 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4498 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4499 if ((playlist = (*i)->playlist()) == 0) {
4502 playlist->clear_changes ();
4503 playlist->duplicate (*ri, selection->time[clicked_selection].end, times);
4504 _session->add_command (new StatefulDiffCommand (playlist));
4507 if (ri == new_regions.end()) {
4512 commit_reversible_command ();
4515 /** Reset all selected points to the relevant default value */
4517 Editor::reset_point_selection ()
4519 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
4520 ARDOUR::AutomationList::iterator j = (*i)->model ();
4521 (*j)->value = (*i)->line().the_list()->default_value ();
4526 Editor::center_playhead ()
4528 float const page = _visible_canvas_width * samples_per_pixel;
4529 center_screen_internal (playhead_cursor->current_frame (), page);
4533 Editor::center_edit_point ()
4535 float const page = _visible_canvas_width * samples_per_pixel;
4536 center_screen_internal (get_preferred_edit_position(), page);
4539 /** Caller must begin and commit a reversible command */
4541 Editor::clear_playlist (boost::shared_ptr<Playlist> playlist)
4543 playlist->clear_changes ();
4545 _session->add_command (new StatefulDiffCommand (playlist));
4549 Editor::nudge_track (bool use_edit, bool forwards)
4551 boost::shared_ptr<Playlist> playlist;
4552 framepos_t distance;
4553 framepos_t next_distance;
4557 start = get_preferred_edit_position();
4562 if ((distance = get_nudge_distance (start, next_distance)) == 0) {
4566 if (selection->tracks.empty()) {
4570 begin_reversible_command (_("nudge track"));
4572 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4574 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4576 if ((playlist = (*i)->playlist()) == 0) {
4580 playlist->clear_changes ();
4581 playlist->clear_owned_changes ();
4583 playlist->nudge_after (start, distance, forwards);
4585 vector<Command*> cmds;
4587 playlist->rdiff (cmds);
4588 _session->add_commands (cmds);
4590 _session->add_command (new StatefulDiffCommand (playlist));
4593 commit_reversible_command ();
4597 Editor::remove_last_capture ()
4599 vector<string> choices;
4606 if (Config->get_verify_remove_last_capture()) {
4607 prompt = _("Do you really want to destroy the last capture?"
4608 "\n(This is destructive and cannot be undone)");
4610 choices.push_back (_("No, do nothing."));
4611 choices.push_back (_("Yes, destroy it."));
4613 Gtkmm2ext::Choice prompter (_("Destroy last capture"), prompt, choices);
4615 if (prompter.run () == 1) {
4616 _session->remove_last_capture ();
4617 _regions->redisplay ();
4621 _session->remove_last_capture();
4622 _regions->redisplay ();
4627 Editor::normalize_region ()
4633 RegionSelection rs = get_regions_from_selection_and_entered ();
4639 NormalizeDialog dialog (rs.size() > 1);
4641 if (dialog.run () == RESPONSE_CANCEL) {
4645 set_canvas_cursor (_cursors->wait);
4648 /* XXX: should really only count audio regions here */
4649 int const regions = rs.size ();
4651 /* Make a list of the selected audio regions' maximum amplitudes, and also
4652 obtain the maximum amplitude of them all.
4654 list<double> max_amps;
4656 for (RegionSelection::const_iterator i = rs.begin(); i != rs.end(); ++i) {
4657 AudioRegionView const * arv = dynamic_cast<AudioRegionView const *> (*i);
4659 dialog.descend (1.0 / regions);
4660 double const a = arv->audio_region()->maximum_amplitude (&dialog);
4663 /* the user cancelled the operation */
4664 set_canvas_cursor (current_canvas_cursor);
4668 max_amps.push_back (a);
4669 max_amp = max (max_amp, a);
4674 begin_reversible_command (_("normalize"));
4676 list<double>::const_iterator a = max_amps.begin ();
4678 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
4679 AudioRegionView* const arv = dynamic_cast<AudioRegionView*> (*r);
4684 arv->region()->clear_changes ();
4686 double const amp = dialog.normalize_individually() ? *a : max_amp;
4688 arv->audio_region()->normalize (amp, dialog.target ());
4689 _session->add_command (new StatefulDiffCommand (arv->region()));
4694 commit_reversible_command ();
4695 set_canvas_cursor (current_canvas_cursor);
4700 Editor::reset_region_scale_amplitude ()
4706 RegionSelection rs = get_regions_from_selection_and_entered ();
4712 begin_reversible_command ("reset gain");
4714 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
4715 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
4718 arv->region()->clear_changes ();
4719 arv->audio_region()->set_scale_amplitude (1.0f);
4720 _session->add_command (new StatefulDiffCommand (arv->region()));
4723 commit_reversible_command ();
4727 Editor::adjust_region_gain (bool up)
4729 RegionSelection rs = get_regions_from_selection_and_entered ();
4731 if (!_session || rs.empty()) {
4735 begin_reversible_command ("adjust region gain");
4737 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
4738 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
4743 arv->region()->clear_changes ();
4745 double dB = accurate_coefficient_to_dB (arv->audio_region()->scale_amplitude ());
4753 arv->audio_region()->set_scale_amplitude (dB_to_coefficient (dB));
4754 _session->add_command (new StatefulDiffCommand (arv->region()));
4757 commit_reversible_command ();
4762 Editor::reverse_region ()
4768 Reverse rev (*_session);
4769 apply_filter (rev, _("reverse regions"));
4773 Editor::strip_region_silence ()
4779 RegionSelection rs = get_regions_from_selection_and_entered ();
4785 std::list<RegionView*> audio_only;
4787 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
4788 AudioRegionView* const arv = dynamic_cast<AudioRegionView*> (*i);
4790 audio_only.push_back (arv);
4794 StripSilenceDialog d (_session, audio_only);
4795 int const r = d.run ();
4799 if (r == Gtk::RESPONSE_OK) {
4800 ARDOUR::AudioIntervalMap silences;
4801 d.silences (silences);
4802 StripSilence s (*_session, silences, d.fade_length());
4803 apply_filter (s, _("strip silence"), &d);
4808 Editor::apply_midi_note_edit_op_to_region (MidiOperator& op, MidiRegionView& mrv)
4810 Evoral::Sequence<Evoral::MusicalTime>::Notes selected;
4811 mrv.selection_as_notelist (selected, true);
4813 vector<Evoral::Sequence<Evoral::MusicalTime>::Notes> v;
4814 v.push_back (selected);
4816 framepos_t pos_frames = mrv.midi_region()->position() - mrv.midi_region()->start();
4817 double pos_beats = _session->tempo_map().framewalk_to_beats(0, pos_frames);
4819 return op (mrv.midi_region()->model(), pos_beats, v);
4823 Editor::apply_midi_note_edit_op (MidiOperator& op)
4827 RegionSelection rs = get_regions_from_selection_and_entered ();
4833 begin_reversible_command (op.name ());
4835 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
4836 RegionSelection::iterator tmp = r;
4839 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*r);
4842 cmd = apply_midi_note_edit_op_to_region (op, *mrv);
4845 _session->add_command (cmd);
4852 commit_reversible_command ();
4856 Editor::fork_region ()
4858 RegionSelection rs = get_regions_from_selection_and_entered ();
4864 begin_reversible_command (_("Fork Region(s)"));
4866 set_canvas_cursor (_cursors->wait);
4869 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
4870 RegionSelection::iterator tmp = r;
4873 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*>(*r);
4877 boost::shared_ptr<Playlist> playlist = mrv->region()->playlist();
4878 boost::shared_ptr<MidiSource> new_source = _session->create_midi_source_by_stealing_name (mrv->midi_view()->track());
4879 boost::shared_ptr<MidiRegion> newregion = mrv->midi_region()->clone (new_source);
4881 playlist->clear_changes ();
4882 playlist->replace_region (mrv->region(), newregion, mrv->region()->position());
4883 _session->add_command(new StatefulDiffCommand (playlist));
4885 error << string_compose (_("Could not unlink %1"), mrv->region()->name()) << endmsg;
4892 commit_reversible_command ();
4894 set_canvas_cursor (current_canvas_cursor);
4898 Editor::quantize_region ()
4900 int selected_midi_region_cnt = 0;
4906 RegionSelection rs = get_regions_from_selection_and_entered ();
4912 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
4913 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*r);
4915 selected_midi_region_cnt++;
4919 if (selected_midi_region_cnt == 0) {
4923 QuantizeDialog* qd = new QuantizeDialog (*this);
4926 const int r = qd->run ();
4929 if (r == Gtk::RESPONSE_OK) {
4930 Quantize quant (*_session, qd->snap_start(), qd->snap_end(),
4931 qd->start_grid_size(), qd->end_grid_size(),
4932 qd->strength(), qd->swing(), qd->threshold());
4934 apply_midi_note_edit_op (quant);
4939 Editor::insert_patch_change (bool from_context)
4941 RegionSelection rs = get_regions_from_selection_and_entered ();
4947 const framepos_t p = get_preferred_edit_position (false, from_context);
4949 /* XXX: bit of a hack; use the MIDNAM from the first selected region;
4950 there may be more than one, but the PatchChangeDialog can only offer
4951 one set of patch menus.
4953 MidiRegionView* first = dynamic_cast<MidiRegionView*> (rs.front ());
4955 Evoral::PatchChange<Evoral::MusicalTime> empty (0, 0, 0, 0);
4956 PatchChangeDialog d (0, _session, empty, first->instrument_info(), Gtk::Stock::ADD);
4958 if (d.run() == RESPONSE_CANCEL) {
4962 for (RegionSelection::iterator i = rs.begin (); i != rs.end(); ++i) {
4963 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*i);
4965 if (p >= mrv->region()->first_frame() && p <= mrv->region()->last_frame()) {
4966 mrv->add_patch_change (p - mrv->region()->position(), d.patch ());
4973 Editor::apply_filter (Filter& filter, string command, ProgressReporter* progress)
4975 RegionSelection rs = get_regions_from_selection_and_entered ();
4981 begin_reversible_command (command);
4983 set_canvas_cursor (_cursors->wait);
4987 int const N = rs.size ();
4989 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
4990 RegionSelection::iterator tmp = r;
4993 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
4995 boost::shared_ptr<Playlist> playlist = arv->region()->playlist();
4998 progress->descend (1.0 / N);
5001 if (arv->audio_region()->apply (filter, progress) == 0) {
5003 playlist->clear_changes ();
5004 playlist->clear_owned_changes ();
5006 if (filter.results.empty ()) {
5008 /* no regions returned; remove the old one */
5009 playlist->remove_region (arv->region ());
5013 std::vector<boost::shared_ptr<Region> >::iterator res = filter.results.begin ();
5015 /* first region replaces the old one */
5016 playlist->replace_region (arv->region(), *res, (*res)->position());
5020 while (res != filter.results.end()) {
5021 playlist->add_region (*res, (*res)->position());
5027 /* We might have removed regions, which alters other regions' layering_index,
5028 so we need to do a recursive diff here.
5030 vector<Command*> cmds;
5031 playlist->rdiff (cmds);
5032 _session->add_commands (cmds);
5034 _session->add_command(new StatefulDiffCommand (playlist));
5040 progress->ascend ();
5048 commit_reversible_command ();
5051 set_canvas_cursor (current_canvas_cursor);
5055 Editor::external_edit_region ()
5061 Editor::reset_region_gain_envelopes ()
5063 RegionSelection rs = get_regions_from_selection_and_entered ();
5065 if (!_session || rs.empty()) {
5069 _session->begin_reversible_command (_("reset region gain"));
5071 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5072 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
5074 boost::shared_ptr<AutomationList> alist (arv->audio_region()->envelope());
5075 XMLNode& before (alist->get_state());
5077 arv->audio_region()->set_default_envelope ();
5078 _session->add_command (new MementoCommand<AutomationList>(*arv->audio_region()->envelope().get(), &before, &alist->get_state()));
5082 _session->commit_reversible_command ();
5086 Editor::set_region_gain_visibility (RegionView* rv)
5088 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (rv);
5090 arv->update_envelope_visibility();
5095 Editor::set_gain_envelope_visibility ()
5101 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5102 AudioTimeAxisView* v = dynamic_cast<AudioTimeAxisView*>(*i);
5104 v->audio_view()->foreach_regionview (sigc::mem_fun (this, &Editor::set_region_gain_visibility));
5110 Editor::toggle_gain_envelope_active ()
5112 if (_ignore_region_action) {
5116 RegionSelection rs = get_regions_from_selection_and_entered ();
5118 if (!_session || rs.empty()) {
5122 _session->begin_reversible_command (_("region gain envelope active"));
5124 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5125 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
5127 arv->region()->clear_changes ();
5128 arv->audio_region()->set_envelope_active (!arv->audio_region()->envelope_active());
5129 _session->add_command (new StatefulDiffCommand (arv->region()));
5133 _session->commit_reversible_command ();
5137 Editor::toggle_region_lock ()
5139 if (_ignore_region_action) {
5143 RegionSelection rs = get_regions_from_selection_and_entered ();
5145 if (!_session || rs.empty()) {
5149 _session->begin_reversible_command (_("toggle region lock"));
5151 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5152 (*i)->region()->clear_changes ();
5153 (*i)->region()->set_locked (!(*i)->region()->locked());
5154 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5157 _session->commit_reversible_command ();
5161 Editor::toggle_region_video_lock ()
5163 if (_ignore_region_action) {
5167 RegionSelection rs = get_regions_from_selection_and_entered ();
5169 if (!_session || rs.empty()) {
5173 _session->begin_reversible_command (_("Toggle Video Lock"));
5175 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5176 (*i)->region()->clear_changes ();
5177 (*i)->region()->set_video_locked (!(*i)->region()->video_locked());
5178 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5181 _session->commit_reversible_command ();
5185 Editor::toggle_region_lock_style ()
5187 if (_ignore_region_action) {
5191 RegionSelection rs = get_regions_from_selection_and_entered ();
5193 if (!_session || rs.empty()) {
5197 _session->begin_reversible_command (_("region lock style"));
5199 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5200 (*i)->region()->clear_changes ();
5201 PositionLockStyle const ns = (*i)->region()->position_lock_style() == AudioTime ? MusicTime : AudioTime;
5202 (*i)->region()->set_position_lock_style (ns);
5203 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5206 _session->commit_reversible_command ();
5210 Editor::toggle_opaque_region ()
5212 if (_ignore_region_action) {
5216 RegionSelection rs = get_regions_from_selection_and_entered ();
5218 if (!_session || rs.empty()) {
5222 _session->begin_reversible_command (_("change region opacity"));
5224 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5225 (*i)->region()->clear_changes ();
5226 (*i)->region()->set_opaque (!(*i)->region()->opaque());
5227 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5230 _session->commit_reversible_command ();
5234 Editor::toggle_record_enable ()
5236 bool new_state = false;
5238 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5239 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5242 if (!rtav->is_track())
5246 new_state = !rtav->track()->record_enabled();
5250 rtav->track()->set_record_enabled (new_state, this);
5255 Editor::toggle_solo ()
5257 bool new_state = false;
5259 boost::shared_ptr<RouteList> rl (new RouteList);
5261 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5262 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5269 new_state = !rtav->route()->soloed ();
5273 rl->push_back (rtav->route());
5276 _session->set_solo (rl, new_state, Session::rt_cleanup, true);
5280 Editor::toggle_mute ()
5282 bool new_state = false;
5284 boost::shared_ptr<RouteList> rl (new RouteList);
5286 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5287 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5294 new_state = !rtav->route()->muted();
5298 rl->push_back (rtav->route());
5301 _session->set_mute (rl, new_state, Session::rt_cleanup, true);
5305 Editor::toggle_solo_isolate ()
5311 Editor::fade_range ()
5313 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
5315 begin_reversible_command (_("fade range"));
5317 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
5318 (*i)->fade_range (selection->time);
5321 commit_reversible_command ();
5326 Editor::set_fade_length (bool in)
5328 RegionSelection rs = get_regions_from_selection_and_entered ();
5334 /* we need a region to measure the offset from the start */
5336 RegionView* rv = rs.front ();
5338 framepos_t pos = get_preferred_edit_position();
5342 if (pos > rv->region()->last_frame() || pos < rv->region()->first_frame()) {
5343 /* edit point is outside the relevant region */
5348 if (pos <= rv->region()->position()) {
5352 len = pos - rv->region()->position();
5353 cmd = _("set fade in length");
5355 if (pos >= rv->region()->last_frame()) {
5359 len = rv->region()->last_frame() - pos;
5360 cmd = _("set fade out length");
5363 begin_reversible_command (cmd);
5365 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5366 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5372 boost::shared_ptr<AutomationList> alist;
5374 alist = tmp->audio_region()->fade_in();
5376 alist = tmp->audio_region()->fade_out();
5379 XMLNode &before = alist->get_state();
5382 tmp->audio_region()->set_fade_in_length (len);
5383 tmp->audio_region()->set_fade_in_active (true);
5385 tmp->audio_region()->set_fade_out_length (len);
5386 tmp->audio_region()->set_fade_out_active (true);
5389 XMLNode &after = alist->get_state();
5390 _session->add_command(new MementoCommand<AutomationList>(*alist, &before, &after));
5393 commit_reversible_command ();
5397 Editor::set_fade_in_shape (FadeShape shape)
5399 RegionSelection rs = get_regions_from_selection_and_entered ();
5405 begin_reversible_command (_("set fade in shape"));
5407 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5408 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5414 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_in();
5415 XMLNode &before = alist->get_state();
5417 tmp->audio_region()->set_fade_in_shape (shape);
5419 XMLNode &after = alist->get_state();
5420 _session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
5423 commit_reversible_command ();
5428 Editor::set_fade_out_shape (FadeShape shape)
5430 RegionSelection rs = get_regions_from_selection_and_entered ();
5436 begin_reversible_command (_("set fade out shape"));
5438 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5439 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5445 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_out();
5446 XMLNode &before = alist->get_state();
5448 tmp->audio_region()->set_fade_out_shape (shape);
5450 XMLNode &after = alist->get_state();
5451 _session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
5454 commit_reversible_command ();
5458 Editor::set_fade_in_active (bool yn)
5460 RegionSelection rs = get_regions_from_selection_and_entered ();
5466 begin_reversible_command (_("set fade in active"));
5468 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5469 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5476 boost::shared_ptr<AudioRegion> ar (tmp->audio_region());
5478 ar->clear_changes ();
5479 ar->set_fade_in_active (yn);
5480 _session->add_command (new StatefulDiffCommand (ar));
5483 commit_reversible_command ();
5487 Editor::set_fade_out_active (bool yn)
5489 RegionSelection rs = get_regions_from_selection_and_entered ();
5495 begin_reversible_command (_("set fade out active"));
5497 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5498 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5504 boost::shared_ptr<AudioRegion> ar (tmp->audio_region());
5506 ar->clear_changes ();
5507 ar->set_fade_out_active (yn);
5508 _session->add_command(new StatefulDiffCommand (ar));
5511 commit_reversible_command ();
5515 Editor::toggle_region_fades (int dir)
5517 if (_ignore_region_action) {
5521 boost::shared_ptr<AudioRegion> ar;
5524 RegionSelection rs = get_regions_from_selection_and_entered ();
5530 RegionSelection::iterator i;
5531 for (i = rs.begin(); i != rs.end(); ++i) {
5532 if ((ar = boost::dynamic_pointer_cast<AudioRegion>((*i)->region())) != 0) {
5534 yn = ar->fade_out_active ();
5536 yn = ar->fade_in_active ();
5542 if (i == rs.end()) {
5546 /* XXX should this undo-able? */
5548 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5549 if ((ar = boost::dynamic_pointer_cast<AudioRegion>((*i)->region())) == 0) {
5552 if (dir == 1 || dir == 0) {
5553 ar->set_fade_in_active (!yn);
5556 if (dir == -1 || dir == 0) {
5557 ar->set_fade_out_active (!yn);
5563 /** Update region fade visibility after its configuration has been changed */
5565 Editor::update_region_fade_visibility ()
5567 bool _fade_visibility = _session->config.get_show_region_fades ();
5569 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5570 AudioTimeAxisView* v = dynamic_cast<AudioTimeAxisView*>(*i);
5572 if (_fade_visibility) {
5573 v->audio_view()->show_all_fades ();
5575 v->audio_view()->hide_all_fades ();
5582 Editor::set_edit_point ()
5587 if (!mouse_frame (where, ignored)) {
5593 if (selection->markers.empty()) {
5595 mouse_add_new_marker (where);
5600 Location* loc = find_location_from_marker (selection->markers.front(), ignored);
5603 loc->move_to (where);
5609 Editor::set_playhead_cursor ()
5611 if (entered_marker) {
5612 _session->request_locate (entered_marker->position(), _session->transport_rolling());
5617 if (!mouse_frame (where, ignored)) {
5624 _session->request_locate (where, _session->transport_rolling());
5628 if ( Config->get_follow_edits() )
5629 cancel_time_selection();
5633 Editor::split_region ()
5635 if ( !selection->time.empty()) {
5636 separate_regions_between (selection->time);
5640 RegionSelection rs = get_regions_from_selection_and_edit_point ();
5642 framepos_t where = get_preferred_edit_position ();
5648 split_regions_at (where, rs);
5651 struct EditorOrderRouteSorter {
5652 bool operator() (boost::shared_ptr<Route> a, boost::shared_ptr<Route> b) {
5653 return a->order_key () < b->order_key ();
5658 Editor::select_next_route()
5660 if (selection->tracks.empty()) {
5661 selection->set (track_views.front());
5665 TimeAxisView* current = selection->tracks.front();
5669 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5670 if (*i == current) {
5672 if (i != track_views.end()) {
5675 current = (*(track_views.begin()));
5676 //selection->set (*(track_views.begin()));
5681 rui = dynamic_cast<RouteUI *>(current);
5682 } while ( current->hidden() || (rui != NULL && !rui->route()->active()));
5684 selection->set(current);
5686 ensure_time_axis_view_is_visible (*current, false);
5690 Editor::select_prev_route()
5692 if (selection->tracks.empty()) {
5693 selection->set (track_views.front());
5697 TimeAxisView* current = selection->tracks.front();
5701 for (TrackViewList::reverse_iterator i = track_views.rbegin(); i != track_views.rend(); ++i) {
5702 if (*i == current) {
5704 if (i != track_views.rend()) {
5707 current = *(track_views.rbegin());
5712 rui = dynamic_cast<RouteUI *>(current);
5713 } while ( current->hidden() || (rui != NULL && !rui->route()->active()));
5715 selection->set (current);
5717 ensure_time_axis_view_is_visible (*current, false);
5721 Editor::set_loop_from_selection (bool play)
5723 if (_session == 0 || selection->time.empty()) {
5727 framepos_t start = selection->time[clicked_selection].start;
5728 framepos_t end = selection->time[clicked_selection].end;
5730 set_loop_range (start, end, _("set loop range from selection"));
5733 _session->request_locate (start, true);
5734 _session->request_play_loop (true);
5739 Editor::set_loop_from_edit_range (bool play)
5741 if (_session == 0) {
5748 if (!get_edit_op_range (start, end)) {
5752 set_loop_range (start, end, _("set loop range from edit range"));
5755 _session->request_locate (start, true);
5756 _session->request_play_loop (true);
5761 Editor::set_loop_from_region (bool play)
5763 framepos_t start = max_framepos;
5766 RegionSelection rs = get_regions_from_selection_and_entered ();
5772 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5773 if ((*i)->region()->position() < start) {
5774 start = (*i)->region()->position();
5776 if ((*i)->region()->last_frame() + 1 > end) {
5777 end = (*i)->region()->last_frame() + 1;
5781 set_loop_range (start, end, _("set loop range from region"));
5784 _session->request_locate (start, true);
5785 _session->request_play_loop (true);
5790 Editor::set_punch_from_selection ()
5792 if (_session == 0 || selection->time.empty()) {
5796 framepos_t start = selection->time[clicked_selection].start;
5797 framepos_t end = selection->time[clicked_selection].end;
5799 set_punch_range (start, end, _("set punch range from selection"));
5803 Editor::set_punch_from_edit_range ()
5805 if (_session == 0) {
5812 if (!get_edit_op_range (start, end)) {
5816 set_punch_range (start, end, _("set punch range from edit range"));
5820 Editor::set_punch_from_region ()
5822 framepos_t start = max_framepos;
5825 RegionSelection rs = get_regions_from_selection_and_entered ();
5831 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5832 if ((*i)->region()->position() < start) {
5833 start = (*i)->region()->position();
5835 if ((*i)->region()->last_frame() + 1 > end) {
5836 end = (*i)->region()->last_frame() + 1;
5840 set_punch_range (start, end, _("set punch range from region"));
5844 Editor::pitch_shift_region ()
5846 RegionSelection rs = get_regions_from_selection_and_entered ();
5848 RegionSelection audio_rs;
5849 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5850 if (dynamic_cast<AudioRegionView*> (*i)) {
5851 audio_rs.push_back (*i);
5855 if (audio_rs.empty()) {
5859 pitch_shift (audio_rs, 1.2);
5863 Editor::transpose_region ()
5865 RegionSelection rs = get_regions_from_selection_and_entered ();
5867 list<MidiRegionView*> midi_region_views;
5868 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5869 MidiRegionView* mrv = dynamic_cast<MidiRegionView*> (*i);
5871 midi_region_views.push_back (mrv);
5876 int const r = d.run ();
5877 if (r != RESPONSE_ACCEPT) {
5881 for (list<MidiRegionView*>::iterator i = midi_region_views.begin(); i != midi_region_views.end(); ++i) {
5882 (*i)->midi_region()->transpose (d.semitones ());
5887 Editor::set_tempo_from_region ()
5889 RegionSelection rs = get_regions_from_selection_and_entered ();
5891 if (!_session || rs.empty()) {
5895 RegionView* rv = rs.front();
5897 define_one_bar (rv->region()->position(), rv->region()->last_frame() + 1);
5901 Editor::use_range_as_bar ()
5903 framepos_t start, end;
5904 if (get_edit_op_range (start, end)) {
5905 define_one_bar (start, end);
5910 Editor::define_one_bar (framepos_t start, framepos_t end)
5912 framepos_t length = end - start;
5914 const Meter& m (_session->tempo_map().meter_at (start));
5916 /* length = 1 bar */
5918 /* now we want frames per beat.
5919 we have frames per bar, and beats per bar, so ...
5922 /* XXXX METER MATH */
5924 double frames_per_beat = length / m.divisions_per_bar();
5926 /* beats per minute = */
5928 double beats_per_minute = (_session->frame_rate() * 60.0) / frames_per_beat;
5930 /* now decide whether to:
5932 (a) set global tempo
5933 (b) add a new tempo marker
5937 const TempoSection& t (_session->tempo_map().tempo_section_at (start));
5939 bool do_global = false;
5941 if ((_session->tempo_map().n_tempos() == 1) && (_session->tempo_map().n_meters() == 1)) {
5943 /* only 1 tempo & 1 meter: ask if the user wants to set the tempo
5944 at the start, or create a new marker
5947 vector<string> options;
5948 options.push_back (_("Cancel"));
5949 options.push_back (_("Add new marker"));
5950 options.push_back (_("Set global tempo"));
5953 _("Define one bar"),
5954 _("Do you want to set the global tempo or add a new tempo marker?"),
5958 c.set_default_response (2);
5974 /* more than 1 tempo and/or meter section already, go ahead do the "usual":
5975 if the marker is at the region starter, change it, otherwise add
5980 begin_reversible_command (_("set tempo from region"));
5981 XMLNode& before (_session->tempo_map().get_state());
5984 _session->tempo_map().change_initial_tempo (beats_per_minute, t.note_type());
5985 } else if (t.frame() == start) {
5986 _session->tempo_map().change_existing_tempo_at (start, beats_per_minute, t.note_type());
5988 Timecode::BBT_Time bbt;
5989 _session->tempo_map().bbt_time (start, bbt);
5990 _session->tempo_map().add_tempo (Tempo (beats_per_minute, t.note_type()), bbt);
5993 XMLNode& after (_session->tempo_map().get_state());
5995 _session->add_command (new MementoCommand<TempoMap>(_session->tempo_map(), &before, &after));
5996 commit_reversible_command ();
6000 Editor::split_region_at_transients ()
6002 AnalysisFeatureList positions;
6004 RegionSelection rs = get_regions_from_selection_and_entered ();
6006 if (!_session || rs.empty()) {
6010 _session->begin_reversible_command (_("split regions"));
6012 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ) {
6014 RegionSelection::iterator tmp;
6019 boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion> ((*i)->region());
6021 if (ar && (ar->get_transients (positions) == 0)) {
6022 split_region_at_points ((*i)->region(), positions, true);
6029 _session->commit_reversible_command ();
6034 Editor::split_region_at_points (boost::shared_ptr<Region> r, AnalysisFeatureList& positions, bool can_ferret, bool select_new)
6036 bool use_rhythmic_rodent = false;
6038 boost::shared_ptr<Playlist> pl = r->playlist();
6040 list<boost::shared_ptr<Region> > new_regions;
6046 if (positions.empty()) {
6051 if (positions.size() > 20 && can_ferret) {
6052 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);
6053 MessageDialog msg (msgstr,
6056 Gtk::BUTTONS_OK_CANCEL);
6059 msg.add_button (_("Call for the Ferret!"), RESPONSE_APPLY);
6060 msg.set_secondary_text (_("Press OK to continue with this split operation\nor ask the Ferret dialog to tune the analysis"));
6062 msg.set_secondary_text (_("Press OK to continue with this split operation"));
6065 msg.set_title (_("Excessive split?"));
6068 int response = msg.run();
6074 case RESPONSE_APPLY:
6075 use_rhythmic_rodent = true;
6082 if (use_rhythmic_rodent) {
6083 show_rhythm_ferret ();
6087 AnalysisFeatureList::const_iterator x;
6089 pl->clear_changes ();
6090 pl->clear_owned_changes ();
6092 x = positions.begin();
6094 if (x == positions.end()) {
6099 pl->remove_region (r);
6103 while (x != positions.end()) {
6105 /* deal with positons that are out of scope of present region bounds */
6106 if (*x <= 0 || *x > r->length()) {
6111 /* file start = original start + how far we from the initial position ?
6114 framepos_t file_start = r->start() + pos;
6116 /* length = next position - current position
6119 framepos_t len = (*x) - pos;
6121 /* XXX we do we really want to allow even single-sample regions?
6122 shouldn't we have some kind of lower limit on region size?
6131 if (RegionFactory::region_name (new_name, r->name())) {
6135 /* do NOT announce new regions 1 by one, just wait till they are all done */
6139 plist.add (ARDOUR::Properties::start, file_start);
6140 plist.add (ARDOUR::Properties::length, len);
6141 plist.add (ARDOUR::Properties::name, new_name);
6142 plist.add (ARDOUR::Properties::layer, 0);
6144 boost::shared_ptr<Region> nr = RegionFactory::create (r->sources(), plist, false);
6145 /* because we set annouce to false, manually add the new region to the
6148 RegionFactory::map_add (nr);
6150 pl->add_region (nr, r->position() + pos);
6153 new_regions.push_front(nr);
6162 RegionFactory::region_name (new_name, r->name());
6164 /* Add the final region */
6167 plist.add (ARDOUR::Properties::start, r->start() + pos);
6168 plist.add (ARDOUR::Properties::length, r->last_frame() - (r->position() + pos) + 1);
6169 plist.add (ARDOUR::Properties::name, new_name);
6170 plist.add (ARDOUR::Properties::layer, 0);
6172 boost::shared_ptr<Region> nr = RegionFactory::create (r->sources(), plist, false);
6173 /* because we set annouce to false, manually add the new region to the
6176 RegionFactory::map_add (nr);
6177 pl->add_region (nr, r->position() + pos);
6180 new_regions.push_front(nr);
6185 /* We might have removed regions, which alters other regions' layering_index,
6186 so we need to do a recursive diff here.
6188 vector<Command*> cmds;
6190 _session->add_commands (cmds);
6192 _session->add_command (new StatefulDiffCommand (pl));
6196 for (list<boost::shared_ptr<Region> >::iterator i = new_regions.begin(); i != new_regions.end(); ++i){
6197 set_selected_regionview_from_region_list ((*i), Selection::Add);
6203 Editor::place_transient()
6209 RegionSelection rs = get_regions_from_selection_and_edit_point ();
6215 framepos_t where = get_preferred_edit_position();
6217 _session->begin_reversible_command (_("place transient"));
6219 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6220 framepos_t position = (*r)->region()->position();
6221 (*r)->region()->add_transient(where - position);
6224 _session->commit_reversible_command ();
6228 Editor::remove_transient(ArdourCanvas::Item* item)
6234 ArdourCanvas::Line* _line = reinterpret_cast<ArdourCanvas::Line*> (item);
6237 AudioRegionView* _arv = reinterpret_cast<AudioRegionView*> (item->get_data ("regionview"));
6238 _arv->remove_transient (*(float*) _line->get_data ("position"));
6242 Editor::snap_regions_to_grid ()
6244 list <boost::shared_ptr<Playlist > > used_playlists;
6246 RegionSelection rs = get_regions_from_selection_and_entered ();
6248 if (!_session || rs.empty()) {
6252 _session->begin_reversible_command (_("snap regions to grid"));
6254 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6256 boost::shared_ptr<Playlist> pl = (*r)->region()->playlist();
6258 if (!pl->frozen()) {
6259 /* we haven't seen this playlist before */
6261 /* remember used playlists so we can thaw them later */
6262 used_playlists.push_back(pl);
6266 framepos_t start_frame = (*r)->region()->first_frame ();
6267 snap_to (start_frame);
6268 (*r)->region()->set_position (start_frame);
6271 while (used_playlists.size() > 0) {
6272 list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
6274 used_playlists.pop_front();
6277 _session->commit_reversible_command ();
6281 Editor::close_region_gaps ()
6283 list <boost::shared_ptr<Playlist > > used_playlists;
6285 RegionSelection rs = get_regions_from_selection_and_entered ();
6287 if (!_session || rs.empty()) {
6291 Dialog dialog (_("Close Region Gaps"));
6294 table.set_spacings (12);
6295 table.set_border_width (12);
6296 Label* l = manage (left_aligned_label (_("Crossfade length")));
6297 table.attach (*l, 0, 1, 0, 1);
6299 SpinButton spin_crossfade (1, 0);
6300 spin_crossfade.set_range (0, 15);
6301 spin_crossfade.set_increments (1, 1);
6302 spin_crossfade.set_value (5);
6303 table.attach (spin_crossfade, 1, 2, 0, 1);
6305 table.attach (*manage (new Label (_("ms"))), 2, 3, 0, 1);
6307 l = manage (left_aligned_label (_("Pull-back length")));
6308 table.attach (*l, 0, 1, 1, 2);
6310 SpinButton spin_pullback (1, 0);
6311 spin_pullback.set_range (0, 100);
6312 spin_pullback.set_increments (1, 1);
6313 spin_pullback.set_value(30);
6314 table.attach (spin_pullback, 1, 2, 1, 2);
6316 table.attach (*manage (new Label (_("ms"))), 2, 3, 1, 2);
6318 dialog.get_vbox()->pack_start (table);
6319 dialog.add_button (Stock::CANCEL, RESPONSE_CANCEL);
6320 dialog.add_button (_("Ok"), RESPONSE_ACCEPT);
6323 if (dialog.run () == RESPONSE_CANCEL) {
6327 framepos_t crossfade_len = spin_crossfade.get_value();
6328 framepos_t pull_back_frames = spin_pullback.get_value();
6330 crossfade_len = lrintf (crossfade_len * _session->frame_rate()/1000);
6331 pull_back_frames = lrintf (pull_back_frames * _session->frame_rate()/1000);
6333 /* Iterate over the region list and make adjacent regions overlap by crossfade_len_ms */
6335 _session->begin_reversible_command (_("close region gaps"));
6338 boost::shared_ptr<Region> last_region;
6340 rs.sort_by_position_and_track();
6342 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6344 boost::shared_ptr<Playlist> pl = (*r)->region()->playlist();
6346 if (!pl->frozen()) {
6347 /* we haven't seen this playlist before */
6349 /* remember used playlists so we can thaw them later */
6350 used_playlists.push_back(pl);
6354 framepos_t position = (*r)->region()->position();
6356 if (idx == 0 || position < last_region->position()){
6357 last_region = (*r)->region();
6362 (*r)->region()->trim_front( (position - pull_back_frames));
6363 last_region->trim_end( (position - pull_back_frames + crossfade_len));
6365 last_region = (*r)->region();
6370 while (used_playlists.size() > 0) {
6371 list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
6373 used_playlists.pop_front();
6376 _session->commit_reversible_command ();
6380 Editor::tab_to_transient (bool forward)
6382 AnalysisFeatureList positions;
6384 RegionSelection rs = get_regions_from_selection_and_entered ();
6390 framepos_t pos = _session->audible_frame ();
6392 if (!selection->tracks.empty()) {
6394 /* don't waste time searching for transients in duplicate playlists.
6397 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
6399 for (TrackViewList::iterator t = ts.begin(); t != ts.end(); ++t) {
6401 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*t);
6404 boost::shared_ptr<Track> tr = rtv->track();
6406 boost::shared_ptr<Playlist> pl = tr->playlist ();
6408 framepos_t result = pl->find_next_transient (pos, forward ? 1 : -1);
6411 positions.push_back (result);
6424 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6425 (*r)->region()->get_transients (positions);
6429 TransientDetector::cleanup_transients (positions, _session->frame_rate(), 3.0);
6432 AnalysisFeatureList::iterator x;
6434 for (x = positions.begin(); x != positions.end(); ++x) {
6440 if (x != positions.end ()) {
6441 _session->request_locate (*x);
6445 AnalysisFeatureList::reverse_iterator x;
6447 for (x = positions.rbegin(); x != positions.rend(); ++x) {
6453 if (x != positions.rend ()) {
6454 _session->request_locate (*x);
6460 Editor::playhead_forward_to_grid ()
6466 framepos_t pos = playhead_cursor->current_frame ();
6467 if (pos < max_framepos - 1) {
6469 snap_to_internal (pos, RoundUpAlways, false);
6470 _session->request_locate (pos);
6476 Editor::playhead_backward_to_grid ()
6482 framepos_t pos = playhead_cursor->current_frame ();
6485 snap_to_internal (pos, RoundDownAlways, false);
6486 _session->request_locate (pos);
6491 Editor::set_track_height (Height h)
6493 TrackSelection& ts (selection->tracks);
6495 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
6496 (*x)->set_height_enum (h);
6501 Editor::toggle_tracks_active ()
6503 TrackSelection& ts (selection->tracks);
6505 bool target = false;
6511 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
6512 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*x);
6516 target = !rtv->_route->active();
6519 rtv->_route->set_active (target, this);
6525 Editor::remove_tracks ()
6527 TrackSelection& ts (selection->tracks);
6533 vector<string> choices;
6537 const char* trackstr;
6539 vector<boost::shared_ptr<Route> > routes;
6540 bool special_bus = false;
6542 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
6543 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*x);
6547 if (rtv->is_track()) {
6552 routes.push_back (rtv->_route);
6554 if (rtv->route()->is_master() || rtv->route()->is_monitor()) {
6559 if (special_bus && !Config->get_allow_special_bus_removal()) {
6560 MessageDialog msg (_("That would be bad news ...."),
6564 msg.set_secondary_text (string_compose (_(
6565 "Removing the master or monitor bus is such a bad idea\n\
6566 that %1 is not going to allow it.\n\
6568 If you really want to do this sort of thing\n\
6569 edit your ardour.rc file to set the\n\
6570 \"allow-special-bus-removal\" option to be \"yes\""), PROGRAM_NAME));
6577 if (ntracks + nbusses == 0) {
6581 // XXX should be using gettext plural forms, maybe?
6583 trackstr = _("tracks");
6585 trackstr = _("track");
6589 busstr = _("busses");
6596 prompt = string_compose (_("Do you really want to remove %1 %2 and %3 %4?\n"
6597 "(You may also lose the playlists associated with the %2)\n\n"
6598 "This action cannot be undone, and the session file will be overwritten!"),
6599 ntracks, trackstr, nbusses, busstr);
6601 prompt = string_compose (_("Do you really want to remove %1 %2?\n"
6602 "(You may also lose the playlists associated with the %2)\n\n"
6603 "This action cannot be undone, and the session file will be overwritten!"),
6606 } else if (nbusses) {
6607 prompt = string_compose (_("Do you really want to remove %1 %2?\n\n"
6608 "This action cannot be undone, and the session file will be overwritten"),
6612 choices.push_back (_("No, do nothing."));
6613 if (ntracks + nbusses > 1) {
6614 choices.push_back (_("Yes, remove them."));
6616 choices.push_back (_("Yes, remove it."));
6621 title = string_compose (_("Remove %1"), trackstr);
6623 title = string_compose (_("Remove %1"), busstr);
6626 Choice prompter (title, prompt, choices);
6628 if (prompter.run () != 1) {
6633 Session::StateProtector sp (_session);
6634 DisplaySuspender ds;
6635 for (vector<boost::shared_ptr<Route> >::iterator x = routes.begin(); x != routes.end(); ++x) {
6636 _session->remove_route (*x);
6642 Editor::do_insert_time ()
6644 if (selection->tracks.empty()) {
6648 InsertTimeDialog d (*this);
6649 int response = d.run ();
6651 if (response != RESPONSE_OK) {
6655 if (d.distance() == 0) {
6659 InsertTimeOption opt = d.intersected_region_action ();
6662 get_preferred_edit_position(),
6668 d.move_glued_markers(),
6669 d.move_locked_markers(),
6675 Editor::insert_time (
6676 framepos_t pos, framecnt_t frames, InsertTimeOption opt,
6677 bool all_playlists, bool ignore_music_glue, bool markers_too, bool glued_markers_too, bool locked_markers_too, bool tempo_too
6680 bool commit = false;
6682 if (Config->get_edit_mode() == Lock) {
6686 begin_reversible_command (_("insert time"));
6688 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
6690 for (TrackViewList::iterator x = ts.begin(); x != ts.end(); ++x) {
6694 /* don't operate on any playlist more than once, which could
6695 * happen if "all playlists" is enabled, but there is more
6696 * than 1 track using playlists "from" a given track.
6699 set<boost::shared_ptr<Playlist> > pl;
6701 if (all_playlists) {
6702 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*x);
6704 vector<boost::shared_ptr<Playlist> > all = _session->playlists->playlists_for_track (rtav->track ());
6705 for (vector<boost::shared_ptr<Playlist> >::iterator p = all.begin(); p != all.end(); ++p) {
6710 if ((*x)->playlist ()) {
6711 pl.insert ((*x)->playlist ());
6715 for (set<boost::shared_ptr<Playlist> >::iterator i = pl.begin(); i != pl.end(); ++i) {
6717 (*i)->clear_changes ();
6718 (*i)->clear_owned_changes ();
6720 if (opt == SplitIntersected) {
6724 (*i)->shift (pos, frames, (opt == MoveIntersected), ignore_music_glue);
6726 vector<Command*> cmds;
6728 _session->add_commands (cmds);
6730 _session->add_command (new StatefulDiffCommand (*i));
6735 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*x);
6737 rtav->route ()->shift (pos, frames);
6745 XMLNode& before (_session->locations()->get_state());
6746 Locations::LocationList copy (_session->locations()->list());
6748 for (Locations::LocationList::iterator i = copy.begin(); i != copy.end(); ++i) {
6750 Locations::LocationList::const_iterator tmp;
6752 bool const was_locked = (*i)->locked ();
6753 if (locked_markers_too) {
6757 if ((*i)->position_lock_style() == AudioTime || glued_markers_too) {
6759 if ((*i)->start() >= pos) {
6760 (*i)->set_start ((*i)->start() + frames);
6761 if (!(*i)->is_mark()) {
6762 (*i)->set_end ((*i)->end() + frames);
6775 XMLNode& after (_session->locations()->get_state());
6776 _session->add_command (new MementoCommand<Locations>(*_session->locations(), &before, &after));
6781 _session->tempo_map().insert_time (pos, frames);
6785 commit_reversible_command ();
6790 Editor::fit_selected_tracks ()
6792 if (!selection->tracks.empty()) {
6793 fit_tracks (selection->tracks);
6797 /* no selected tracks - use tracks with selected regions */
6799 if (!selection->regions.empty()) {
6800 for (RegionSelection::iterator r = selection->regions.begin(); r != selection->regions.end(); ++r) {
6801 tvl.push_back (&(*r)->get_time_axis_view ());
6807 } else if (internal_editing()) {
6808 /* no selected tracks, or regions, but in internal edit mode, so follow the mouse and use
6811 if (entered_track) {
6812 tvl.push_back (entered_track);
6821 Editor::fit_tracks (TrackViewList & tracks)
6823 if (tracks.empty()) {
6827 uint32_t child_heights = 0;
6828 int visible_tracks = 0;
6830 for (TrackSelection::iterator t = tracks.begin(); t != tracks.end(); ++t) {
6832 if (!(*t)->marked_for_display()) {
6836 child_heights += (*t)->effective_height() - (*t)->current_height();
6840 /* compute the per-track height from:
6842 total canvas visible height -
6843 height that will be taken by visible children of selected
6844 tracks - height of the ruler/hscroll area
6846 uint32_t h = (uint32_t) floor ((trackviews_height() - child_heights) / visible_tracks);
6847 double first_y_pos = DBL_MAX;
6849 if (h < TimeAxisView::preset_height (HeightSmall)) {
6850 MessageDialog msg (*this, _("There are too many tracks to fit in the current window"));
6851 /* too small to be displayed */
6855 undo_visual_stack.push_back (current_visual_state (true));
6856 no_save_visual = true;
6858 /* build a list of all tracks, including children */
6861 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
6863 TimeAxisView::Children c = (*i)->get_child_list ();
6864 for (TimeAxisView::Children::iterator j = c.begin(); j != c.end(); ++j) {
6865 all.push_back (j->get());
6869 bool prev_was_selected = false;
6870 bool is_selected = tracks.contains (all.front());
6871 bool next_is_selected;
6873 for (TrackViewList::iterator t = all.begin(); t != all.end(); ++t) {
6875 TrackViewList::iterator next;
6880 if (next != all.end()) {
6881 next_is_selected = tracks.contains (*next);
6883 next_is_selected = false;
6886 if ((*t)->marked_for_display ()) {
6888 (*t)->set_height (h);
6889 first_y_pos = std::min ((*t)->y_position (), first_y_pos);
6891 if (prev_was_selected && next_is_selected) {
6892 hide_track_in_display (*t);
6897 prev_was_selected = is_selected;
6898 is_selected = next_is_selected;
6902 set the controls_layout height now, because waiting for its size
6903 request signal handler will cause the vertical adjustment setting to fail
6906 controls_layout.property_height () = _full_canvas_height;
6907 vertical_adjustment.set_value (first_y_pos);
6909 redo_visual_stack.push_back (current_visual_state (true));
6911 visible_tracks_selector.set_text (_("Sel"));
6915 Editor::save_visual_state (uint32_t n)
6917 while (visual_states.size() <= n) {
6918 visual_states.push_back (0);
6921 if (visual_states[n] != 0) {
6922 delete visual_states[n];
6925 visual_states[n] = current_visual_state (true);
6930 Editor::goto_visual_state (uint32_t n)
6932 if (visual_states.size() <= n) {
6936 if (visual_states[n] == 0) {
6940 use_visual_state (*visual_states[n]);
6944 Editor::start_visual_state_op (uint32_t n)
6946 save_visual_state (n);
6948 PopUp* pup = new PopUp (WIN_POS_MOUSE, 1000, true);
6950 snprintf (buf, sizeof (buf), _("Saved view %u"), n+1);
6951 pup->set_text (buf);
6956 Editor::cancel_visual_state_op (uint32_t n)
6958 goto_visual_state (n);
6962 Editor::toggle_region_mute ()
6964 if (_ignore_region_action) {
6968 RegionSelection rs = get_regions_from_selection_and_entered ();
6974 if (rs.size() > 1) {
6975 begin_reversible_command (_("mute regions"));
6977 begin_reversible_command (_("mute region"));
6980 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
6982 (*i)->region()->playlist()->clear_changes ();
6983 (*i)->region()->set_muted (!(*i)->region()->muted ());
6984 _session->add_command (new StatefulDiffCommand ((*i)->region()->playlist()));
6988 commit_reversible_command ();
6992 Editor::combine_regions ()
6994 /* foreach track with selected regions, take all selected regions
6995 and join them into a new region containing the subregions (as a
6999 typedef set<RouteTimeAxisView*> RTVS;
7002 if (selection->regions.empty()) {
7006 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
7007 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(&(*i)->get_time_axis_view());
7010 tracks.insert (rtv);
7014 begin_reversible_command (_("combine regions"));
7016 vector<RegionView*> new_selection;
7018 for (RTVS::iterator i = tracks.begin(); i != tracks.end(); ++i) {
7021 if ((rv = (*i)->combine_regions ()) != 0) {
7022 new_selection.push_back (rv);
7026 selection->clear_regions ();
7027 for (vector<RegionView*>::iterator i = new_selection.begin(); i != new_selection.end(); ++i) {
7028 selection->add (*i);
7031 commit_reversible_command ();
7035 Editor::uncombine_regions ()
7037 typedef set<RouteTimeAxisView*> RTVS;
7040 if (selection->regions.empty()) {
7044 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
7045 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(&(*i)->get_time_axis_view());
7048 tracks.insert (rtv);
7052 begin_reversible_command (_("uncombine regions"));
7054 for (RTVS::iterator i = tracks.begin(); i != tracks.end(); ++i) {
7055 (*i)->uncombine_regions ();
7058 commit_reversible_command ();
7062 Editor::toggle_midi_input_active (bool flip_others)
7065 boost::shared_ptr<RouteList> rl (new RouteList);
7067 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
7068 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
7074 boost::shared_ptr<MidiTrack> mt = rtav->midi_track();
7077 rl->push_back (rtav->route());
7078 onoff = !mt->input_active();
7082 _session->set_exclusive_input_active (rl, onoff, flip_others);
7089 lock_dialog = new Gtk::Dialog (string_compose (_("%1: Locked"), PROGRAM_NAME), true);
7091 Gtk::Image* padlock = manage (new Gtk::Image (ARDOUR_UI_UTILS::get_icon ("padlock_closed")));
7092 lock_dialog->get_vbox()->pack_start (*padlock);
7094 ArdourButton* b = manage (new ArdourButton);
7095 b->set_name ("lock button");
7096 b->set_text (_("Click to unlock"));
7097 b->signal_clicked.connect (sigc::mem_fun (*this, &Editor::unlock));
7098 lock_dialog->get_vbox()->pack_start (*b);
7100 lock_dialog->get_vbox()->show_all ();
7101 lock_dialog->set_size_request (200, 200);
7105 /* The global menu bar continues to be accessible to applications
7106 with modal dialogs, which means that we need to desensitize
7107 all items in the menu bar. Since those items are really just
7108 proxies for actions, that means disabling all actions.
7110 ActionManager::disable_all_actions ();
7112 lock_dialog->present ();
7118 lock_dialog->hide ();
7121 ActionManager::pop_action_state ();
7124 if (ARDOUR_UI::config()->get_lock_gui_after_seconds()) {
7125 start_lock_event_timing ();
7130 Editor::bring_in_callback (Gtk::Label* label, uint32_t n, uint32_t total, string name)
7132 Gtkmm2ext::UI::instance()->call_slot (invalidator (*this), boost::bind (&Editor::update_bring_in_message, this, label, n, total, name));
7136 Editor::update_bring_in_message (Gtk::Label* label, uint32_t n, uint32_t total, string name)
7138 label->set_text (string_compose ("Copying %1, %2 of %3", name, n, total));
7139 Gtkmm2ext::UI::instance()->flush_pending ();
7143 Editor::bring_all_sources_into_session ()
7150 ArdourDialog w (_("Moving embedded files into session folder"));
7151 w.get_vbox()->pack_start (msg);
7154 /* flush all pending GUI events because we're about to start copying
7158 Gtkmm2ext::UI::instance()->flush_pending ();
7162 _session->bring_all_sources_into_session (boost::bind (&Editor::bring_in_callback, this, &msg, _1, _2, _3));