2 Copyright (C) 2000-2004 Paul Davis
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 /* Note: public Editor methods are documented in public_editor.h */
31 #include <gtkmm/messagedialog.h>
33 #include "pbd/error.h"
34 #include "pbd/basename.h"
35 #include "pbd/pthread_utils.h"
36 #include "pbd/memento_command.h"
37 #include "pbd/unwind.h"
38 #include "pbd/whitespace.h"
39 #include "pbd/stateful_diff_command.h"
41 #include "gtkmm2ext/utils.h"
43 #include "widgets/choice.h"
44 #include "widgets/popup.h"
45 #include "widgets/prompter.h"
47 #include "ardour/audio_track.h"
48 #include "ardour/audioregion.h"
49 #include "ardour/boost_debug.h"
50 #include "ardour/dB.h"
51 #include "ardour/location.h"
52 #include "ardour/midi_region.h"
53 #include "ardour/midi_track.h"
54 #include "ardour/operations.h"
55 #include "ardour/playlist_factory.h"
56 #include "ardour/profile.h"
57 #include "ardour/quantize.h"
58 #include "ardour/legatize.h"
59 #include "ardour/region_factory.h"
60 #include "ardour/reverse.h"
61 #include "ardour/session.h"
62 #include "ardour/session_playlists.h"
63 #include "ardour/strip_silence.h"
64 #include "ardour/transient_detector.h"
65 #include "ardour/transpose.h"
67 #include "canvas/canvas.h"
70 #include "audio_region_view.h"
71 #include "audio_streamview.h"
72 #include "audio_time_axis.h"
73 #include "automation_region_view.h"
74 #include "automation_time_axis.h"
75 #include "control_point.h"
79 #include "editor_cursors.h"
80 #include "editor_drag.h"
81 #include "editor_regions.h"
82 #include "editor_routes.h"
83 #include "gui_thread.h"
84 #include "insert_remove_time_dialog.h"
85 #include "interthread_progress_window.h"
86 #include "item_counts.h"
88 #include "midi_region_view.h"
90 #include "mixer_strip.h"
91 #include "mouse_cursors.h"
92 #include "normalize_dialog.h"
94 #include "paste_context.h"
95 #include "patch_change_dialog.h"
96 #include "quantize_dialog.h"
97 #include "region_gain_line.h"
98 #include "rgb_macros.h"
99 #include "route_time_axis.h"
100 #include "selection.h"
101 #include "selection_templates.h"
102 #include "streamview.h"
103 #include "strip_silence_dialog.h"
104 #include "time_axis_view.h"
106 #include "transpose_dialog.h"
107 #include "transform_dialog.h"
108 #include "ui_config.h"
110 #include "pbd/i18n.h"
113 using namespace ARDOUR;
116 using namespace Gtkmm2ext;
117 using namespace ArdourWidgets;
118 using namespace Editing;
119 using Gtkmm2ext::Keyboard;
121 /***********************************************************************
123 ***********************************************************************/
126 Editor::undo (uint32_t n)
128 if (_session && _session->actively_recording()) {
129 /* no undo allowed while recording. Session will check also,
130 but we don't even want to get to that.
135 if (_drags->active ()) {
141 if (_session->undo_depth() == 0) {
142 undo_action->set_sensitive(false);
144 redo_action->set_sensitive(true);
145 begin_selection_op_history ();
150 Editor::redo (uint32_t n)
152 if (_session && _session->actively_recording()) {
153 /* no redo allowed while recording. Session will check also,
154 but we don't even want to get to that.
159 if (_drags->active ()) {
165 if (_session->redo_depth() == 0) {
166 redo_action->set_sensitive(false);
168 undo_action->set_sensitive(true);
169 begin_selection_op_history ();
174 Editor::split_regions_at (MusicFrame where, RegionSelection& regions, bool snap_frame)
178 RegionSelection pre_selected_regions = selection->regions;
179 bool working_on_selection = !pre_selected_regions.empty();
181 list<boost::shared_ptr<Playlist> > used_playlists;
182 list<RouteTimeAxisView*> used_trackviews;
184 if (regions.empty()) {
188 begin_reversible_command (_("split"));
190 // if splitting a single region, and snap-to is using
191 // region boundaries, don't pay attention to them
193 if (regions.size() == 1) {
194 switch (_snap_type) {
195 case SnapToRegionStart:
196 case SnapToRegionSync:
197 case SnapToRegionEnd:
210 EditorFreeze(); /* Emit Signal */
213 for (RegionSelection::iterator a = regions.begin(); a != regions.end(); ) {
215 RegionSelection::iterator tmp;
217 /* XXX this test needs to be more complicated, to make sure we really
218 have something to split.
221 if (!(*a)->region()->covers (where.frame)) {
229 boost::shared_ptr<Playlist> pl = (*a)->region()->playlist();
237 /* we haven't seen this playlist before */
239 /* remember used playlists so we can thaw them later */
240 used_playlists.push_back(pl);
242 TimeAxisView& tv = (*a)->get_time_axis_view();
243 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (&tv);
245 used_trackviews.push_back (rtv);
252 pl->clear_changes ();
253 pl->split_region ((*a)->region(), where);
254 _session->add_command (new StatefulDiffCommand (pl));
260 latest_regionviews.clear ();
262 vector<sigc::connection> region_added_connections;
264 for (list<RouteTimeAxisView*>::iterator i = used_trackviews.begin(); i != used_trackviews.end(); ++i) {
265 region_added_connections.push_back ((*i)->view()->RegionViewAdded.connect (sigc::mem_fun(*this, &Editor::collect_new_region_view)));
268 while (used_playlists.size() > 0) {
269 list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
271 used_playlists.pop_front();
274 for (vector<sigc::connection>::iterator c = region_added_connections.begin(); c != region_added_connections.end(); ++c) {
279 EditorThaw(); /* Emit Signal */
282 if (working_on_selection) {
283 // IFF we were working on selected regions, try to reinstate the other region selections that existed before the freeze/thaw.
285 RegionSelectionAfterSplit rsas = Config->get_region_selection_after_split();
286 /* There are three classes of regions that we might want selected after
287 splitting selected regions:
288 - regions selected before the split operation, and unaffected by it
289 - newly-created regions before the split
290 - newly-created regions after the split
293 if (rsas & Existing) {
294 // region selections that existed before the split.
295 selection->add ( pre_selected_regions );
298 for (RegionSelection::iterator ri = latest_regionviews.begin(); ri != latest_regionviews.end(); ri++) {
299 if ((*ri)->region()->position() < where.frame) {
300 // new regions created before the split
301 if (rsas & NewlyCreatedLeft) {
302 selection->add (*ri);
305 // new regions created after the split
306 if (rsas & NewlyCreatedRight) {
307 selection->add (*ri);
312 if( working_on_selection ) {
313 selection->add (latest_regionviews); //these are the new regions created after the split
317 commit_reversible_command ();
320 /** Move one extreme of the current range selection. If more than one range is selected,
321 * the start of the earliest range or the end of the latest range is moved.
323 * @param move_end true to move the end of the current range selection, false to move
325 * @param next true to move the extreme to the next region boundary, false to move to
329 Editor::move_range_selection_start_or_end_to_region_boundary (bool move_end, bool next)
331 if (selection->time.start() == selection->time.end_frame()) {
335 framepos_t start = selection->time.start ();
336 framepos_t end = selection->time.end_frame ();
338 /* the position of the thing we may move */
339 framepos_t pos = move_end ? end : start;
340 int dir = next ? 1 : -1;
342 /* so we don't find the current region again */
343 if (dir > 0 || pos > 0) {
347 framepos_t const target = get_region_boundary (pos, dir, true, false);
362 begin_reversible_selection_op (_("alter selection"));
363 selection->set_preserving_all_ranges (start, end);
364 commit_reversible_selection_op ();
368 Editor::nudge_forward_release (GdkEventButton* ev)
370 if (ev->state & Keyboard::PrimaryModifier) {
371 nudge_forward (false, true);
373 nudge_forward (false, false);
379 Editor::nudge_backward_release (GdkEventButton* ev)
381 if (ev->state & Keyboard::PrimaryModifier) {
382 nudge_backward (false, true);
384 nudge_backward (false, false);
391 Editor::nudge_forward (bool next, bool force_playhead)
394 framepos_t next_distance;
400 RegionSelection rs = get_regions_from_selection_and_entered ();
402 if (!force_playhead && !rs.empty()) {
404 begin_reversible_command (_("nudge regions forward"));
406 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
407 boost::shared_ptr<Region> r ((*i)->region());
409 distance = get_nudge_distance (r->position(), next_distance);
412 distance = next_distance;
416 r->set_position (r->position() + distance);
417 _session->add_command (new StatefulDiffCommand (r));
420 commit_reversible_command ();
423 } else if (!force_playhead && !selection->markers.empty()) {
426 bool in_command = false;
427 const int32_t divisions = get_grid_music_divisions (0);
429 for (MarkerSelection::iterator i = selection->markers.begin(); i != selection->markers.end(); ++i) {
431 Location* loc = find_location_from_marker ((*i), is_start);
435 XMLNode& before (loc->get_state());
438 distance = get_nudge_distance (loc->start(), next_distance);
440 distance = next_distance;
442 if (max_framepos - distance > loc->start() + loc->length()) {
443 loc->set_start (loc->start() + distance, false, true, divisions);
445 loc->set_start (max_framepos - loc->length(), false, true, divisions);
448 distance = get_nudge_distance (loc->end(), next_distance);
450 distance = next_distance;
452 if (max_framepos - distance > loc->end()) {
453 loc->set_end (loc->end() + distance, false, true, divisions);
455 loc->set_end (max_framepos, false, true, divisions);
457 if (loc->is_session_range()) {
458 _session->set_end_is_free (false);
462 begin_reversible_command (_("nudge location forward"));
465 XMLNode& after (loc->get_state());
466 _session->add_command (new MementoCommand<Location>(*loc, &before, &after));
471 commit_reversible_command ();
474 distance = get_nudge_distance (playhead_cursor->current_frame (), next_distance);
475 _session->request_locate (playhead_cursor->current_frame () + distance);
480 Editor::nudge_backward (bool next, bool force_playhead)
483 framepos_t next_distance;
489 RegionSelection rs = get_regions_from_selection_and_entered ();
491 if (!force_playhead && !rs.empty()) {
493 begin_reversible_command (_("nudge regions backward"));
495 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
496 boost::shared_ptr<Region> r ((*i)->region());
498 distance = get_nudge_distance (r->position(), next_distance);
501 distance = next_distance;
506 if (r->position() > distance) {
507 r->set_position (r->position() - distance);
511 _session->add_command (new StatefulDiffCommand (r));
514 commit_reversible_command ();
516 } else if (!force_playhead && !selection->markers.empty()) {
519 bool in_command = false;
521 for (MarkerSelection::iterator i = selection->markers.begin(); i != selection->markers.end(); ++i) {
523 Location* loc = find_location_from_marker ((*i), is_start);
527 XMLNode& before (loc->get_state());
530 distance = get_nudge_distance (loc->start(), next_distance);
532 distance = next_distance;
534 if (distance < loc->start()) {
535 loc->set_start (loc->start() - distance, false, true, get_grid_music_divisions(0));
537 loc->set_start (0, false, true, get_grid_music_divisions(0));
540 distance = get_nudge_distance (loc->end(), next_distance);
543 distance = next_distance;
546 if (distance < loc->end() - loc->length()) {
547 loc->set_end (loc->end() - distance, false, true, get_grid_music_divisions(0));
549 loc->set_end (loc->length(), false, true, get_grid_music_divisions(0));
551 if (loc->is_session_range()) {
552 _session->set_end_is_free (false);
556 begin_reversible_command (_("nudge location forward"));
559 XMLNode& after (loc->get_state());
560 _session->add_command (new MementoCommand<Location>(*loc, &before, &after));
564 commit_reversible_command ();
569 distance = get_nudge_distance (playhead_cursor->current_frame (), next_distance);
571 if (playhead_cursor->current_frame () > distance) {
572 _session->request_locate (playhead_cursor->current_frame () - distance);
574 _session->goto_start();
580 Editor::nudge_forward_capture_offset ()
582 RegionSelection rs = get_regions_from_selection_and_entered ();
584 if (!_session || rs.empty()) {
588 begin_reversible_command (_("nudge forward"));
590 framepos_t const distance = _session->worst_output_latency();
592 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
593 boost::shared_ptr<Region> r ((*i)->region());
596 r->set_position (r->position() + distance);
597 _session->add_command(new StatefulDiffCommand (r));
600 commit_reversible_command ();
604 Editor::nudge_backward_capture_offset ()
606 RegionSelection rs = get_regions_from_selection_and_entered ();
608 if (!_session || rs.empty()) {
612 begin_reversible_command (_("nudge backward"));
614 framepos_t const distance = _session->worst_output_latency();
616 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
617 boost::shared_ptr<Region> r ((*i)->region());
621 if (r->position() > distance) {
622 r->set_position (r->position() - distance);
626 _session->add_command(new StatefulDiffCommand (r));
629 commit_reversible_command ();
632 struct RegionSelectionPositionSorter {
633 bool operator() (RegionView* a, RegionView* b) {
634 return a->region()->position() < b->region()->position();
639 Editor::sequence_regions ()
642 framepos_t r_end_prev;
650 RegionSelection rs = get_regions_from_selection_and_entered ();
651 rs.sort(RegionSelectionPositionSorter());
655 bool in_command = false;
657 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
658 boost::shared_ptr<Region> r ((*i)->region());
666 if(r->position_locked())
673 r->set_position(r_end_prev);
677 begin_reversible_command (_("sequence regions"));
680 _session->add_command (new StatefulDiffCommand (r));
682 r_end=r->position() + r->length();
688 commit_reversible_command ();
697 Editor::move_to_start ()
699 _session->goto_start ();
703 Editor::move_to_end ()
706 _session->request_locate (_session->current_end_frame());
710 Editor::build_region_boundary_cache ()
713 vector<RegionPoint> interesting_points;
714 boost::shared_ptr<Region> r;
715 TrackViewList tracks;
718 region_boundary_cache.clear ();
724 switch (_snap_type) {
725 case SnapToRegionStart:
726 interesting_points.push_back (Start);
728 case SnapToRegionEnd:
729 interesting_points.push_back (End);
731 case SnapToRegionSync:
732 interesting_points.push_back (SyncPoint);
734 case SnapToRegionBoundary:
735 interesting_points.push_back (Start);
736 interesting_points.push_back (End);
739 fatal << string_compose (_("build_region_boundary_cache called with snap_type = %1"), _snap_type) << endmsg;
740 abort(); /*NOTREACHED*/
744 TimeAxisView *ontrack = 0;
747 if (!selection->tracks.empty()) {
748 tlist = selection->tracks.filter_to_unique_playlists ();
750 tlist = track_views.filter_to_unique_playlists ();
753 while (pos < _session->current_end_frame() && !at_end) {
756 framepos_t lpos = max_framepos;
758 for (vector<RegionPoint>::iterator p = interesting_points.begin(); p != interesting_points.end(); ++p) {
760 if ((r = find_next_region (pos, *p, 1, tlist, &ontrack)) == 0) {
761 if (*p == interesting_points.back()) {
764 /* move to next point type */
770 rpos = r->first_frame();
774 rpos = r->last_frame();
778 rpos = r->sync_position ();
786 RouteTimeAxisView *rtav;
788 if (ontrack != 0 && (rtav = dynamic_cast<RouteTimeAxisView*>(ontrack)) != 0 ) {
789 if (rtav->track() != 0) {
790 speed = rtav->track()->speed();
794 rpos = track_frame_to_session_frame (rpos, speed);
800 /* prevent duplicates, but we don't use set<> because we want to be able
804 vector<framepos_t>::iterator ri;
806 for (ri = region_boundary_cache.begin(); ri != region_boundary_cache.end(); ++ri) {
812 if (ri == region_boundary_cache.end()) {
813 region_boundary_cache.push_back (rpos);
820 /* finally sort to be sure that the order is correct */
822 sort (region_boundary_cache.begin(), region_boundary_cache.end());
825 boost::shared_ptr<Region>
826 Editor::find_next_region (framepos_t frame, RegionPoint point, int32_t dir, TrackViewList& tracks, TimeAxisView **ontrack)
828 TrackViewList::iterator i;
829 framepos_t closest = max_framepos;
830 boost::shared_ptr<Region> ret;
834 framepos_t track_frame;
835 RouteTimeAxisView *rtav;
837 for (i = tracks.begin(); i != tracks.end(); ++i) {
840 boost::shared_ptr<Region> r;
843 if ( (rtav = dynamic_cast<RouteTimeAxisView*>(*i)) != 0 ) {
844 if (rtav->track()!=0)
845 track_speed = rtav->track()->speed();
848 track_frame = session_frame_to_track_frame(frame, track_speed);
850 if ((r = (*i)->find_next_region (track_frame, point, dir)) == 0) {
856 rpos = r->first_frame ();
860 rpos = r->last_frame ();
864 rpos = r->sync_position ();
868 // rpos is a "track frame", converting it to "_session frame"
869 rpos = track_frame_to_session_frame(rpos, track_speed);
872 distance = rpos - frame;
874 distance = frame - rpos;
877 if (distance < closest) {
889 Editor::find_next_region_boundary (framepos_t pos, int32_t dir, const TrackViewList& tracks)
891 framecnt_t distance = max_framepos;
892 framepos_t current_nearest = -1;
894 for (TrackViewList::const_iterator i = tracks.begin(); i != tracks.end(); ++i) {
895 framepos_t contender;
898 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*i);
904 if ((contender = rtv->find_next_region_boundary (pos, dir)) < 0) {
908 d = ::llabs (pos - contender);
911 current_nearest = contender;
916 return current_nearest;
920 Editor::get_region_boundary (framepos_t pos, int32_t dir, bool with_selection, bool only_onscreen)
925 if (with_selection && Config->get_region_boundaries_from_selected_tracks()) {
927 if (!selection->tracks.empty()) {
929 target = find_next_region_boundary (pos, dir, selection->tracks);
933 if (only_onscreen || Config->get_region_boundaries_from_onscreen_tracks()) {
934 get_onscreen_tracks (tvl);
935 target = find_next_region_boundary (pos, dir, tvl);
937 target = find_next_region_boundary (pos, dir, track_views);
943 if (only_onscreen || Config->get_region_boundaries_from_onscreen_tracks()) {
944 get_onscreen_tracks (tvl);
945 target = find_next_region_boundary (pos, dir, tvl);
947 target = find_next_region_boundary (pos, dir, track_views);
955 Editor::cursor_to_region_boundary (bool with_selection, int32_t dir)
957 framepos_t pos = playhead_cursor->current_frame ();
964 // so we don't find the current region again..
965 if (dir > 0 || pos > 0) {
969 if ((target = get_region_boundary (pos, dir, with_selection, false)) < 0) {
973 _session->request_locate (target);
977 Editor::cursor_to_next_region_boundary (bool with_selection)
979 cursor_to_region_boundary (with_selection, 1);
983 Editor::cursor_to_previous_region_boundary (bool with_selection)
985 cursor_to_region_boundary (with_selection, -1);
989 Editor::cursor_to_region_point (EditorCursor* cursor, RegionPoint point, int32_t dir)
991 boost::shared_ptr<Region> r;
992 framepos_t pos = cursor->current_frame ();
998 TimeAxisView *ontrack = 0;
1000 // so we don't find the current region again..
1004 if (!selection->tracks.empty()) {
1006 r = find_next_region (pos, point, dir, selection->tracks, &ontrack);
1008 } else if (clicked_axisview) {
1011 t.push_back (clicked_axisview);
1013 r = find_next_region (pos, point, dir, t, &ontrack);
1017 r = find_next_region (pos, point, dir, track_views, &ontrack);
1026 pos = r->first_frame ();
1030 pos = r->last_frame ();
1034 pos = r->sync_position ();
1039 RouteTimeAxisView *rtav;
1041 if ( ontrack != 0 && (rtav = dynamic_cast<RouteTimeAxisView*>(ontrack)) != 0 ) {
1042 if (rtav->track() != 0) {
1043 speed = rtav->track()->speed();
1047 pos = track_frame_to_session_frame(pos, speed);
1049 if (cursor == playhead_cursor) {
1050 _session->request_locate (pos);
1052 cursor->set_position (pos);
1057 Editor::cursor_to_next_region_point (EditorCursor* cursor, RegionPoint point)
1059 cursor_to_region_point (cursor, point, 1);
1063 Editor::cursor_to_previous_region_point (EditorCursor* cursor, RegionPoint point)
1065 cursor_to_region_point (cursor, point, -1);
1069 Editor::cursor_to_selection_start (EditorCursor *cursor)
1073 switch (mouse_mode) {
1075 if (!selection->regions.empty()) {
1076 pos = selection->regions.start();
1081 if (!selection->time.empty()) {
1082 pos = selection->time.start ();
1090 if (cursor == playhead_cursor) {
1091 _session->request_locate (pos);
1093 cursor->set_position (pos);
1098 Editor::cursor_to_selection_end (EditorCursor *cursor)
1102 switch (mouse_mode) {
1104 if (!selection->regions.empty()) {
1105 pos = selection->regions.end_frame();
1110 if (!selection->time.empty()) {
1111 pos = selection->time.end_frame ();
1119 if (cursor == playhead_cursor) {
1120 _session->request_locate (pos);
1122 cursor->set_position (pos);
1127 Editor::selected_marker_to_region_boundary (bool with_selection, int32_t dir)
1137 if (selection->markers.empty()) {
1141 if (!mouse_frame (mouse, ignored)) {
1145 add_location_mark (mouse);
1148 if ((loc = find_location_from_marker (selection->markers.front(), ignored)) == 0) {
1152 framepos_t pos = loc->start();
1154 // so we don't find the current region again..
1155 if (dir > 0 || pos > 0) {
1159 if ((target = get_region_boundary (pos, dir, with_selection, false)) < 0) {
1163 loc->move_to (target, 0);
1167 Editor::selected_marker_to_next_region_boundary (bool with_selection)
1169 selected_marker_to_region_boundary (with_selection, 1);
1173 Editor::selected_marker_to_previous_region_boundary (bool with_selection)
1175 selected_marker_to_region_boundary (with_selection, -1);
1179 Editor::selected_marker_to_region_point (RegionPoint point, int32_t dir)
1181 boost::shared_ptr<Region> r;
1186 if (!_session || selection->markers.empty()) {
1190 if ((loc = find_location_from_marker (selection->markers.front(), ignored)) == 0) {
1194 TimeAxisView *ontrack = 0;
1198 // so we don't find the current region again..
1202 if (!selection->tracks.empty()) {
1204 r = find_next_region (pos, point, dir, selection->tracks, &ontrack);
1208 r = find_next_region (pos, point, dir, track_views, &ontrack);
1217 pos = r->first_frame ();
1221 pos = r->last_frame ();
1225 pos = r->adjust_to_sync (r->first_frame());
1230 RouteTimeAxisView *rtav;
1232 if (ontrack != 0 && (rtav = dynamic_cast<RouteTimeAxisView*>(ontrack)) != 0) {
1233 if (rtav->track() != 0) {
1234 speed = rtav->track()->speed();
1238 pos = track_frame_to_session_frame(pos, speed);
1240 loc->move_to (pos, 0);
1244 Editor::selected_marker_to_next_region_point (RegionPoint point)
1246 selected_marker_to_region_point (point, 1);
1250 Editor::selected_marker_to_previous_region_point (RegionPoint point)
1252 selected_marker_to_region_point (point, -1);
1256 Editor::selected_marker_to_selection_start ()
1262 if (!_session || selection->markers.empty()) {
1266 if ((loc = find_location_from_marker (selection->markers.front(), ignored)) == 0) {
1270 switch (mouse_mode) {
1272 if (!selection->regions.empty()) {
1273 pos = selection->regions.start();
1278 if (!selection->time.empty()) {
1279 pos = selection->time.start ();
1287 loc->move_to (pos, 0);
1291 Editor::selected_marker_to_selection_end ()
1297 if (!_session || selection->markers.empty()) {
1301 if ((loc = find_location_from_marker (selection->markers.front(), ignored)) == 0) {
1305 switch (mouse_mode) {
1307 if (!selection->regions.empty()) {
1308 pos = selection->regions.end_frame();
1313 if (!selection->time.empty()) {
1314 pos = selection->time.end_frame ();
1322 loc->move_to (pos, 0);
1326 Editor::scroll_playhead (bool forward)
1328 framepos_t pos = playhead_cursor->current_frame ();
1329 framecnt_t delta = (framecnt_t) floor (current_page_samples() / 0.8);
1332 if (pos == max_framepos) {
1336 if (pos < max_framepos - delta) {
1355 _session->request_locate (pos);
1359 Editor::cursor_align (bool playhead_to_edit)
1365 if (playhead_to_edit) {
1367 if (selection->markers.empty()) {
1371 _session->request_locate (selection->markers.front()->position(), _session->transport_rolling());
1374 const int32_t divisions = get_grid_music_divisions (0);
1375 /* move selected markers to playhead */
1377 for (MarkerSelection::iterator i = selection->markers.begin(); i != selection->markers.end(); ++i) {
1380 Location* loc = find_location_from_marker (*i, ignored);
1382 if (loc->is_mark()) {
1383 loc->set_start (playhead_cursor->current_frame (), false, true, divisions);
1385 loc->set (playhead_cursor->current_frame (),
1386 playhead_cursor->current_frame () + loc->length(), true, divisions);
1393 Editor::scroll_backward (float pages)
1395 framepos_t const one_page = (framepos_t) rint (_visible_canvas_width * samples_per_pixel);
1396 framepos_t const cnt = (framepos_t) floor (pages * one_page);
1399 if (leftmost_frame < cnt) {
1402 frame = leftmost_frame - cnt;
1405 reset_x_origin (frame);
1409 Editor::scroll_forward (float pages)
1411 framepos_t const one_page = (framepos_t) rint (_visible_canvas_width * samples_per_pixel);
1412 framepos_t const cnt = (framepos_t) floor (pages * one_page);
1415 if (max_framepos - cnt < leftmost_frame) {
1416 frame = max_framepos - cnt;
1418 frame = leftmost_frame + cnt;
1421 reset_x_origin (frame);
1425 Editor::scroll_tracks_down ()
1427 double vert_value = vertical_adjustment.get_value() + vertical_adjustment.get_page_size();
1428 if (vert_value > vertical_adjustment.get_upper() - _visible_canvas_height) {
1429 vert_value = vertical_adjustment.get_upper() - _visible_canvas_height;
1432 vertical_adjustment.set_value (vert_value);
1436 Editor::scroll_tracks_up ()
1438 vertical_adjustment.set_value (vertical_adjustment.get_value() - vertical_adjustment.get_page_size());
1442 Editor::scroll_tracks_down_line ()
1444 double vert_value = vertical_adjustment.get_value() + 60;
1446 if (vert_value > vertical_adjustment.get_upper() - _visible_canvas_height) {
1447 vert_value = vertical_adjustment.get_upper() - _visible_canvas_height;
1450 vertical_adjustment.set_value (vert_value);
1454 Editor::scroll_tracks_up_line ()
1456 reset_y_origin (vertical_adjustment.get_value() - 60);
1460 Editor::select_topmost_track ()
1462 const double top_of_trackviews = vertical_adjustment.get_value();
1463 for (TrackViewList::iterator t = track_views.begin(); t != track_views.end(); ++t) {
1464 if ((*t)->hidden()) {
1467 std::pair<TimeAxisView*,double> res = (*t)->covers_y_position (top_of_trackviews);
1469 selection->set (*t);
1476 Editor::scroll_down_one_track (bool skip_child_views)
1478 TrackViewList::reverse_iterator next = track_views.rend();
1479 const double top_of_trackviews = vertical_adjustment.get_value();
1481 for (TrackViewList::reverse_iterator t = track_views.rbegin(); t != track_views.rend(); ++t) {
1482 if ((*t)->hidden()) {
1486 /* If this is the upper-most visible trackview, we want to display
1487 * the one above it (next)
1489 * Note that covers_y_position() is recursive and includes child views
1491 std::pair<TimeAxisView*,double> res = (*t)->covers_y_position (top_of_trackviews);
1494 if (skip_child_views) {
1497 /* automation lane (one level, non-recursive)
1499 * - if no automation lane exists -> move to next tack
1500 * - if the first (here: bottom-most) matches -> move to next tack
1501 * - if no y-axis match is found -> the current track is at the top
1502 * -> move to last (here: top-most) automation lane
1504 TimeAxisView::Children kids = (*t)->get_child_list();
1505 TimeAxisView::Children::reverse_iterator nkid = kids.rend();
1507 for (TimeAxisView::Children::reverse_iterator ci = kids.rbegin(); ci != kids.rend(); ++ci) {
1508 if ((*ci)->hidden()) {
1512 std::pair<TimeAxisView*,double> dev;
1513 dev = (*ci)->covers_y_position (top_of_trackviews);
1515 /* some automation lane is currently at the top */
1516 if (ci == kids.rbegin()) {
1517 /* first (bottom-most) autmation lane is at the top.
1518 * -> move to next track
1527 if (nkid != kids.rend()) {
1528 ensure_time_axis_view_is_visible (**nkid, true);
1536 /* move to the track below the first one that covers the */
1538 if (next != track_views.rend()) {
1539 ensure_time_axis_view_is_visible (**next, true);
1547 Editor::scroll_up_one_track (bool skip_child_views)
1549 TrackViewList::iterator prev = track_views.end();
1550 double top_of_trackviews = vertical_adjustment.get_value ();
1552 for (TrackViewList::iterator t = track_views.begin(); t != track_views.end(); ++t) {
1554 if ((*t)->hidden()) {
1558 /* find the trackview at the top of the trackview group
1560 * Note that covers_y_position() is recursive and includes child views
1562 std::pair<TimeAxisView*,double> res = (*t)->covers_y_position (top_of_trackviews);
1565 if (skip_child_views) {
1568 /* automation lane (one level, non-recursive)
1570 * - if no automation lane exists -> move to prev tack
1571 * - if no y-axis match is found -> the current track is at the top -> move to prev track
1572 * (actually last automation lane of previous track, see below)
1573 * - if first (top-most) lane is at the top -> move to this track
1574 * - else move up one lane
1576 TimeAxisView::Children kids = (*t)->get_child_list();
1577 TimeAxisView::Children::iterator pkid = kids.end();
1579 for (TimeAxisView::Children::iterator ci = kids.begin(); ci != kids.end(); ++ci) {
1580 if ((*ci)->hidden()) {
1584 std::pair<TimeAxisView*,double> dev;
1585 dev = (*ci)->covers_y_position (top_of_trackviews);
1587 /* some automation lane is currently at the top */
1588 if (ci == kids.begin()) {
1589 /* first (top-most) autmation lane is at the top.
1590 * jump directly to this track's top
1592 ensure_time_axis_view_is_visible (**t, true);
1595 else if (pkid != kids.end()) {
1596 /* some other automation lane is at the top.
1597 * move up to prev automation lane.
1599 ensure_time_axis_view_is_visible (**pkid, true);
1602 assert(0); // not reached
1613 if (prev != track_views.end()) {
1614 // move to bottom-most automation-lane of the previous track
1615 TimeAxisView::Children kids = (*prev)->get_child_list();
1616 TimeAxisView::Children::reverse_iterator pkid = kids.rend();
1617 if (!skip_child_views) {
1618 // find the last visible lane
1619 for (TimeAxisView::Children::reverse_iterator ci = kids.rbegin(); ci != kids.rend(); ++ci) {
1620 if (!(*ci)->hidden()) {
1626 if (pkid != kids.rend()) {
1627 ensure_time_axis_view_is_visible (**pkid, true);
1629 ensure_time_axis_view_is_visible (**prev, true);
1638 Editor::scroll_left_step ()
1640 framepos_t xdelta = (current_page_samples() / 8);
1642 if (leftmost_frame > xdelta) {
1643 reset_x_origin (leftmost_frame - xdelta);
1651 Editor::scroll_right_step ()
1653 framepos_t xdelta = (current_page_samples() / 8);
1655 if (max_framepos - xdelta > leftmost_frame) {
1656 reset_x_origin (leftmost_frame + xdelta);
1658 reset_x_origin (max_framepos - current_page_samples());
1663 Editor::scroll_left_half_page ()
1665 framepos_t xdelta = (current_page_samples() / 2);
1666 if (leftmost_frame > xdelta) {
1667 reset_x_origin (leftmost_frame - xdelta);
1674 Editor::scroll_right_half_page ()
1676 framepos_t xdelta = (current_page_samples() / 2);
1677 if (max_framepos - xdelta > leftmost_frame) {
1678 reset_x_origin (leftmost_frame + xdelta);
1680 reset_x_origin (max_framepos - current_page_samples());
1687 Editor::tav_zoom_step (bool coarser)
1689 DisplaySuspender ds;
1693 if (selection->tracks.empty()) {
1696 ts = &selection->tracks;
1699 for (TrackViewList::iterator i = ts->begin(); i != ts->end(); ++i) {
1700 TimeAxisView *tv = (static_cast<TimeAxisView*>(*i));
1701 tv->step_height (coarser);
1706 Editor::tav_zoom_smooth (bool coarser, bool force_all)
1708 DisplaySuspender ds;
1712 if (selection->tracks.empty() || force_all) {
1715 ts = &selection->tracks;
1718 for (TrackViewList::iterator i = ts->begin(); i != ts->end(); ++i) {
1719 TimeAxisView *tv = (static_cast<TimeAxisView*>(*i));
1720 uint32_t h = tv->current_height ();
1725 if (h >= TimeAxisView::preset_height (HeightSmall)) {
1730 tv->set_height (h + 5);
1736 Editor::temporal_zoom_step_mouse_focus_scale (bool zoom_out, double scale)
1738 Editing::ZoomFocus temp_focus = zoom_focus;
1739 zoom_focus = Editing::ZoomFocusMouse;
1740 temporal_zoom_step_scale (zoom_out, scale);
1741 zoom_focus = temp_focus;
1745 Editor::temporal_zoom_step_mouse_focus (bool zoom_out)
1747 temporal_zoom_step_mouse_focus_scale (zoom_out, 2.0);
1751 Editor::temporal_zoom_step (bool zoom_out)
1753 temporal_zoom_step_scale (zoom_out, 2.0);
1757 Editor::temporal_zoom_step_scale (bool zoom_out, double scale)
1759 ENSURE_GUI_THREAD (*this, &Editor::temporal_zoom_step, zoom_out, scale)
1761 framecnt_t nspp = samples_per_pixel;
1765 if (nspp == samples_per_pixel) {
1770 if (nspp == samples_per_pixel) {
1775 // ToDo: encapsulate all of this into something like editor::get_session_extents() or editor::leftmost(), rightmost()
1777 //ToDo: also incorporate automation regions (in case the session has no audio/midi but is just used for automating plugins or the like)
1779 //calculate the extents of all regions in every playlist
1780 framecnt_t session_extent_start = 0;
1781 framecnt_t session_extent_end = 0;
1783 boost::shared_ptr<RouteList> rl = _session->get_routes();
1784 for (RouteList::iterator r = rl->begin(); r != rl->end(); ++r) {
1785 boost::shared_ptr<Track> tr = boost::dynamic_pointer_cast<Track> (*r);
1787 boost::shared_ptr<Playlist> pl = tr->playlist();
1789 pair<framepos_t, framepos_t> e;
1790 e = pl->get_extent();
1791 if (e.first < session_extent_start) {
1792 session_extent_start = e.first;
1794 if (e.second > session_extent_end) {
1795 session_extent_end = e.second;
1801 framecnt_t session_extents = session_extent_end - session_extent_start;
1803 //in a session with no regions, use the start/end markers to set max zoom
1804 framecnt_t const session_length = _session->current_end_frame() - _session->current_start_frame ();
1805 if ( session_length > session_extents )
1806 session_extents = session_length;
1808 //in a session with no regions or start/end markers, use 2 minutes to set max zoom
1809 framecnt_t const min_length = _session->nominal_frame_rate()*60*2;
1810 if ( min_length > session_extents )
1811 session_extents = min_length;
1813 //convert to samples-per-pixel and limit our zoom to this value
1814 framecnt_t session_extents_pp = session_extents / _visible_canvas_width;
1815 if (nspp > session_extents_pp)
1816 nspp = session_extents_pp;
1819 temporal_zoom (nspp);
1823 Editor::temporal_zoom (framecnt_t fpp)
1829 framepos_t current_page = current_page_samples();
1830 framepos_t current_leftmost = leftmost_frame;
1831 framepos_t current_rightmost;
1832 framepos_t current_center;
1833 framepos_t new_page_size;
1834 framepos_t half_page_size;
1835 framepos_t leftmost_after_zoom = 0;
1837 bool in_track_canvas;
1838 bool use_mouse_frame = true;
1842 if (fpp == samples_per_pixel) {
1846 // Imposing an arbitrary limit to zoom out as too much zoom out produces
1847 // segfaults for lack of memory. If somebody decides this is not high enough I
1848 // believe it can be raisen to higher values but some limit must be in place.
1850 // This constant represents 1 day @ 48kHz on a 1600 pixel wide display
1851 // all of which is used for the editor track displays. The whole day
1852 // would be 4147200000 samples, so 2592000 samples per pixel.
1854 nfpp = min (fpp, (framecnt_t) 2592000);
1855 nfpp = max ((framecnt_t) 1, nfpp);
1857 new_page_size = (framepos_t) floor (_visible_canvas_width * nfpp);
1858 half_page_size = new_page_size / 2;
1860 switch (zoom_focus) {
1862 leftmost_after_zoom = current_leftmost;
1865 case ZoomFocusRight:
1866 current_rightmost = leftmost_frame + current_page;
1867 if (current_rightmost < new_page_size) {
1868 leftmost_after_zoom = 0;
1870 leftmost_after_zoom = current_rightmost - new_page_size;
1874 case ZoomFocusCenter:
1875 current_center = current_leftmost + (current_page/2);
1876 if (current_center < half_page_size) {
1877 leftmost_after_zoom = 0;
1879 leftmost_after_zoom = current_center - half_page_size;
1883 case ZoomFocusPlayhead:
1884 /* centre playhead */
1885 l = playhead_cursor->current_frame () - (new_page_size * 0.5);
1888 leftmost_after_zoom = 0;
1889 } else if (l > max_framepos) {
1890 leftmost_after_zoom = max_framepos - new_page_size;
1892 leftmost_after_zoom = (framepos_t) l;
1896 case ZoomFocusMouse:
1897 /* try to keep the mouse over the same point in the display */
1899 if (_drags->active()) {
1900 where = _drags->current_pointer_frame ();
1901 } else if (!mouse_frame (where, in_track_canvas)) {
1902 use_mouse_frame = false;
1905 if (use_mouse_frame) {
1906 l = - ((new_page_size * ((where - current_leftmost)/(double)current_page)) - where);
1909 leftmost_after_zoom = 0;
1910 } else if (l > max_framepos) {
1911 leftmost_after_zoom = max_framepos - new_page_size;
1913 leftmost_after_zoom = (framepos_t) l;
1916 /* use playhead instead */
1917 where = playhead_cursor->current_frame ();
1919 if (where < half_page_size) {
1920 leftmost_after_zoom = 0;
1922 leftmost_after_zoom = where - half_page_size;
1928 /* try to keep the edit point in the same place */
1929 where = get_preferred_edit_position ();
1933 double l = - ((new_page_size * ((where - current_leftmost)/(double)current_page)) - where);
1936 leftmost_after_zoom = 0;
1937 } else if (l > max_framepos) {
1938 leftmost_after_zoom = max_framepos - new_page_size;
1940 leftmost_after_zoom = (framepos_t) l;
1944 /* edit point not defined */
1951 // leftmost_after_zoom = min (leftmost_after_zoom, _session->current_end_frame());
1953 reposition_and_zoom (leftmost_after_zoom, nfpp);
1957 Editor::calc_extra_zoom_edges(framepos_t &start, framepos_t &end)
1959 /* this func helps make sure we leave a little space
1960 at each end of the editor so that the zoom doesn't fit the region
1961 precisely to the screen.
1964 GdkScreen* screen = gdk_screen_get_default ();
1965 const gint pixwidth = gdk_screen_get_width (screen);
1966 const gint mmwidth = gdk_screen_get_width_mm (screen);
1967 const double pix_per_mm = (double) pixwidth/ (double) mmwidth;
1968 const double one_centimeter_in_pixels = pix_per_mm * 10.0;
1970 const framepos_t range = end - start;
1971 const framecnt_t new_fpp = (framecnt_t) ceil ((double) range / (double) _visible_canvas_width);
1972 const framepos_t extra_samples = (framepos_t) floor (one_centimeter_in_pixels * new_fpp);
1974 if (start > extra_samples) {
1975 start -= extra_samples;
1980 if (max_framepos - extra_samples > end) {
1981 end += extra_samples;
1988 Editor::get_selection_extents (framepos_t &start, framepos_t &end) const
1990 start = max_framepos;
1994 //ToDo: if notes are selected, set extents to that selection
1996 //ToDo: if control points are selected, set extents to that selection
1998 if ( !selection->regions.empty() ) {
1999 RegionSelection rs = get_regions_from_selection_and_entered ();
2001 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
2003 if ((*i)->region()->position() < start) {
2004 start = (*i)->region()->position();
2007 if ((*i)->region()->last_frame() + 1 > end) {
2008 end = (*i)->region()->last_frame() + 1;
2012 } else if (!selection->time.empty()) {
2013 start = selection->time.start();
2014 end = selection->time.end_frame();
2016 ret = false; //no selection found
2019 if ((start == 0 && end == 0) || end < start) {
2028 Editor::temporal_zoom_selection (Editing::ZoomAxis axes)
2030 if (!selection) return;
2032 //ToDo: if notes are selected, zoom to that
2034 //ToDo: if control points are selected, zoom to that
2036 if (axes == Horizontal || axes == Both) {
2038 framepos_t start, end;
2039 if (get_selection_extents (start, end)) {
2040 calc_extra_zoom_edges (start, end);
2041 temporal_zoom_by_frame (start, end);
2045 if (axes == Vertical || axes == Both) {
2051 Editor::temporal_zoom_session ()
2053 ENSURE_GUI_THREAD (*this, &Editor::temporal_zoom_session)
2056 framecnt_t start = _session->current_start_frame();
2057 framecnt_t end = _session->current_end_frame();
2059 if (_session->actively_recording () ) {
2060 framepos_t cur = playhead_cursor->current_frame ();
2062 /* recording beyond the end marker; zoom out
2063 * by 5 seconds more so that if 'follow
2064 * playhead' is active we don't immediately
2067 end = cur + _session->frame_rate() * 5;
2071 if ((start == 0 && end == 0) || end < start) {
2075 calc_extra_zoom_edges(start, end);
2077 temporal_zoom_by_frame (start, end);
2082 Editor::temporal_zoom_by_frame (framepos_t start, framepos_t end)
2084 if (!_session) return;
2086 if ((start == 0 && end == 0) || end < start) {
2090 framepos_t range = end - start;
2092 const framecnt_t new_fpp = (framecnt_t) ceil ((double) range / (double) _visible_canvas_width);
2094 framepos_t new_page = range;
2095 framepos_t middle = (framepos_t) floor ((double) start + ((double) range / 2.0f));
2096 framepos_t new_leftmost = (framepos_t) floor ((double) middle - ((double) new_page / 2.0f));
2098 if (new_leftmost > middle) {
2102 if (new_leftmost < 0) {
2106 reposition_and_zoom (new_leftmost, new_fpp);
2110 Editor::temporal_zoom_to_frame (bool coarser, framepos_t frame)
2116 framecnt_t range_before = frame - leftmost_frame;
2120 if (samples_per_pixel <= 1) {
2123 new_spp = samples_per_pixel + (samples_per_pixel/2);
2125 range_before += range_before/2;
2127 if (samples_per_pixel >= 1) {
2128 new_spp = samples_per_pixel - (samples_per_pixel/2);
2130 /* could bail out here since we cannot zoom any finer,
2131 but leave that to the equality test below
2133 new_spp = samples_per_pixel;
2136 range_before -= range_before/2;
2139 if (new_spp == samples_per_pixel) {
2143 /* zoom focus is automatically taken as @param frame when this
2147 framepos_t new_leftmost = frame - (framepos_t)range_before;
2149 if (new_leftmost > frame) {
2153 if (new_leftmost < 0) {
2157 reposition_and_zoom (new_leftmost, new_spp);
2162 Editor::choose_new_marker_name(string &name) {
2164 if (!UIConfiguration::instance().get_name_new_markers()) {
2165 /* don't prompt user for a new name */
2169 Prompter dialog (true);
2171 dialog.set_prompt (_("New Name:"));
2173 dialog.set_title (_("New Location Marker"));
2175 dialog.set_name ("MarkNameWindow");
2176 dialog.set_size_request (250, -1);
2177 dialog.set_position (Gtk::WIN_POS_MOUSE);
2179 dialog.add_button (Stock::OK, RESPONSE_ACCEPT);
2180 dialog.set_initial_text (name);
2184 switch (dialog.run ()) {
2185 case RESPONSE_ACCEPT:
2191 dialog.get_result(name);
2198 Editor::add_location_from_selection ()
2202 if (selection->time.empty()) {
2206 if (_session == 0 || clicked_axisview == 0) {
2210 framepos_t start = selection->time[clicked_selection].start;
2211 framepos_t end = selection->time[clicked_selection].end;
2213 _session->locations()->next_available_name(rangename,"selection");
2214 Location *location = new Location (*_session, start, end, rangename, Location::IsRangeMarker, get_grid_music_divisions(0));
2216 begin_reversible_command (_("add marker"));
2218 XMLNode &before = _session->locations()->get_state();
2219 _session->locations()->add (location, true);
2220 XMLNode &after = _session->locations()->get_state();
2221 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2223 commit_reversible_command ();
2227 Editor::add_location_mark (framepos_t where)
2231 select_new_marker = true;
2233 _session->locations()->next_available_name(markername,"mark");
2234 if (!choose_new_marker_name(markername)) {
2237 Location *location = new Location (*_session, where, where, markername, Location::IsMark, get_grid_music_divisions (0));
2238 begin_reversible_command (_("add marker"));
2240 XMLNode &before = _session->locations()->get_state();
2241 _session->locations()->add (location, true);
2242 XMLNode &after = _session->locations()->get_state();
2243 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2245 commit_reversible_command ();
2249 Editor::set_session_start_from_playhead ()
2255 if ((loc = _session->locations()->session_range_location()) == 0) { //should never happen
2256 _session->set_session_extents ( _session->audible_frame(), _session->audible_frame() );
2258 XMLNode &before = loc->get_state();
2260 _session->set_session_extents ( _session->audible_frame(), loc->end() );
2262 XMLNode &after = loc->get_state();
2264 begin_reversible_command (_("Set session start"));
2266 _session->add_command (new MementoCommand<Location>(*loc, &before, &after));
2268 commit_reversible_command ();
2273 Editor::set_session_end_from_playhead ()
2279 if ((loc = _session->locations()->session_range_location()) == 0) { //should never happen
2280 _session->set_session_extents ( _session->audible_frame(), _session->audible_frame() );
2282 XMLNode &before = loc->get_state();
2284 _session->set_session_extents ( loc->start(), _session->audible_frame() );
2286 XMLNode &after = loc->get_state();
2288 begin_reversible_command (_("Set session start"));
2290 _session->add_command (new MementoCommand<Location>(*loc, &before, &after));
2292 commit_reversible_command ();
2295 _session->set_end_is_free (false);
2300 Editor::toggle_location_at_playhead_cursor ()
2302 if (!do_remove_location_at_playhead_cursor())
2304 add_location_from_playhead_cursor();
2309 Editor::add_location_from_playhead_cursor ()
2311 add_location_mark (_session->audible_frame());
2315 Editor::do_remove_location_at_playhead_cursor ()
2317 bool removed = false;
2320 XMLNode &before = _session->locations()->get_state();
2322 //find location(s) at this time
2323 Locations::LocationList locs;
2324 _session->locations()->find_all_between (_session->audible_frame(), _session->audible_frame()+1, locs, Location::Flags(0));
2325 for (Locations::LocationList::iterator i = locs.begin(); i != locs.end(); ++i) {
2326 if ((*i)->is_mark()) {
2327 _session->locations()->remove (*i);
2334 begin_reversible_command (_("remove marker"));
2335 XMLNode &after = _session->locations()->get_state();
2336 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2337 commit_reversible_command ();
2344 Editor::remove_location_at_playhead_cursor ()
2346 do_remove_location_at_playhead_cursor ();
2349 /** Add a range marker around each selected region */
2351 Editor::add_locations_from_region ()
2353 RegionSelection rs = get_regions_from_selection_and_entered ();
2358 bool commit = false;
2360 XMLNode &before = _session->locations()->get_state();
2362 for (RegionSelection::iterator i = rs.begin (); i != rs.end (); ++i) {
2364 boost::shared_ptr<Region> region = (*i)->region ();
2366 Location *location = new Location (*_session, region->position(), region->last_frame(), region->name(), Location::IsRangeMarker, 0);
2368 _session->locations()->add (location, true);
2373 begin_reversible_command (selection->regions.size () > 1 ? _("add markers") : _("add marker"));
2374 XMLNode &after = _session->locations()->get_state();
2375 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2376 commit_reversible_command ();
2380 /** Add a single range marker around all selected regions */
2382 Editor::add_location_from_region ()
2384 RegionSelection rs = get_regions_from_selection_and_entered ();
2390 XMLNode &before = _session->locations()->get_state();
2394 if (rs.size() > 1) {
2395 _session->locations()->next_available_name(markername, "regions");
2397 RegionView* rv = *(rs.begin());
2398 boost::shared_ptr<Region> region = rv->region();
2399 markername = region->name();
2402 if (!choose_new_marker_name(markername)) {
2406 // single range spanning all selected
2407 Location *location = new Location (*_session, selection->regions.start(), selection->regions.end_frame(), markername, Location::IsRangeMarker, 0);
2408 _session->locations()->add (location, true);
2410 begin_reversible_command (_("add marker"));
2411 XMLNode &after = _session->locations()->get_state();
2412 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2413 commit_reversible_command ();
2419 Editor::jump_forward_to_mark ()
2425 framepos_t pos = _session->locations()->first_mark_after (playhead_cursor->current_frame());
2431 _session->request_locate (pos, _session->transport_rolling());
2435 Editor::jump_backward_to_mark ()
2441 framepos_t pos = _session->locations()->first_mark_before (playhead_cursor->current_frame());
2443 //handle the case where we are rolling, and we're less than one-half second past the mark, we want to go to the prior mark...
2444 if ( _session->transport_rolling() ) {
2445 if ( (playhead_cursor->current_frame() - pos) < _session->frame_rate()/2 ) {
2446 framepos_t prior = _session->locations()->first_mark_before ( pos );
2455 _session->request_locate (pos, _session->transport_rolling());
2461 framepos_t const pos = _session->audible_frame ();
2464 _session->locations()->next_available_name (markername, "mark");
2466 if (!choose_new_marker_name (markername)) {
2470 _session->locations()->add (new Location (*_session, pos, 0, markername, Location::IsMark, 0), true);
2474 Editor::clear_markers ()
2477 begin_reversible_command (_("clear markers"));
2479 XMLNode &before = _session->locations()->get_state();
2480 _session->locations()->clear_markers ();
2481 XMLNode &after = _session->locations()->get_state();
2482 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2484 commit_reversible_command ();
2489 Editor::clear_ranges ()
2492 begin_reversible_command (_("clear ranges"));
2494 XMLNode &before = _session->locations()->get_state();
2496 _session->locations()->clear_ranges ();
2498 XMLNode &after = _session->locations()->get_state();
2499 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2501 commit_reversible_command ();
2506 Editor::clear_locations ()
2508 begin_reversible_command (_("clear locations"));
2510 XMLNode &before = _session->locations()->get_state();
2511 _session->locations()->clear ();
2512 XMLNode &after = _session->locations()->get_state();
2513 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2515 commit_reversible_command ();
2519 Editor::unhide_markers ()
2521 for (LocationMarkerMap::iterator i = location_markers.begin(); i != location_markers.end(); ++i) {
2522 Location *l = (*i).first;
2523 if (l->is_hidden() && l->is_mark()) {
2524 l->set_hidden(false, this);
2530 Editor::unhide_ranges ()
2532 for (LocationMarkerMap::iterator i = location_markers.begin(); i != location_markers.end(); ++i) {
2533 Location *l = (*i).first;
2534 if (l->is_hidden() && l->is_range_marker()) {
2535 l->set_hidden(false, this);
2540 /* INSERT/REPLACE */
2543 Editor::insert_region_list_selection (float times)
2545 RouteTimeAxisView *tv = 0;
2546 boost::shared_ptr<Playlist> playlist;
2548 if (clicked_routeview != 0) {
2549 tv = clicked_routeview;
2550 } else if (!selection->tracks.empty()) {
2551 if ((tv = dynamic_cast<RouteTimeAxisView*>(selection->tracks.front())) == 0) {
2554 } else if (entered_track != 0) {
2555 if ((tv = dynamic_cast<RouteTimeAxisView*>(entered_track)) == 0) {
2562 if ((playlist = tv->playlist()) == 0) {
2566 boost::shared_ptr<Region> region = _regions->get_single_selection ();
2571 begin_reversible_command (_("insert region"));
2572 playlist->clear_changes ();
2573 playlist->add_region ((RegionFactory::create (region, true)), get_preferred_edit_position(), times);
2574 if (Config->get_edit_mode() == Ripple)
2575 playlist->ripple (get_preferred_edit_position(), region->length() * times, boost::shared_ptr<Region>());
2577 _session->add_command(new StatefulDiffCommand (playlist));
2578 commit_reversible_command ();
2581 /* BUILT-IN EFFECTS */
2584 Editor::reverse_selection ()
2589 /* GAIN ENVELOPE EDITING */
2592 Editor::edit_envelope ()
2599 Editor::transition_to_rolling (bool fwd)
2605 if (_session->config.get_external_sync()) {
2606 switch (Config->get_sync_source()) {
2610 /* transport controlled by the master */
2615 if (_session->is_auditioning()) {
2616 _session->cancel_audition ();
2620 _session->request_transport_speed (fwd ? 1.0f : -1.0f);
2624 Editor::play_from_start ()
2626 _session->request_locate (_session->current_start_frame(), true);
2630 Editor::play_from_edit_point ()
2632 _session->request_locate (get_preferred_edit_position(), true);
2636 Editor::play_from_edit_point_and_return ()
2638 framepos_t start_frame;
2639 framepos_t return_frame;
2641 start_frame = get_preferred_edit_position ( EDIT_IGNORE_PHEAD );
2643 if (_session->transport_rolling()) {
2644 _session->request_locate (start_frame, false);
2648 /* don't reset the return frame if its already set */
2650 if ((return_frame = _session->requested_return_frame()) < 0) {
2651 return_frame = _session->audible_frame();
2654 if (start_frame >= 0) {
2655 _session->request_roll_at_and_return (start_frame, return_frame);
2660 Editor::play_selection ()
2662 framepos_t start, end;
2663 if (!get_selection_extents ( start, end))
2666 AudioRange ar (start, end, 0);
2667 list<AudioRange> lar;
2670 _session->request_play_range (&lar, true);
2675 Editor::maybe_locate_with_edit_preroll (framepos_t location)
2677 if ( _session->transport_rolling() || !UIConfiguration::instance().get_follow_edits() || _session->config.get_external_sync() )
2680 location -= _session->preroll_samples (location);
2682 //don't try to locate before the beginning of time
2687 //if follow_playhead is on, keep the playhead on the screen
2688 if ( _follow_playhead )
2689 if ( location < leftmost_frame )
2690 location = leftmost_frame;
2692 _session->request_locate( location );
2696 Editor::play_with_preroll ()
2698 framepos_t start, end;
2699 if ( UIConfiguration::instance().get_follow_edits() && get_selection_extents ( start, end) ) {
2700 const framepos_t preroll = _session->preroll_samples (start);
2702 framepos_t ret = start;
2704 if (start > preroll) {
2705 start = start - preroll;
2708 end = end + preroll; //"post-roll"
2710 AudioRange ar (start, end, 0);
2711 list<AudioRange> lar;
2714 _session->request_play_range (&lar, true);
2715 _session->set_requested_return_frame (ret); //force auto-return to return to range start, without the preroll
2717 framepos_t ph = playhead_cursor->current_frame ();
2718 const framepos_t preroll = _session->preroll_samples (ph);
2721 start = ph - preroll;
2725 _session->request_locate (start, true);
2726 _session->set_requested_return_frame (ph); //force auto-return to return to playhead location, without the preroll
2731 Editor::rec_with_preroll ()
2733 framepos_t ph = playhead_cursor->current_frame ();
2734 framepos_t preroll = _session->preroll_samples (ph);
2735 _session->request_preroll_record_trim (ph, preroll);
2739 Editor::rec_with_count_in ()
2741 _session->request_count_in_record ();
2745 Editor::play_location (Location& location)
2747 if (location.start() <= location.end()) {
2751 _session->request_bounded_roll (location.start(), location.end());
2755 Editor::loop_location (Location& location)
2757 if (location.start() <= location.end()) {
2763 if ((tll = transport_loop_location()) != 0) {
2764 tll->set (location.start(), location.end());
2766 // enable looping, reposition and start rolling
2767 _session->request_locate (tll->start(), true);
2768 _session->request_play_loop (true);
2773 Editor::do_layer_operation (LayerOperation op)
2775 if (selection->regions.empty ()) {
2779 bool const multiple = selection->regions.size() > 1;
2783 begin_reversible_command (_("raise regions"));
2785 begin_reversible_command (_("raise region"));
2791 begin_reversible_command (_("raise regions to top"));
2793 begin_reversible_command (_("raise region to top"));
2799 begin_reversible_command (_("lower regions"));
2801 begin_reversible_command (_("lower region"));
2807 begin_reversible_command (_("lower regions to bottom"));
2809 begin_reversible_command (_("lower region"));
2814 set<boost::shared_ptr<Playlist> > playlists = selection->regions.playlists ();
2815 for (set<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
2816 (*i)->clear_owned_changes ();
2819 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
2820 boost::shared_ptr<Region> r = (*i)->region ();
2832 r->lower_to_bottom ();
2836 for (set<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
2837 vector<Command*> cmds;
2839 _session->add_commands (cmds);
2842 commit_reversible_command ();
2846 Editor::raise_region ()
2848 do_layer_operation (Raise);
2852 Editor::raise_region_to_top ()
2854 do_layer_operation (RaiseToTop);
2858 Editor::lower_region ()
2860 do_layer_operation (Lower);
2864 Editor::lower_region_to_bottom ()
2866 do_layer_operation (LowerToBottom);
2869 /** Show the region editor for the selected regions */
2871 Editor::show_region_properties ()
2873 selection->foreach_regionview (&RegionView::show_region_editor);
2876 /** Show the midi list editor for the selected MIDI regions */
2878 Editor::show_midi_list_editor ()
2880 selection->foreach_midi_regionview (&MidiRegionView::show_list_editor);
2884 Editor::rename_region ()
2886 RegionSelection rs = get_regions_from_selection_and_entered ();
2892 ArdourDialog d (_("Rename Region"), true, false);
2894 Label label (_("New name:"));
2897 hbox.set_spacing (6);
2898 hbox.pack_start (label, false, false);
2899 hbox.pack_start (entry, true, true);
2901 d.get_vbox()->set_border_width (12);
2902 d.get_vbox()->pack_start (hbox, false, false);
2904 d.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
2905 d.add_button(Gtk::Stock::OK, Gtk::RESPONSE_OK);
2907 d.set_size_request (300, -1);
2909 entry.set_text (rs.front()->region()->name());
2910 entry.select_region (0, -1);
2912 entry.signal_activate().connect (sigc::bind (sigc::mem_fun (d, &Dialog::response), RESPONSE_OK));
2918 int const ret = d.run();
2922 if (ret != RESPONSE_OK) {
2926 std::string str = entry.get_text();
2927 strip_whitespace_edges (str);
2929 rs.front()->region()->set_name (str);
2930 _regions->redisplay ();
2934 /** Start an audition of the first selected region */
2936 Editor::play_edit_range ()
2938 framepos_t start, end;
2940 if (get_edit_op_range (start, end)) {
2941 _session->request_bounded_roll (start, end);
2946 Editor::play_selected_region ()
2948 framepos_t start = max_framepos;
2951 RegionSelection rs = get_regions_from_selection_and_entered ();
2957 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
2958 if ((*i)->region()->position() < start) {
2959 start = (*i)->region()->position();
2961 if ((*i)->region()->last_frame() + 1 > end) {
2962 end = (*i)->region()->last_frame() + 1;
2966 _session->request_bounded_roll (start, end);
2970 Editor::audition_playlist_region_standalone (boost::shared_ptr<Region> region)
2972 _session->audition_region (region);
2976 Editor::region_from_selection ()
2978 if (clicked_axisview == 0) {
2982 if (selection->time.empty()) {
2986 framepos_t start = selection->time[clicked_selection].start;
2987 framepos_t end = selection->time[clicked_selection].end;
2989 TrackViewList tracks = get_tracks_for_range_action ();
2991 framepos_t selection_cnt = end - start + 1;
2993 for (TrackSelection::iterator i = tracks.begin(); i != tracks.end(); ++i) {
2994 boost::shared_ptr<Region> current;
2995 boost::shared_ptr<Playlist> pl;
2996 framepos_t internal_start;
2999 if ((pl = (*i)->playlist()) == 0) {
3003 if ((current = pl->top_region_at (start)) == 0) {
3007 internal_start = start - current->position();
3008 RegionFactory::region_name (new_name, current->name(), true);
3012 plist.add (ARDOUR::Properties::start, current->start() + internal_start);
3013 plist.add (ARDOUR::Properties::length, selection_cnt);
3014 plist.add (ARDOUR::Properties::name, new_name);
3015 plist.add (ARDOUR::Properties::layer, 0);
3017 boost::shared_ptr<Region> region (RegionFactory::create (current, plist));
3022 Editor::create_region_from_selection (vector<boost::shared_ptr<Region> >& new_regions)
3024 if (selection->time.empty() || selection->tracks.empty()) {
3028 framepos_t start, end;
3029 if (clicked_selection) {
3030 start = selection->time[clicked_selection].start;
3031 end = selection->time[clicked_selection].end;
3033 start = selection->time.start();
3034 end = selection->time.end_frame();
3037 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
3038 sort_track_selection (ts);
3040 for (TrackSelection::iterator i = ts.begin(); i != ts.end(); ++i) {
3041 boost::shared_ptr<Region> current;
3042 boost::shared_ptr<Playlist> playlist;
3043 framepos_t internal_start;
3046 if ((playlist = (*i)->playlist()) == 0) {
3050 if ((current = playlist->top_region_at(start)) == 0) {
3054 internal_start = start - current->position();
3055 RegionFactory::region_name (new_name, current->name(), true);
3059 plist.add (ARDOUR::Properties::start, current->start() + internal_start);
3060 plist.add (ARDOUR::Properties::length, end - start + 1);
3061 plist.add (ARDOUR::Properties::name, new_name);
3063 new_regions.push_back (RegionFactory::create (current, plist));
3068 Editor::split_multichannel_region ()
3070 RegionSelection rs = get_regions_from_selection_and_entered ();
3076 vector< boost::shared_ptr<Region> > v;
3078 for (list<RegionView*>::iterator x = rs.begin(); x != rs.end(); ++x) {
3079 (*x)->region()->separate_by_channel (*_session, v);
3084 Editor::new_region_from_selection ()
3086 region_from_selection ();
3087 cancel_selection ();
3091 add_if_covered (RegionView* rv, const AudioRange* ar, RegionSelection* rs)
3093 switch (rv->region()->coverage (ar->start, ar->end - 1)) {
3094 // n.b. -1 because AudioRange::end is one past the end, but coverage expects inclusive ranges
3095 case Evoral::OverlapNone:
3103 * - selected tracks, or if there are none...
3104 * - tracks containing selected regions, or if there are none...
3109 Editor::get_tracks_for_range_action () const
3113 if (selection->tracks.empty()) {
3115 /* use tracks with selected regions */
3117 RegionSelection rs = selection->regions;
3119 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3120 TimeAxisView* tv = &(*i)->get_time_axis_view();
3122 if (!t.contains (tv)) {
3128 /* no regions and no tracks: use all tracks */
3134 t = selection->tracks;
3137 return t.filter_to_unique_playlists();
3141 Editor::separate_regions_between (const TimeSelection& ts)
3143 bool in_command = false;
3144 boost::shared_ptr<Playlist> playlist;
3145 RegionSelection new_selection;
3147 TrackViewList tmptracks = get_tracks_for_range_action ();
3148 sort_track_selection (tmptracks);
3150 for (TrackSelection::iterator i = tmptracks.begin(); i != tmptracks.end(); ++i) {
3152 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> ((*i));
3158 if (!rtv->is_track()) {
3162 /* no edits to destructive tracks */
3164 if (rtv->track()->destructive()) {
3168 if ((playlist = rtv->playlist()) != 0) {
3170 playlist->clear_changes ();
3172 /* XXX need to consider musical time selections here at some point */
3174 double speed = rtv->track()->speed();
3176 for (list<AudioRange>::const_iterator t = ts.begin(); t != ts.end(); ++t) {
3178 sigc::connection c = rtv->view()->RegionViewAdded.connect (
3179 sigc::mem_fun(*this, &Editor::collect_new_region_view));
3181 latest_regionviews.clear ();
3183 playlist->partition ((framepos_t)((*t).start * speed),
3184 (framepos_t)((*t).end * speed), false);
3188 if (!latest_regionviews.empty()) {
3190 rtv->view()->foreach_regionview (sigc::bind (
3191 sigc::ptr_fun (add_if_covered),
3192 &(*t), &new_selection));
3195 begin_reversible_command (_("separate"));
3199 /* pick up changes to existing regions */
3201 vector<Command*> cmds;
3202 playlist->rdiff (cmds);
3203 _session->add_commands (cmds);
3205 /* pick up changes to the playlist itself (adds/removes)
3208 _session->add_command(new StatefulDiffCommand (playlist));
3215 // selection->set (new_selection);
3217 commit_reversible_command ();
3221 struct PlaylistState {
3222 boost::shared_ptr<Playlist> playlist;
3226 /** Take tracks from get_tracks_for_range_action and cut any regions
3227 * on those tracks so that the tracks are empty over the time
3231 Editor::separate_region_from_selection ()
3233 /* preferentially use *all* ranges in the time selection if we're in range mode
3234 to allow discontiguous operation, since get_edit_op_range() currently
3235 returns a single range.
3238 if (!selection->time.empty()) {
3240 separate_regions_between (selection->time);
3247 if (get_edit_op_range (start, end)) {
3249 AudioRange ar (start, end, 1);
3253 separate_regions_between (ts);
3259 Editor::separate_region_from_punch ()
3261 Location* loc = _session->locations()->auto_punch_location();
3263 separate_regions_using_location (*loc);
3268 Editor::separate_region_from_loop ()
3270 Location* loc = _session->locations()->auto_loop_location();
3272 separate_regions_using_location (*loc);
3277 Editor::separate_regions_using_location (Location& loc)
3279 if (loc.is_mark()) {
3283 AudioRange ar (loc.start(), loc.end(), 1);
3288 separate_regions_between (ts);
3291 /** Separate regions under the selected region */
3293 Editor::separate_under_selected_regions ()
3295 vector<PlaylistState> playlists;
3299 rs = get_regions_from_selection_and_entered();
3301 if (!_session || rs.empty()) {
3305 begin_reversible_command (_("separate region under"));
3307 list<boost::shared_ptr<Region> > regions_to_remove;
3309 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3310 // we can't just remove the region(s) in this loop because
3311 // this removes them from the RegionSelection, and they thus
3312 // disappear from underneath the iterator, and the ++i above
3313 // SEGVs in a puzzling fashion.
3315 // so, first iterate over the regions to be removed from rs and
3316 // add them to the regions_to_remove list, and then
3317 // iterate over the list to actually remove them.
3319 regions_to_remove.push_back ((*i)->region());
3322 for (list<boost::shared_ptr<Region> >::iterator rl = regions_to_remove.begin(); rl != regions_to_remove.end(); ++rl) {
3324 boost::shared_ptr<Playlist> playlist = (*rl)->playlist();
3327 // is this check necessary?
3331 vector<PlaylistState>::iterator i;
3333 //only take state if this is a new playlist.
3334 for (i = playlists.begin(); i != playlists.end(); ++i) {
3335 if ((*i).playlist == playlist) {
3340 if (i == playlists.end()) {
3342 PlaylistState before;
3343 before.playlist = playlist;
3344 before.before = &playlist->get_state();
3346 playlist->freeze ();
3347 playlists.push_back(before);
3350 //Partition on the region bounds
3351 playlist->partition ((*rl)->first_frame() - 1, (*rl)->last_frame() + 1, true);
3353 //Re-add region that was just removed due to the partition operation
3354 playlist->add_region( (*rl), (*rl)->first_frame() );
3357 vector<PlaylistState>::iterator pl;
3359 for (pl = playlists.begin(); pl != playlists.end(); ++pl) {
3360 (*pl).playlist->thaw ();
3361 _session->add_command(new MementoCommand<Playlist>(*(*pl).playlist, (*pl).before, &(*pl).playlist->get_state()));
3364 commit_reversible_command ();
3368 Editor::crop_region_to_selection ()
3370 if (!selection->time.empty()) {
3372 crop_region_to (selection->time.start(), selection->time.end_frame());
3379 if (get_edit_op_range (start, end)) {
3380 crop_region_to (start, end);
3387 Editor::crop_region_to (framepos_t start, framepos_t end)
3389 vector<boost::shared_ptr<Playlist> > playlists;
3390 boost::shared_ptr<Playlist> playlist;
3393 if (selection->tracks.empty()) {
3394 ts = track_views.filter_to_unique_playlists();
3396 ts = selection->tracks.filter_to_unique_playlists ();
3399 sort_track_selection (ts);
3401 for (TrackSelection::iterator i = ts.begin(); i != ts.end(); ++i) {
3403 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> ((*i));
3409 boost::shared_ptr<Track> t = rtv->track();
3411 if (t != 0 && ! t->destructive()) {
3413 if ((playlist = rtv->playlist()) != 0) {
3414 playlists.push_back (playlist);
3419 if (playlists.empty()) {
3424 framepos_t new_start;
3426 framecnt_t new_length;
3427 bool in_command = false;
3429 for (vector<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
3431 /* Only the top regions at start and end have to be cropped */
3432 boost::shared_ptr<Region> region_at_start = (*i)->top_region_at(start);
3433 boost::shared_ptr<Region> region_at_end = (*i)->top_region_at(end);
3435 vector<boost::shared_ptr<Region> > regions;
3437 if (region_at_start != 0) {
3438 regions.push_back (region_at_start);
3440 if (region_at_end != 0) {
3441 regions.push_back (region_at_end);
3444 /* now adjust lengths */
3445 for (vector<boost::shared_ptr<Region> >::iterator i = regions.begin(); i != regions.end(); ++i) {
3447 pos = (*i)->position();
3448 new_start = max (start, pos);
3449 if (max_framepos - pos > (*i)->length()) {
3450 new_end = pos + (*i)->length() - 1;
3452 new_end = max_framepos;
3454 new_end = min (end, new_end);
3455 new_length = new_end - new_start + 1;
3458 begin_reversible_command (_("trim to selection"));
3461 (*i)->clear_changes ();
3462 (*i)->trim_to (new_start, new_length);
3463 _session->add_command (new StatefulDiffCommand (*i));
3468 commit_reversible_command ();
3473 Editor::region_fill_track ()
3475 boost::shared_ptr<Playlist> playlist;
3476 RegionSelection regions = get_regions_from_selection_and_entered ();
3477 RegionSelection foo;
3479 framepos_t const end = _session->current_end_frame ();
3481 if (regions.empty () || regions.end_frame () + 1 >= end) {
3485 framepos_t const start_frame = regions.start ();
3486 framepos_t const end_frame = regions.end_frame ();
3487 framecnt_t const gap = end_frame - start_frame + 1;
3489 begin_reversible_command (Operations::region_fill);
3491 selection->clear_regions ();
3493 for (RegionSelection::iterator i = regions.begin(); i != regions.end(); ++i) {
3495 boost::shared_ptr<Region> r ((*i)->region());
3497 TimeAxisView& tv = (*i)->get_time_axis_view();
3498 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (&tv);
3499 latest_regionviews.clear ();
3500 sigc::connection c = rtv->view()->RegionViewAdded.connect (sigc::mem_fun(*this, &Editor::collect_new_region_view));
3502 framepos_t const position = end_frame + (r->first_frame() - start_frame + 1);
3503 playlist = (*i)->region()->playlist();
3504 playlist->clear_changes ();
3505 playlist->duplicate_until (r, position, gap, end);
3506 _session->add_command(new StatefulDiffCommand (playlist));
3510 foo.insert (foo.end(), latest_regionviews.begin(), latest_regionviews.end());
3514 selection->set (foo);
3517 commit_reversible_command ();
3521 Editor::set_region_sync_position ()
3523 set_sync_point (get_preferred_edit_position (), get_regions_from_selection_and_edit_point ());
3527 Editor::set_sync_point (framepos_t where, const RegionSelection& rs)
3529 bool in_command = false;
3531 for (RegionSelection::const_iterator r = rs.begin(); r != rs.end(); ++r) {
3533 if (!(*r)->region()->covers (where)) {
3537 boost::shared_ptr<Region> region ((*r)->region());
3540 begin_reversible_command (_("set sync point"));
3544 region->clear_changes ();
3545 region->set_sync_position (where);
3546 _session->add_command(new StatefulDiffCommand (region));
3550 commit_reversible_command ();
3554 /** Remove the sync positions of the selection */
3556 Editor::remove_region_sync ()
3558 RegionSelection rs = get_regions_from_selection_and_entered ();
3564 begin_reversible_command (_("remove region sync"));
3566 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3568 (*i)->region()->clear_changes ();
3569 (*i)->region()->clear_sync_position ();
3570 _session->add_command(new StatefulDiffCommand ((*i)->region()));
3573 commit_reversible_command ();
3577 Editor::naturalize_region ()
3579 RegionSelection rs = get_regions_from_selection_and_entered ();
3585 if (rs.size() > 1) {
3586 begin_reversible_command (_("move regions to original position"));
3588 begin_reversible_command (_("move region to original position"));
3591 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3592 (*i)->region()->clear_changes ();
3593 (*i)->region()->move_to_natural_position ();
3594 _session->add_command (new StatefulDiffCommand ((*i)->region()));
3597 commit_reversible_command ();
3601 Editor::align_regions (RegionPoint what)
3603 RegionSelection const rs = get_regions_from_selection_and_edit_point ();
3609 begin_reversible_command (_("align selection"));
3611 framepos_t const position = get_preferred_edit_position ();
3613 for (RegionSelection::const_iterator i = rs.begin(); i != rs.end(); ++i) {
3614 align_region_internal ((*i)->region(), what, position);
3617 commit_reversible_command ();
3620 struct RegionSortByTime {
3621 bool operator() (const RegionView* a, const RegionView* b) {
3622 return a->region()->position() < b->region()->position();
3627 Editor::align_regions_relative (RegionPoint point)
3629 RegionSelection const rs = get_regions_from_selection_and_edit_point ();
3635 framepos_t const position = get_preferred_edit_position ();
3637 framepos_t distance = 0;
3641 list<RegionView*> sorted;
3642 rs.by_position (sorted);
3644 boost::shared_ptr<Region> r ((*sorted.begin())->region());
3649 if (position > r->position()) {
3650 distance = position - r->position();
3652 distance = r->position() - position;
3658 if (position > r->last_frame()) {
3659 distance = position - r->last_frame();
3660 pos = r->position() + distance;
3662 distance = r->last_frame() - position;
3663 pos = r->position() - distance;
3669 pos = r->adjust_to_sync (position);
3670 if (pos > r->position()) {
3671 distance = pos - r->position();
3673 distance = r->position() - pos;
3679 if (pos == r->position()) {
3683 begin_reversible_command (_("align selection (relative)"));
3685 /* move first one specially */
3687 r->clear_changes ();
3688 r->set_position (pos);
3689 _session->add_command(new StatefulDiffCommand (r));
3691 /* move rest by the same amount */
3695 for (list<RegionView*>::iterator i = sorted.begin(); i != sorted.end(); ++i) {
3697 boost::shared_ptr<Region> region ((*i)->region());
3699 region->clear_changes ();
3702 region->set_position (region->position() + distance);
3704 region->set_position (region->position() - distance);
3707 _session->add_command(new StatefulDiffCommand (region));
3711 commit_reversible_command ();
3715 Editor::align_region (boost::shared_ptr<Region> region, RegionPoint point, framepos_t position)
3717 begin_reversible_command (_("align region"));
3718 align_region_internal (region, point, position);
3719 commit_reversible_command ();
3723 Editor::align_region_internal (boost::shared_ptr<Region> region, RegionPoint point, framepos_t position)
3725 region->clear_changes ();
3729 region->set_position (region->adjust_to_sync (position));
3733 if (position > region->length()) {
3734 region->set_position (position - region->length());
3739 region->set_position (position);
3743 _session->add_command(new StatefulDiffCommand (region));
3747 Editor::trim_region_front ()
3753 Editor::trim_region_back ()
3755 trim_region (false);
3759 Editor::trim_region (bool front)
3761 framepos_t where = get_preferred_edit_position();
3762 RegionSelection rs = get_regions_from_selection_and_edit_point ();
3768 begin_reversible_command (front ? _("trim front") : _("trim back"));
3770 for (list<RegionView*>::const_iterator i = rs.by_layer().begin(); i != rs.by_layer().end(); ++i) {
3771 if (!(*i)->region()->locked()) {
3773 (*i)->region()->clear_changes ();
3776 (*i)->region()->trim_front (where);
3778 (*i)->region()->trim_end (where);
3781 _session->add_command (new StatefulDiffCommand ((*i)->region()));
3785 commit_reversible_command ();
3788 /** Trim the end of the selected regions to the position of the edit cursor */
3790 Editor::trim_region_to_loop ()
3792 Location* loc = _session->locations()->auto_loop_location();
3796 trim_region_to_location (*loc, _("trim to loop"));
3800 Editor::trim_region_to_punch ()
3802 Location* loc = _session->locations()->auto_punch_location();
3806 trim_region_to_location (*loc, _("trim to punch"));
3810 Editor::trim_region_to_location (const Location& loc, const char* str)
3812 RegionSelection rs = get_regions_from_selection_and_entered ();
3813 bool in_command = false;
3815 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
3816 RegionView* rv = (*x);
3818 /* require region to span proposed trim */
3819 switch (rv->region()->coverage (loc.start(), loc.end())) {
3820 case Evoral::OverlapInternal:
3826 RouteTimeAxisView* tav = dynamic_cast<RouteTimeAxisView*> (&rv->get_time_axis_view());
3835 if (tav->track() != 0) {
3836 speed = tav->track()->speed();
3839 start = session_frame_to_track_frame (loc.start(), speed);
3840 end = session_frame_to_track_frame (loc.end(), speed);
3842 rv->region()->clear_changes ();
3843 rv->region()->trim_to (start, (end - start));
3846 begin_reversible_command (str);
3849 _session->add_command(new StatefulDiffCommand (rv->region()));
3853 commit_reversible_command ();
3858 Editor::trim_region_to_previous_region_end ()
3860 return trim_to_region(false);
3864 Editor::trim_region_to_next_region_start ()
3866 return trim_to_region(true);
3870 Editor::trim_to_region(bool forward)
3872 RegionSelection rs = get_regions_from_selection_and_entered ();
3873 bool in_command = false;
3875 boost::shared_ptr<Region> next_region;
3877 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
3879 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*x);
3885 AudioTimeAxisView* atav = dynamic_cast<AudioTimeAxisView*> (&arv->get_time_axis_view());
3893 if (atav->track() != 0) {
3894 speed = atav->track()->speed();
3898 boost::shared_ptr<Region> region = arv->region();
3899 boost::shared_ptr<Playlist> playlist (region->playlist());
3901 region->clear_changes ();
3905 next_region = playlist->find_next_region (region->first_frame(), Start, 1);
3911 region->trim_end((framepos_t) ( (next_region->first_frame() - 1) * speed));
3912 arv->region_changed (PropertyChange (ARDOUR::Properties::length));
3916 next_region = playlist->find_next_region (region->first_frame(), Start, 0);
3922 region->trim_front((framepos_t) ((next_region->last_frame() + 1) * speed));
3924 arv->region_changed (ARDOUR::bounds_change);
3928 begin_reversible_command (_("trim to region"));
3931 _session->add_command(new StatefulDiffCommand (region));
3935 commit_reversible_command ();
3940 Editor::unfreeze_route ()
3942 if (clicked_routeview == 0 || !clicked_routeview->is_track()) {
3946 clicked_routeview->track()->unfreeze ();
3950 Editor::_freeze_thread (void* arg)
3952 return static_cast<Editor*>(arg)->freeze_thread ();
3956 Editor::freeze_thread ()
3958 /* create event pool because we may need to talk to the session */
3959 SessionEvent::create_per_thread_pool ("freeze events", 64);
3960 /* create per-thread buffers for process() tree to use */
3961 clicked_routeview->audio_track()->freeze_me (*current_interthread_info);
3962 current_interthread_info->done = true;
3967 Editor::freeze_route ()
3973 /* stop transport before we start. this is important */
3975 _session->request_transport_speed (0.0);
3977 /* wait for just a little while, because the above call is asynchronous */
3979 Glib::usleep (250000);
3981 if (clicked_routeview == 0 || !clicked_routeview->is_audio_track()) {
3985 if (!clicked_routeview->track()->bounceable (clicked_routeview->track()->main_outs(), true)) {
3987 _("This track/bus cannot be frozen because the signal adds or loses channels before reaching the outputs.\n"
3988 "This is typically caused by plugins that generate stereo output from mono input or vice versa.")
3990 d.set_title (_("Cannot freeze"));
3995 if (clicked_routeview->track()->has_external_redirects()) {
3996 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"
3997 "Freezing will only process the signal as far as the first send/insert/return."),
3998 clicked_routeview->track()->name()), true, MESSAGE_INFO, BUTTONS_NONE, true);
4000 d.add_button (_("Freeze anyway"), Gtk::RESPONSE_OK);
4001 d.add_button (_("Don't freeze"), Gtk::RESPONSE_CANCEL);
4002 d.set_title (_("Freeze Limits"));
4004 int response = d.run ();
4007 case Gtk::RESPONSE_CANCEL:
4014 InterThreadInfo itt;
4015 current_interthread_info = &itt;
4017 InterthreadProgressWindow ipw (current_interthread_info, _("Freeze"), _("Cancel Freeze"));
4019 pthread_create_and_store (X_("freezer"), &itt.thread, _freeze_thread, this);
4021 CursorContext::Handle cursor_ctx = CursorContext::create(*this, _cursors->wait);
4023 while (!itt.done && !itt.cancel) {
4024 gtk_main_iteration ();
4027 pthread_join (itt.thread, 0);
4028 current_interthread_info = 0;
4032 Editor::bounce_range_selection (bool replace, bool enable_processing)
4034 if (selection->time.empty()) {
4038 TrackSelection views = selection->tracks;
4040 for (TrackViewList::iterator i = views.begin(); i != views.end(); ++i) {
4042 if (enable_processing) {
4044 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*i);
4046 if (rtv && rtv->track() && replace && enable_processing && !rtv->track()->bounceable (rtv->track()->main_outs(), false)) {
4048 _("You can't perform this operation because the processing of the signal "
4049 "will cause one or more of the tracks to end up with a region with more channels than this track has inputs.\n\n"
4050 "You can do this without processing, which is a different operation.")
4052 d.set_title (_("Cannot bounce"));
4059 framepos_t start = selection->time[clicked_selection].start;
4060 framepos_t end = selection->time[clicked_selection].end;
4061 framepos_t cnt = end - start + 1;
4062 bool in_command = false;
4064 for (TrackViewList::iterator i = views.begin(); i != views.end(); ++i) {
4066 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*i);
4072 boost::shared_ptr<Playlist> playlist;
4074 if ((playlist = rtv->playlist()) == 0) {
4078 InterThreadInfo itt;
4080 playlist->clear_changes ();
4081 playlist->clear_owned_changes ();
4083 boost::shared_ptr<Region> r;
4085 if (enable_processing) {
4086 r = rtv->track()->bounce_range (start, start+cnt, itt, rtv->track()->main_outs(), false);
4088 r = rtv->track()->bounce_range (start, start+cnt, itt, boost::shared_ptr<Processor>(), false);
4096 list<AudioRange> ranges;
4097 ranges.push_back (AudioRange (start, start+cnt, 0));
4098 playlist->cut (ranges); // discard result
4099 playlist->add_region (r, start);
4103 begin_reversible_command (_("bounce range"));
4106 vector<Command*> cmds;
4107 playlist->rdiff (cmds);
4108 _session->add_commands (cmds);
4110 _session->add_command (new StatefulDiffCommand (playlist));
4114 commit_reversible_command ();
4118 /** Delete selected regions, automation points or a time range */
4122 //special case: if the user is pointing in the editor/mixer strip, they may be trying to delete a plugin.
4123 //we need this because the editor-mixer strip is in the editor window, so it doesn't get the bindings from the mix window
4124 bool deleted = false;
4125 if ( current_mixer_strip && current_mixer_strip == MixerStrip::entered_mixer_strip() )
4126 deleted = current_mixer_strip->delete_processors ();
4132 /** Cut selected regions, automation points or a time range */
4139 /** Copy selected regions, automation points or a time range */
4147 /** @return true if a Cut, Copy or Clear is possible */
4149 Editor::can_cut_copy () const
4151 if (!selection->time.empty() || !selection->regions.empty() || !selection->points.empty())
4158 /** Cut, copy or clear selected regions, automation points or a time range.
4159 * @param op Operation (Delete, Cut, Copy or Clear)
4162 Editor::cut_copy (CutCopyOp op)
4164 /* only cancel selection if cut/copy is successful.*/
4170 opname = _("delete");
4179 opname = _("clear");
4183 /* if we're deleting something, and the mouse is still pressed,
4184 the thing we started a drag for will be gone when we release
4185 the mouse button(s). avoid this. see part 2 at the end of
4189 if (op == Delete || op == Cut || op == Clear) {
4190 if (_drags->active ()) {
4195 if ( op != Delete ) //"Delete" doesn't change copy/paste buf
4196 cut_buffer->clear ();
4198 if (entered_marker) {
4200 /* cut/delete op while pointing at a marker */
4203 Location* loc = find_location_from_marker (entered_marker, ignored);
4205 if (_session && loc) {
4206 entered_marker = NULL;
4207 Glib::signal_idle().connect (sigc::bind (sigc::mem_fun(*this, &Editor::really_remove_marker), loc));
4214 switch (mouse_mode) {
4217 begin_reversible_command (opname + ' ' + X_("MIDI"));
4219 commit_reversible_command ();
4225 bool did_edit = false;
4227 if (!selection->regions.empty() || !selection->points.empty()) {
4228 begin_reversible_command (opname + ' ' + _("objects"));
4231 if (!selection->regions.empty()) {
4232 cut_copy_regions (op, selection->regions);
4234 if (op == Cut || op == Delete) {
4235 selection->clear_regions ();
4239 if (!selection->points.empty()) {
4240 cut_copy_points (op);
4242 if (op == Cut || op == Delete) {
4243 selection->clear_points ();
4246 } else if (selection->time.empty()) {
4247 framepos_t start, end;
4248 /* no time selection, see if we can get an edit range
4251 if (get_edit_op_range (start, end)) {
4252 selection->set (start, end);
4254 } else if (!selection->time.empty()) {
4255 begin_reversible_command (opname + ' ' + _("range"));
4258 cut_copy_ranges (op);
4260 if (op == Cut || op == Delete) {
4261 selection->clear_time ();
4266 /* reset repeated paste state */
4269 commit_reversible_command ();
4272 if (op == Delete || op == Cut || op == Clear) {
4278 struct AutomationRecord {
4279 AutomationRecord () : state (0) , line(NULL) {}
4280 AutomationRecord (XMLNode* s, const AutomationLine* l) : state (s) , line (l) {}
4282 XMLNode* state; ///< state before any operation
4283 const AutomationLine* line; ///< line this came from
4284 boost::shared_ptr<Evoral::ControlList> copy; ///< copied events for the cut buffer
4287 struct PointsSelectionPositionSorter {
4288 bool operator() (ControlPoint* a, ControlPoint* b) {
4289 return (*(a->model()))->when < (*(b->model()))->when;
4293 /** Cut, copy or clear selected automation points.
4294 * @param op Operation (Cut, Copy or Clear)
4297 Editor::cut_copy_points (Editing::CutCopyOp op, Evoral::Beats earliest, bool midi)
4299 if (selection->points.empty ()) {
4303 /* XXX: not ideal, as there may be more than one track involved in the point selection */
4304 _last_cut_copy_source_track = &selection->points.front()->line().trackview;
4306 /* Keep a record of the AutomationLists that we end up using in this operation */
4307 typedef std::map<boost::shared_ptr<AutomationList>, AutomationRecord> Lists;
4310 /* user could select points in any order */
4311 selection->points.sort(PointsSelectionPositionSorter ());
4313 /* Go through all selected points, making an AutomationRecord for each distinct AutomationList */
4314 for (PointSelection::iterator sel_point = selection->points.begin(); sel_point != selection->points.end(); ++sel_point) {
4315 const AutomationLine& line = (*sel_point)->line();
4316 const boost::shared_ptr<AutomationList> al = line.the_list();
4317 if (lists.find (al) == lists.end ()) {
4318 /* We haven't seen this list yet, so make a record for it. This includes
4319 taking a copy of its current state, in case this is needed for undo later.
4321 lists[al] = AutomationRecord (&al->get_state (), &line);
4325 if (op == Cut || op == Copy) {
4326 /* This operation will involve putting things in the cut buffer, so create an empty
4327 ControlList for each of our source lists to put the cut buffer data in.
4329 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
4330 i->second.copy = i->first->create (i->first->parameter (), i->first->descriptor());
4333 /* Add all selected points to the relevant copy ControlLists */
4334 MusicFrame start (std::numeric_limits<framepos_t>::max(), 0);
4335 for (PointSelection::iterator sel_point = selection->points.begin(); sel_point != selection->points.end(); ++sel_point) {
4336 boost::shared_ptr<AutomationList> al = (*sel_point)->line().the_list();
4337 AutomationList::const_iterator ctrl_evt = (*sel_point)->model ();
4339 lists[al].copy->fast_simple_add ((*ctrl_evt)->when, (*ctrl_evt)->value);
4341 /* Update earliest MIDI start time in beats */
4342 earliest = std::min(earliest, Evoral::Beats((*ctrl_evt)->when));
4344 /* Update earliest session start time in frames */
4345 start.frame = std::min(start.frame, (*sel_point)->line().session_position(ctrl_evt));
4349 /* Snap start time backwards, so copy/paste is snap aligned. */
4351 if (earliest == Evoral::Beats::max()) {
4352 earliest = Evoral::Beats(); // Weird... don't offset
4354 earliest.round_down_to_beat();
4356 if (start.frame == std::numeric_limits<double>::max()) {
4357 start.frame = 0; // Weird... don't offset
4359 snap_to(start, RoundDownMaybe);
4362 const double line_offset = midi ? earliest.to_double() : start.frame;
4363 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
4364 /* Correct this copy list so that it is relative to the earliest
4365 start time, so relative ordering between points is preserved
4366 when copying from several lists and the paste starts at the
4367 earliest copied piece of data. */
4368 boost::shared_ptr<Evoral::ControlList> &al_cpy = i->second.copy;
4369 for (AutomationList::iterator ctrl_evt = al_cpy->begin(); ctrl_evt != al_cpy->end(); ++ctrl_evt) {
4370 (*ctrl_evt)->when -= line_offset;
4373 /* And add it to the cut buffer */
4374 cut_buffer->add (al_cpy);
4378 if (op == Delete || op == Cut) {
4379 /* This operation needs to remove things from the main AutomationList, so do that now */
4381 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
4382 i->first->freeze ();
4385 /* Remove each selected point from its AutomationList */
4386 for (PointSelection::iterator sel_point = selection->points.begin(); sel_point != selection->points.end(); ++sel_point) {
4387 AutomationLine& line = (*sel_point)->line ();
4388 boost::shared_ptr<AutomationList> al = line.the_list();
4392 if (dynamic_cast<AudioRegionGainLine*> (&line)) {
4393 /* removing of first and last gain point in region gain lines is prohibited*/
4394 if (line.is_last_point (*(*sel_point)) || line.is_first_point (*(*sel_point))) {
4400 al->erase ((*sel_point)->model ());
4404 /* Thaw the lists and add undo records for them */
4405 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
4406 boost::shared_ptr<AutomationList> al = i->first;
4408 _session->add_command (new MementoCommand<AutomationList> (*al.get(), i->second.state, &(al->get_state ())));
4413 /** Cut, copy or clear selected automation points.
4414 * @param op Operation (Cut, Copy or Clear)
4417 Editor::cut_copy_midi (CutCopyOp op)
4419 Evoral::Beats earliest = Evoral::Beats::max();
4420 for (MidiRegionSelection::iterator i = selection->midi_regions.begin(); i != selection->midi_regions.end(); ++i) {
4421 MidiRegionView* mrv = dynamic_cast<MidiRegionView*>(*i);
4423 if (!mrv->selection().empty()) {
4424 earliest = std::min(earliest, (*mrv->selection().begin())->note()->time());
4426 mrv->cut_copy_clear (op);
4428 /* XXX: not ideal, as there may be more than one track involved in the selection */
4429 _last_cut_copy_source_track = &mrv->get_time_axis_view();
4433 if (!selection->points.empty()) {
4434 cut_copy_points (op, earliest, true);
4435 if (op == Cut || op == Delete) {
4436 selection->clear_points ();
4441 struct lt_playlist {
4442 bool operator () (const PlaylistState& a, const PlaylistState& b) {
4443 return a.playlist < b.playlist;
4447 struct PlaylistMapping {
4449 boost::shared_ptr<Playlist> pl;
4451 PlaylistMapping (TimeAxisView* tvp) : tv (tvp) {}
4454 /** Remove `clicked_regionview' */
4456 Editor::remove_clicked_region ()
4458 if (clicked_routeview == 0 || clicked_regionview == 0) {
4462 begin_reversible_command (_("remove region"));
4464 boost::shared_ptr<Playlist> playlist = clicked_routeview->playlist();
4466 playlist->clear_changes ();
4467 playlist->clear_owned_changes ();
4468 playlist->remove_region (clicked_regionview->region());
4469 if (Config->get_edit_mode() == Ripple)
4470 playlist->ripple (clicked_regionview->region()->position(), -clicked_regionview->region()->length(), boost::shared_ptr<Region>());
4472 /* We might have removed regions, which alters other regions' layering_index,
4473 so we need to do a recursive diff here.
4475 vector<Command*> cmds;
4476 playlist->rdiff (cmds);
4477 _session->add_commands (cmds);
4479 _session->add_command(new StatefulDiffCommand (playlist));
4480 commit_reversible_command ();
4484 /** Remove the selected regions */
4486 Editor::remove_selected_regions ()
4488 RegionSelection rs = get_regions_from_selection_and_entered ();
4490 if (!_session || rs.empty()) {
4494 list<boost::shared_ptr<Region> > regions_to_remove;
4496 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
4497 // we can't just remove the region(s) in this loop because
4498 // this removes them from the RegionSelection, and they thus
4499 // disappear from underneath the iterator, and the ++i above
4500 // SEGVs in a puzzling fashion.
4502 // so, first iterate over the regions to be removed from rs and
4503 // add them to the regions_to_remove list, and then
4504 // iterate over the list to actually remove them.
4506 regions_to_remove.push_back ((*i)->region());
4509 vector<boost::shared_ptr<Playlist> > playlists;
4511 for (list<boost::shared_ptr<Region> >::iterator rl = regions_to_remove.begin(); rl != regions_to_remove.end(); ++rl) {
4513 boost::shared_ptr<Playlist> playlist = (*rl)->playlist();
4516 // is this check necessary?
4520 /* get_regions_from_selection_and_entered() guarantees that
4521 the playlists involved are unique, so there is no need
4525 playlists.push_back (playlist);
4527 playlist->clear_changes ();
4528 playlist->clear_owned_changes ();
4529 playlist->freeze ();
4530 playlist->remove_region (*rl);
4531 if (Config->get_edit_mode() == Ripple)
4532 playlist->ripple ((*rl)->position(), -(*rl)->length(), boost::shared_ptr<Region>());
4536 vector<boost::shared_ptr<Playlist> >::iterator pl;
4537 bool in_command = false;
4539 for (pl = playlists.begin(); pl != playlists.end(); ++pl) {
4542 /* We might have removed regions, which alters other regions' layering_index,
4543 so we need to do a recursive diff here.
4547 begin_reversible_command (_("remove region"));
4550 vector<Command*> cmds;
4551 (*pl)->rdiff (cmds);
4552 _session->add_commands (cmds);
4554 _session->add_command(new StatefulDiffCommand (*pl));
4558 commit_reversible_command ();
4562 /** Cut, copy or clear selected regions.
4563 * @param op Operation (Cut, Copy or Clear)
4566 Editor::cut_copy_regions (CutCopyOp op, RegionSelection& rs)
4568 /* we can't use a std::map here because the ordering is important, and we can't trivially sort
4569 a map when we want ordered access to both elements. i think.
4572 vector<PlaylistMapping> pmap;
4574 framepos_t first_position = max_framepos;
4576 typedef set<boost::shared_ptr<Playlist> > FreezeList;
4577 FreezeList freezelist;
4579 /* get ordering correct before we cut/copy */
4581 rs.sort_by_position_and_track ();
4583 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
4585 first_position = min ((framepos_t) (*x)->region()->position(), first_position);
4587 if (op == Cut || op == Clear || op == Delete) {
4588 boost::shared_ptr<Playlist> pl = (*x)->region()->playlist();
4591 FreezeList::iterator fl;
4593 // only take state if this is a new playlist.
4594 for (fl = freezelist.begin(); fl != freezelist.end(); ++fl) {
4600 if (fl == freezelist.end()) {
4601 pl->clear_changes();
4602 pl->clear_owned_changes ();
4604 freezelist.insert (pl);
4609 TimeAxisView* tv = &(*x)->get_time_axis_view();
4610 vector<PlaylistMapping>::iterator z;
4612 for (z = pmap.begin(); z != pmap.end(); ++z) {
4613 if ((*z).tv == tv) {
4618 if (z == pmap.end()) {
4619 pmap.push_back (PlaylistMapping (tv));
4623 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ) {
4625 boost::shared_ptr<Playlist> pl = (*x)->region()->playlist();
4628 /* region not yet associated with a playlist (e.g. unfinished
4635 TimeAxisView& tv = (*x)->get_time_axis_view();
4636 boost::shared_ptr<Playlist> npl;
4637 RegionSelection::iterator tmp;
4644 vector<PlaylistMapping>::iterator z;
4646 for (z = pmap.begin(); z != pmap.end(); ++z) {
4647 if ((*z).tv == &tv) {
4652 assert (z != pmap.end());
4655 npl = PlaylistFactory::create (pl->data_type(), *_session, "cutlist", true);
4663 boost::shared_ptr<Region> r = (*x)->region();
4664 boost::shared_ptr<Region> _xx;
4670 pl->remove_region (r);
4671 if (Config->get_edit_mode() == Ripple)
4672 pl->ripple (r->position(), -r->length(), boost::shared_ptr<Region>());
4676 _xx = RegionFactory::create (r);
4677 npl->add_region (_xx, r->position() - first_position);
4678 pl->remove_region (r);
4679 if (Config->get_edit_mode() == Ripple)
4680 pl->ripple (r->position(), -r->length(), boost::shared_ptr<Region>());
4684 /* copy region before adding, so we're not putting same object into two different playlists */
4685 npl->add_region (RegionFactory::create (r), r->position() - first_position);
4689 pl->remove_region (r);
4690 if (Config->get_edit_mode() == Ripple)
4691 pl->ripple (r->position(), -r->length(), boost::shared_ptr<Region>());
4700 list<boost::shared_ptr<Playlist> > foo;
4702 /* the pmap is in the same order as the tracks in which selected regions occurred */
4704 for (vector<PlaylistMapping>::iterator i = pmap.begin(); i != pmap.end(); ++i) {
4707 foo.push_back ((*i).pl);
4712 cut_buffer->set (foo);
4716 _last_cut_copy_source_track = 0;
4718 _last_cut_copy_source_track = pmap.front().tv;
4722 for (FreezeList::iterator pl = freezelist.begin(); pl != freezelist.end(); ++pl) {
4725 /* We might have removed regions, which alters other regions' layering_index,
4726 so we need to do a recursive diff here.
4728 vector<Command*> cmds;
4729 (*pl)->rdiff (cmds);
4730 _session->add_commands (cmds);
4732 _session->add_command (new StatefulDiffCommand (*pl));
4737 Editor::cut_copy_ranges (CutCopyOp op)
4739 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4741 /* Sort the track selection now, so that it if is used, the playlists
4742 selected by the calls below to cut_copy_clear are in the order that
4743 their tracks appear in the editor. This makes things like paste
4744 of ranges work properly.
4747 sort_track_selection (ts);
4750 if (!entered_track) {
4753 ts.push_back (entered_track);
4756 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4757 (*i)->cut_copy_clear (*selection, op);
4762 Editor::paste (float times, bool from_context)
4764 DEBUG_TRACE (DEBUG::CutNPaste, "paste to preferred edit pos\n");
4765 MusicFrame where (get_preferred_edit_position (EDIT_IGNORE_NONE, from_context), 0);
4766 paste_internal (where.frame, times, 0);
4770 Editor::mouse_paste ()
4772 MusicFrame where (0, 0);
4774 if (!mouse_frame (where.frame, ignored)) {
4779 paste_internal (where.frame, 1, where.division);
4783 Editor::paste_internal (framepos_t position, float times, const int32_t sub_num)
4785 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("apparent paste position is %1\n", position));
4787 if (cut_buffer->empty(internal_editing())) {
4791 if (position == max_framepos) {
4792 position = get_preferred_edit_position();
4793 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("preferred edit position is %1\n", position));
4796 if (position == last_paste_pos) {
4797 /* repeated paste in the same position */
4800 /* paste in new location, reset repeated paste state */
4802 last_paste_pos = position;
4805 /* get everything in the correct order */
4808 if (!selection->tracks.empty()) {
4809 /* If there is a track selection, paste into exactly those tracks and
4810 * only those tracks. This allows the user to be explicit and override
4811 * the below "do the reasonable thing" logic. */
4812 ts = selection->tracks.filter_to_unique_playlists ();
4813 sort_track_selection (ts);
4815 /* Figure out which track to base the paste at. */
4816 TimeAxisView* base_track = NULL;
4817 if (_edit_point == Editing::EditAtMouse && entered_track) {
4818 /* With the mouse edit point, paste onto the track under the mouse. */
4819 base_track = entered_track;
4820 } else if (_edit_point == Editing::EditAtMouse && entered_regionview) {
4821 /* With the mouse edit point, paste onto the track of the region under the mouse. */
4822 base_track = &entered_regionview->get_time_axis_view();
4823 } else if (_last_cut_copy_source_track) {
4824 /* Paste to the track that the cut/copy came from (see mantis #333). */
4825 base_track = _last_cut_copy_source_track;
4827 /* This is "impossible" since we've copied... well, do nothing. */
4831 /* Walk up to parent if necessary, so base track is a route. */
4832 while (base_track->get_parent()) {
4833 base_track = base_track->get_parent();
4836 /* Add base track and all tracks below it. The paste logic will select
4837 the appropriate object types from the cut buffer in relative order. */
4838 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4839 if ((*i)->order() >= base_track->order()) {
4844 /* Sort tracks so the nth track of type T will pick the nth object of type T. */
4845 sort_track_selection (ts);
4847 /* Add automation children of each track in order, for pasting several lines. */
4848 for (TrackViewList::iterator i = ts.begin(); i != ts.end();) {
4849 /* Add any automation children for pasting several lines */
4850 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*i++);
4855 typedef RouteTimeAxisView::AutomationTracks ATracks;
4856 const ATracks& atracks = rtv->automation_tracks();
4857 for (ATracks::const_iterator a = atracks.begin(); a != atracks.end(); ++a) {
4858 i = ts.insert(i, a->second.get());
4863 /* We now have a list of trackviews starting at base_track, including
4864 automation children, in the order shown in the editor, e.g. R1,
4865 R1.A1, R1.A2, R2, R2.A1, ... */
4868 begin_reversible_command (Operations::paste);
4870 if (ts.size() == 1 && cut_buffer->lines.size() == 1 &&
4871 dynamic_cast<AutomationTimeAxisView*>(ts.front())) {
4872 /* Only one line copied, and one automation track selected. Do a
4873 "greedy" paste from one automation type to another. */
4875 PasteContext ctx(paste_count, times, ItemCounts(), true);
4876 ts.front()->paste (position, *cut_buffer, ctx, sub_num);
4880 /* Paste into tracks */
4882 PasteContext ctx(paste_count, times, ItemCounts(), false);
4883 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4884 (*i)->paste (position, *cut_buffer, ctx, sub_num);
4888 commit_reversible_command ();
4892 Editor::duplicate_regions (float times)
4894 RegionSelection rs (get_regions_from_selection_and_entered());
4895 duplicate_some_regions (rs, times);
4899 Editor::duplicate_some_regions (RegionSelection& regions, float times)
4901 if (regions.empty ()) {
4905 boost::shared_ptr<Playlist> playlist;
4906 RegionSelection sel = regions; // clear (below) may clear the argument list if its the current region selection
4907 RegionSelection foo;
4909 framepos_t const start_frame = regions.start ();
4910 framepos_t const end_frame = regions.end_frame ();
4911 framecnt_t const gap = end_frame - start_frame + 1;
4913 begin_reversible_command (Operations::duplicate_region);
4915 selection->clear_regions ();
4917 for (RegionSelection::iterator i = sel.begin(); i != sel.end(); ++i) {
4919 boost::shared_ptr<Region> r ((*i)->region());
4921 TimeAxisView& tv = (*i)->get_time_axis_view();
4922 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (&tv);
4923 latest_regionviews.clear ();
4924 sigc::connection c = rtv->view()->RegionViewAdded.connect (sigc::mem_fun(*this, &Editor::collect_new_region_view));
4926 framepos_t const position = end_frame + (r->first_frame() - start_frame + 1);
4927 playlist = (*i)->region()->playlist();
4928 playlist->clear_changes ();
4929 playlist->duplicate (r, position, gap, times);
4930 _session->add_command(new StatefulDiffCommand (playlist));
4934 foo.insert (foo.end(), latest_regionviews.begin(), latest_regionviews.end());
4938 selection->set (foo);
4941 commit_reversible_command ();
4945 Editor::duplicate_selection (float times)
4947 if (selection->time.empty() || selection->tracks.empty()) {
4951 boost::shared_ptr<Playlist> playlist;
4953 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4955 bool in_command = false;
4957 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4958 if ((playlist = (*i)->playlist()) == 0) {
4961 playlist->clear_changes ();
4963 if (clicked_selection) {
4964 playlist->duplicate_range (selection->time[clicked_selection], times);
4966 playlist->duplicate_ranges (selection->time, times);
4970 begin_reversible_command (_("duplicate range selection"));
4973 _session->add_command (new StatefulDiffCommand (playlist));
4978 if (times == 1.0f) {
4979 // now "move" range selection to after the current range selection
4980 framecnt_t distance = 0;
4982 if (clicked_selection) {
4984 selection->time[clicked_selection].end - selection->time[clicked_selection].start;
4986 distance = selection->time.end_frame () - selection->time.start ();
4989 selection->move_time (distance);
4991 commit_reversible_command ();
4995 /** Reset all selected points to the relevant default value */
4997 Editor::reset_point_selection ()
4999 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
5000 ARDOUR::AutomationList::iterator j = (*i)->model ();
5001 (*j)->value = (*i)->line().the_list()->descriptor ().normal;
5006 Editor::center_playhead ()
5008 float const page = _visible_canvas_width * samples_per_pixel;
5009 center_screen_internal (playhead_cursor->current_frame (), page);
5013 Editor::center_edit_point ()
5015 float const page = _visible_canvas_width * samples_per_pixel;
5016 center_screen_internal (get_preferred_edit_position(), page);
5019 /** Caller must begin and commit a reversible command */
5021 Editor::clear_playlist (boost::shared_ptr<Playlist> playlist)
5023 playlist->clear_changes ();
5025 _session->add_command (new StatefulDiffCommand (playlist));
5029 Editor::nudge_track (bool use_edit, bool forwards)
5031 boost::shared_ptr<Playlist> playlist;
5032 framepos_t distance;
5033 framepos_t next_distance;
5037 start = get_preferred_edit_position();
5042 if ((distance = get_nudge_distance (start, next_distance)) == 0) {
5046 if (selection->tracks.empty()) {
5050 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
5051 bool in_command = false;
5053 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
5055 if ((playlist = (*i)->playlist()) == 0) {
5059 playlist->clear_changes ();
5060 playlist->clear_owned_changes ();
5062 playlist->nudge_after (start, distance, forwards);
5065 begin_reversible_command (_("nudge track"));
5068 vector<Command*> cmds;
5070 playlist->rdiff (cmds);
5071 _session->add_commands (cmds);
5073 _session->add_command (new StatefulDiffCommand (playlist));
5077 commit_reversible_command ();
5082 Editor::remove_last_capture ()
5084 vector<string> choices;
5091 if (Config->get_verify_remove_last_capture()) {
5092 prompt = _("Do you really want to destroy the last capture?"
5093 "\n(This is destructive and cannot be undone)");
5095 choices.push_back (_("No, do nothing."));
5096 choices.push_back (_("Yes, destroy it."));
5098 Choice prompter (_("Destroy last capture"), prompt, choices);
5100 if (prompter.run () == 1) {
5101 _session->remove_last_capture ();
5102 _regions->redisplay ();
5106 _session->remove_last_capture();
5107 _regions->redisplay ();
5112 Editor::normalize_region ()
5118 RegionSelection rs = get_regions_from_selection_and_entered ();
5124 NormalizeDialog dialog (rs.size() > 1);
5126 if (dialog.run () != RESPONSE_ACCEPT) {
5130 CursorContext::Handle cursor_ctx = CursorContext::create(*this, _cursors->wait);
5133 /* XXX: should really only count audio regions here */
5134 int const regions = rs.size ();
5136 /* Make a list of the selected audio regions' maximum amplitudes, and also
5137 obtain the maximum amplitude of them all.
5139 list<double> max_amps;
5140 list<double> rms_vals;
5143 bool use_rms = dialog.constrain_rms ();
5145 for (RegionSelection::const_iterator i = rs.begin(); i != rs.end(); ++i) {
5146 AudioRegionView const * arv = dynamic_cast<AudioRegionView const *> (*i);
5150 dialog.descend (1.0 / regions);
5151 double const a = arv->audio_region()->maximum_amplitude (&dialog);
5153 double r = arv->audio_region()->rms (&dialog);
5154 max_rms = max (max_rms, r);
5155 rms_vals.push_back (r);
5159 /* the user cancelled the operation */
5163 max_amps.push_back (a);
5164 max_amp = max (max_amp, a);
5168 list<double>::const_iterator a = max_amps.begin ();
5169 list<double>::const_iterator l = rms_vals.begin ();
5170 bool in_command = false;
5172 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
5173 AudioRegionView* const arv = dynamic_cast<AudioRegionView*> (*r);
5178 arv->region()->clear_changes ();
5180 double amp = dialog.normalize_individually() ? *a : max_amp;
5181 double target = dialog.target_peak (); // dB
5184 double const amp_rms = dialog.normalize_individually() ? *l : max_rms;
5185 const double t_rms = dialog.target_rms ();
5186 const gain_t c_peak = dB_to_coefficient (target);
5187 const gain_t c_rms = dB_to_coefficient (t_rms);
5188 if ((amp_rms / c_rms) > (amp / c_peak)) {
5194 arv->audio_region()->normalize (amp, target);
5197 begin_reversible_command (_("normalize"));
5200 _session->add_command (new StatefulDiffCommand (arv->region()));
5207 commit_reversible_command ();
5213 Editor::reset_region_scale_amplitude ()
5219 RegionSelection rs = get_regions_from_selection_and_entered ();
5225 bool in_command = false;
5227 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
5228 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
5231 arv->region()->clear_changes ();
5232 arv->audio_region()->set_scale_amplitude (1.0f);
5235 begin_reversible_command ("reset gain");
5238 _session->add_command (new StatefulDiffCommand (arv->region()));
5242 commit_reversible_command ();
5247 Editor::adjust_region_gain (bool up)
5249 RegionSelection rs = get_regions_from_selection_and_entered ();
5251 if (!_session || rs.empty()) {
5255 bool in_command = false;
5257 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
5258 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
5263 arv->region()->clear_changes ();
5265 double dB = accurate_coefficient_to_dB (arv->audio_region()->scale_amplitude ());
5273 arv->audio_region()->set_scale_amplitude (dB_to_coefficient (dB));
5276 begin_reversible_command ("adjust region gain");
5279 _session->add_command (new StatefulDiffCommand (arv->region()));
5283 commit_reversible_command ();
5288 Editor::reset_region_gain ()
5290 RegionSelection rs = get_regions_from_selection_and_entered ();
5292 if (!_session || rs.empty()) {
5296 bool in_command = false;
5298 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
5299 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
5304 arv->region()->clear_changes ();
5306 arv->audio_region()->set_scale_amplitude (1.0f);
5309 begin_reversible_command ("reset region gain");
5312 _session->add_command (new StatefulDiffCommand (arv->region()));
5316 commit_reversible_command ();
5321 Editor::reverse_region ()
5327 Reverse rev (*_session);
5328 apply_filter (rev, _("reverse regions"));
5332 Editor::strip_region_silence ()
5338 RegionSelection rs = get_regions_from_selection_and_entered ();
5344 std::list<RegionView*> audio_only;
5346 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5347 AudioRegionView* const arv = dynamic_cast<AudioRegionView*> (*i);
5349 audio_only.push_back (arv);
5353 assert (!audio_only.empty());
5355 StripSilenceDialog d (_session, audio_only);
5356 int const r = d.run ();
5360 if (r == Gtk::RESPONSE_OK) {
5361 ARDOUR::AudioIntervalMap silences;
5362 d.silences (silences);
5363 StripSilence s (*_session, silences, d.fade_length());
5365 apply_filter (s, _("strip silence"), &d);
5370 Editor::apply_midi_note_edit_op_to_region (MidiOperator& op, MidiRegionView& mrv)
5372 Evoral::Sequence<Evoral::Beats>::Notes selected;
5373 mrv.selection_as_notelist (selected, true);
5375 vector<Evoral::Sequence<Evoral::Beats>::Notes> v;
5376 v.push_back (selected);
5378 Evoral::Beats pos_beats = Evoral::Beats (mrv.midi_region()->beat()) - mrv.midi_region()->start_beats();
5380 return op (mrv.midi_region()->model(), pos_beats, v);
5384 Editor::apply_midi_note_edit_op (MidiOperator& op, const RegionSelection& rs)
5390 bool in_command = false;
5392 for (RegionSelection::const_iterator r = rs.begin(); r != rs.end(); ) {
5393 RegionSelection::const_iterator tmp = r;
5396 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*r);
5399 Command* cmd = apply_midi_note_edit_op_to_region (op, *mrv);
5402 begin_reversible_command (op.name ());
5406 _session->add_command (cmd);
5414 commit_reversible_command ();
5419 Editor::fork_region ()
5421 RegionSelection rs = get_regions_from_selection_and_entered ();
5427 CursorContext::Handle cursor_ctx = CursorContext::create(*this, _cursors->wait);
5428 bool in_command = false;
5432 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
5433 RegionSelection::iterator tmp = r;
5436 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*>(*r);
5440 boost::shared_ptr<Playlist> playlist = mrv->region()->playlist();
5441 boost::shared_ptr<MidiSource> new_source = _session->create_midi_source_by_stealing_name (mrv->midi_view()->track());
5442 boost::shared_ptr<MidiRegion> newregion = mrv->midi_region()->clone (new_source);
5445 begin_reversible_command (_("Fork Region(s)"));
5448 playlist->clear_changes ();
5449 playlist->replace_region (mrv->region(), newregion, mrv->region()->position());
5450 _session->add_command(new StatefulDiffCommand (playlist));
5452 error << string_compose (_("Could not unlink %1"), mrv->region()->name()) << endmsg;
5460 commit_reversible_command ();
5465 Editor::quantize_region ()
5468 quantize_regions(get_regions_from_selection_and_entered ());
5473 Editor::quantize_regions (const RegionSelection& rs)
5475 if (rs.n_midi_regions() == 0) {
5479 if (!quantize_dialog) {
5480 quantize_dialog = new QuantizeDialog (*this);
5483 if (quantize_dialog->is_mapped()) {
5484 /* in progress already */
5488 quantize_dialog->present ();
5489 const int r = quantize_dialog->run ();
5490 quantize_dialog->hide ();
5492 if (r == Gtk::RESPONSE_OK) {
5493 Quantize quant (quantize_dialog->snap_start(),
5494 quantize_dialog->snap_end(),
5495 quantize_dialog->start_grid_size(),
5496 quantize_dialog->end_grid_size(),
5497 quantize_dialog->strength(),
5498 quantize_dialog->swing(),
5499 quantize_dialog->threshold());
5501 apply_midi_note_edit_op (quant, rs);
5506 Editor::legatize_region (bool shrink_only)
5509 legatize_regions(get_regions_from_selection_and_entered (), shrink_only);
5514 Editor::legatize_regions (const RegionSelection& rs, bool shrink_only)
5516 if (rs.n_midi_regions() == 0) {
5520 Legatize legatize(shrink_only);
5521 apply_midi_note_edit_op (legatize, rs);
5525 Editor::transform_region ()
5528 transform_regions(get_regions_from_selection_and_entered ());
5533 Editor::transform_regions (const RegionSelection& rs)
5535 if (rs.n_midi_regions() == 0) {
5542 const int r = td.run();
5545 if (r == Gtk::RESPONSE_OK) {
5546 Transform transform(td.get());
5547 apply_midi_note_edit_op(transform, rs);
5552 Editor::transpose_region ()
5555 transpose_regions(get_regions_from_selection_and_entered ());
5560 Editor::transpose_regions (const RegionSelection& rs)
5562 if (rs.n_midi_regions() == 0) {
5567 int const r = d.run ();
5569 if (r == RESPONSE_ACCEPT) {
5570 Transpose transpose(d.semitones ());
5571 apply_midi_note_edit_op (transpose, rs);
5576 Editor::insert_patch_change (bool from_context)
5578 RegionSelection rs = get_regions_from_selection_and_entered ();
5584 const framepos_t p = get_preferred_edit_position (EDIT_IGNORE_NONE, from_context);
5586 /* XXX: bit of a hack; use the MIDNAM from the first selected region;
5587 there may be more than one, but the PatchChangeDialog can only offer
5588 one set of patch menus.
5590 MidiRegionView* first = dynamic_cast<MidiRegionView*> (rs.front ());
5592 Evoral::PatchChange<Evoral::Beats> empty (Evoral::Beats(), 0, 0, 0);
5593 PatchChangeDialog d (0, _session, empty, first->instrument_info(), Gtk::Stock::ADD);
5595 if (d.run() == RESPONSE_CANCEL) {
5599 for (RegionSelection::iterator i = rs.begin (); i != rs.end(); ++i) {
5600 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*i);
5602 if (p >= mrv->region()->first_frame() && p <= mrv->region()->last_frame()) {
5603 mrv->add_patch_change (p - mrv->region()->position(), d.patch ());
5610 Editor::apply_filter (Filter& filter, string command, ProgressReporter* progress)
5612 RegionSelection rs = get_regions_from_selection_and_entered ();
5618 CursorContext::Handle cursor_ctx = CursorContext::create(*this, _cursors->wait);
5619 bool in_command = false;
5624 int const N = rs.size ();
5626 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
5627 RegionSelection::iterator tmp = r;
5630 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
5632 boost::shared_ptr<Playlist> playlist = arv->region()->playlist();
5635 progress->descend (1.0 / N);
5638 if (arv->audio_region()->apply (filter, progress) == 0) {
5640 playlist->clear_changes ();
5641 playlist->clear_owned_changes ();
5644 begin_reversible_command (command);
5648 if (filter.results.empty ()) {
5650 /* no regions returned; remove the old one */
5651 playlist->remove_region (arv->region ());
5655 std::vector<boost::shared_ptr<Region> >::iterator res = filter.results.begin ();
5657 /* first region replaces the old one */
5658 playlist->replace_region (arv->region(), *res, (*res)->position());
5662 while (res != filter.results.end()) {
5663 playlist->add_region (*res, (*res)->position());
5669 /* We might have removed regions, which alters other regions' layering_index,
5670 so we need to do a recursive diff here.
5672 vector<Command*> cmds;
5673 playlist->rdiff (cmds);
5674 _session->add_commands (cmds);
5676 _session->add_command(new StatefulDiffCommand (playlist));
5680 progress->ascend ();
5689 commit_reversible_command ();
5694 Editor::external_edit_region ()
5700 Editor::reset_region_gain_envelopes ()
5702 RegionSelection rs = get_regions_from_selection_and_entered ();
5704 if (!_session || rs.empty()) {
5708 bool in_command = false;
5710 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5711 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
5713 boost::shared_ptr<AutomationList> alist (arv->audio_region()->envelope());
5714 XMLNode& before (alist->get_state());
5716 arv->audio_region()->set_default_envelope ();
5719 begin_reversible_command (_("reset region gain"));
5722 _session->add_command (new MementoCommand<AutomationList>(*arv->audio_region()->envelope().get(), &before, &alist->get_state()));
5727 commit_reversible_command ();
5732 Editor::set_region_gain_visibility (RegionView* rv)
5734 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (rv);
5736 arv->update_envelope_visibility();
5741 Editor::set_gain_envelope_visibility ()
5747 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5748 AudioTimeAxisView* v = dynamic_cast<AudioTimeAxisView*>(*i);
5750 v->audio_view()->foreach_regionview (sigc::mem_fun (this, &Editor::set_region_gain_visibility));
5756 Editor::toggle_gain_envelope_active ()
5758 if (_ignore_region_action) {
5762 RegionSelection rs = get_regions_from_selection_and_entered ();
5764 if (!_session || rs.empty()) {
5768 bool in_command = false;
5770 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5771 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
5773 arv->region()->clear_changes ();
5774 arv->audio_region()->set_envelope_active (!arv->audio_region()->envelope_active());
5777 begin_reversible_command (_("region gain envelope active"));
5780 _session->add_command (new StatefulDiffCommand (arv->region()));
5785 commit_reversible_command ();
5790 Editor::toggle_region_lock ()
5792 if (_ignore_region_action) {
5796 RegionSelection rs = get_regions_from_selection_and_entered ();
5798 if (!_session || rs.empty()) {
5802 begin_reversible_command (_("toggle region lock"));
5804 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5805 (*i)->region()->clear_changes ();
5806 (*i)->region()->set_locked (!(*i)->region()->locked());
5807 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5810 commit_reversible_command ();
5814 Editor::toggle_region_video_lock ()
5816 if (_ignore_region_action) {
5820 RegionSelection rs = get_regions_from_selection_and_entered ();
5822 if (!_session || rs.empty()) {
5826 begin_reversible_command (_("Toggle Video Lock"));
5828 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5829 (*i)->region()->clear_changes ();
5830 (*i)->region()->set_video_locked (!(*i)->region()->video_locked());
5831 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5834 commit_reversible_command ();
5838 Editor::toggle_region_lock_style ()
5840 if (_ignore_region_action) {
5844 RegionSelection rs = get_regions_from_selection_and_entered ();
5846 if (!_session || rs.empty()) {
5850 Glib::RefPtr<ToggleAction> a = Glib::RefPtr<ToggleAction>::cast_dynamic (_region_actions->get_action("toggle-region-lock-style"));
5851 vector<Widget*> proxies = a->get_proxies();
5852 Gtk::CheckMenuItem* cmi = dynamic_cast<Gtk::CheckMenuItem*> (proxies.front());
5856 begin_reversible_command (_("toggle region lock style"));
5858 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5859 (*i)->region()->clear_changes ();
5860 PositionLockStyle const ns = ((*i)->region()->position_lock_style() == AudioTime && !cmi->get_inconsistent()) ? MusicTime : AudioTime;
5861 (*i)->region()->set_position_lock_style (ns);
5862 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5865 commit_reversible_command ();
5869 Editor::toggle_opaque_region ()
5871 if (_ignore_region_action) {
5875 RegionSelection rs = get_regions_from_selection_and_entered ();
5877 if (!_session || rs.empty()) {
5881 begin_reversible_command (_("change region opacity"));
5883 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5884 (*i)->region()->clear_changes ();
5885 (*i)->region()->set_opaque (!(*i)->region()->opaque());
5886 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5889 commit_reversible_command ();
5893 Editor::toggle_record_enable ()
5895 bool new_state = false;
5897 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5898 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5901 if (!rtav->is_track())
5905 new_state = !rtav->track()->rec_enable_control()->get_value();
5909 rtav->track()->rec_enable_control()->set_value (new_state, Controllable::UseGroup);
5914 Editor::toggle_solo ()
5916 bool new_state = false;
5918 boost::shared_ptr<ControlList> cl (new ControlList);
5920 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5921 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5928 new_state = !rtav->route()->soloed ();
5932 cl->push_back (rtav->route()->solo_control());
5935 _session->set_controls (cl, new_state ? 1.0 : 0.0, Controllable::UseGroup);
5939 Editor::toggle_mute ()
5941 bool new_state = false;
5943 boost::shared_ptr<RouteList> rl (new RouteList);
5945 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5946 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5953 new_state = !rtav->route()->muted();
5957 rl->push_back (rtav->route());
5960 _session->set_controls (route_list_to_control_list (rl, &Stripable::mute_control), new_state, Controllable::UseGroup);
5964 Editor::toggle_solo_isolate ()
5970 Editor::fade_range ()
5972 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
5974 begin_reversible_command (_("fade range"));
5976 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
5977 (*i)->fade_range (selection->time);
5980 commit_reversible_command ();
5985 Editor::set_fade_length (bool in)
5987 RegionSelection rs = get_regions_from_selection_and_entered ();
5993 /* we need a region to measure the offset from the start */
5995 RegionView* rv = rs.front ();
5997 framepos_t pos = get_preferred_edit_position();
6001 if (pos > rv->region()->last_frame() || pos < rv->region()->first_frame()) {
6002 /* edit point is outside the relevant region */
6007 if (pos <= rv->region()->position()) {
6011 len = pos - rv->region()->position();
6012 cmd = _("set fade in length");
6014 if (pos >= rv->region()->last_frame()) {
6018 len = rv->region()->last_frame() - pos;
6019 cmd = _("set fade out length");
6022 bool in_command = false;
6024 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
6025 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
6031 boost::shared_ptr<AutomationList> alist;
6033 alist = tmp->audio_region()->fade_in();
6035 alist = tmp->audio_region()->fade_out();
6038 XMLNode &before = alist->get_state();
6041 tmp->audio_region()->set_fade_in_length (len);
6042 tmp->audio_region()->set_fade_in_active (true);
6044 tmp->audio_region()->set_fade_out_length (len);
6045 tmp->audio_region()->set_fade_out_active (true);
6049 begin_reversible_command (cmd);
6052 XMLNode &after = alist->get_state();
6053 _session->add_command(new MementoCommand<AutomationList>(*alist, &before, &after));
6057 commit_reversible_command ();
6062 Editor::set_fade_in_shape (FadeShape shape)
6064 RegionSelection rs = get_regions_from_selection_and_entered ();
6069 bool in_command = false;
6071 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
6072 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
6078 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_in();
6079 XMLNode &before = alist->get_state();
6081 tmp->audio_region()->set_fade_in_shape (shape);
6084 begin_reversible_command (_("set fade in shape"));
6087 XMLNode &after = alist->get_state();
6088 _session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
6092 commit_reversible_command ();
6097 Editor::set_fade_out_shape (FadeShape shape)
6099 RegionSelection rs = get_regions_from_selection_and_entered ();
6104 bool in_command = false;
6106 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
6107 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
6113 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_out();
6114 XMLNode &before = alist->get_state();
6116 tmp->audio_region()->set_fade_out_shape (shape);
6119 begin_reversible_command (_("set fade out shape"));
6122 XMLNode &after = alist->get_state();
6123 _session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
6127 commit_reversible_command ();
6132 Editor::set_fade_in_active (bool yn)
6134 RegionSelection rs = get_regions_from_selection_and_entered ();
6139 bool in_command = false;
6141 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
6142 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
6149 boost::shared_ptr<AudioRegion> ar (tmp->audio_region());
6151 ar->clear_changes ();
6152 ar->set_fade_in_active (yn);
6155 begin_reversible_command (_("set fade in active"));
6158 _session->add_command (new StatefulDiffCommand (ar));
6162 commit_reversible_command ();
6167 Editor::set_fade_out_active (bool yn)
6169 RegionSelection rs = get_regions_from_selection_and_entered ();
6174 bool in_command = false;
6176 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
6177 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
6183 boost::shared_ptr<AudioRegion> ar (tmp->audio_region());
6185 ar->clear_changes ();
6186 ar->set_fade_out_active (yn);
6189 begin_reversible_command (_("set fade out active"));
6192 _session->add_command(new StatefulDiffCommand (ar));
6196 commit_reversible_command ();
6201 Editor::toggle_region_fades (int dir)
6203 if (_ignore_region_action) {
6207 boost::shared_ptr<AudioRegion> ar;
6210 RegionSelection rs = get_regions_from_selection_and_entered ();
6216 RegionSelection::iterator i;
6217 for (i = rs.begin(); i != rs.end(); ++i) {
6218 if ((ar = boost::dynamic_pointer_cast<AudioRegion>((*i)->region())) != 0) {
6220 yn = ar->fade_out_active ();
6222 yn = ar->fade_in_active ();
6228 if (i == rs.end()) {
6232 /* XXX should this undo-able? */
6233 bool in_command = false;
6235 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
6236 if ((ar = boost::dynamic_pointer_cast<AudioRegion>((*i)->region())) == 0) {
6239 ar->clear_changes ();
6241 if (dir == 1 || dir == 0) {
6242 ar->set_fade_in_active (!yn);
6245 if (dir == -1 || dir == 0) {
6246 ar->set_fade_out_active (!yn);
6249 begin_reversible_command (_("toggle fade active"));
6252 _session->add_command(new StatefulDiffCommand (ar));
6256 commit_reversible_command ();
6261 /** Update region fade visibility after its configuration has been changed */
6263 Editor::update_region_fade_visibility ()
6265 bool _fade_visibility = _session->config.get_show_region_fades ();
6267 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
6268 AudioTimeAxisView* v = dynamic_cast<AudioTimeAxisView*>(*i);
6270 if (_fade_visibility) {
6271 v->audio_view()->show_all_fades ();
6273 v->audio_view()->hide_all_fades ();
6280 Editor::set_edit_point ()
6283 MusicFrame where (0, 0);
6285 if (!mouse_frame (where.frame, ignored)) {
6291 if (selection->markers.empty()) {
6293 mouse_add_new_marker (where.frame);
6298 Location* loc = find_location_from_marker (selection->markers.front(), ignored);
6301 loc->move_to (where.frame, where.division);
6307 Editor::set_playhead_cursor ()
6309 if (entered_marker) {
6310 _session->request_locate (entered_marker->position(), _session->transport_rolling());
6312 MusicFrame where (0, 0);
6315 if (!mouse_frame (where.frame, ignored)) {
6322 _session->request_locate (where.frame, _session->transport_rolling());
6326 //not sure what this was for; remove it for now.
6327 // if (UIConfiguration::instance().get_follow_edits() && (!_session || !_session->config.get_external_sync())) {
6328 // cancel_time_selection();
6334 Editor::split_region ()
6336 if (_drags->active ()) {
6340 //if a range is selected, separate it
6341 if ( !selection->time.empty()) {
6342 separate_regions_between (selection->time);
6346 //if no range was selected, try to find some regions to split
6347 if (current_mouse_mode() == MouseObject) { //don't try this for Internal Edit, Stretch, Draw, etc.
6349 RegionSelection rs = get_regions_from_selection_and_edit_point ();
6350 const framepos_t pos = get_preferred_edit_position();
6351 const int32_t division = get_grid_music_divisions (0);
6352 MusicFrame where (pos, division);
6358 split_regions_at (where, rs);
6364 Editor::select_next_route()
6366 if (selection->tracks.empty()) {
6367 selection->set (track_views.front());
6371 TimeAxisView* current = selection->tracks.front();
6375 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
6377 if (*i == current) {
6379 if (i != track_views.end()) {
6382 current = (*(track_views.begin()));
6383 //selection->set (*(track_views.begin()));
6389 rui = dynamic_cast<RouteUI *>(current);
6391 } while (current->hidden() || (rui == NULL) || !rui->route()->active());
6393 selection->set (current);
6395 ensure_time_axis_view_is_visible (*current, false);
6399 Editor::select_prev_route()
6401 if (selection->tracks.empty()) {
6402 selection->set (track_views.front());
6406 TimeAxisView* current = selection->tracks.front();
6410 for (TrackViewList::reverse_iterator i = track_views.rbegin(); i != track_views.rend(); ++i) {
6412 if (*i == current) {
6414 if (i != track_views.rend()) {
6417 current = *(track_views.rbegin());
6422 rui = dynamic_cast<RouteUI *>(current);
6424 } while (current->hidden() || (rui == NULL) || !rui->route()->active());
6426 selection->set (current);
6428 ensure_time_axis_view_is_visible (*current, false);
6432 Editor::set_loop_from_selection (bool play)
6434 if (_session == 0) {
6438 framepos_t start, end;
6439 if (!get_selection_extents ( start, end))
6442 set_loop_range (start, end, _("set loop range from selection"));
6445 _session->request_play_loop (true, true);
6450 Editor::set_loop_from_region (bool play)
6452 framepos_t start, end;
6453 if (!get_selection_extents ( start, end))
6456 set_loop_range (start, end, _("set loop range from region"));
6459 _session->request_locate (start, true);
6460 _session->request_play_loop (true);
6465 Editor::set_punch_from_selection ()
6467 if (_session == 0) {
6471 framepos_t start, end;
6472 if (!get_selection_extents ( start, end))
6475 set_punch_range (start, end, _("set punch range from selection"));
6479 Editor::set_auto_punch_range ()
6481 // auto punch in/out button from a single button
6482 // If Punch In is unset, set punch range from playhead to end, enable punch in
6483 // If Punch In is set, the next punch sets Punch Out, unless the playhead has been
6484 // rewound beyond the Punch In marker, in which case that marker will be moved back
6485 // to the current playhead position.
6486 // If punch out is set, it clears the punch range and Punch In/Out buttons
6488 if (_session == 0) {
6492 Location* tpl = transport_punch_location();
6493 framepos_t now = playhead_cursor->current_frame();
6494 framepos_t begin = now;
6495 framepos_t end = _session->current_end_frame();
6497 if (!_session->config.get_punch_in()) {
6498 // First Press - set punch in and create range from here to eternity
6499 set_punch_range (begin, end, _("Auto Punch In"));
6500 _session->config.set_punch_in(true);
6501 } else if (tpl && !_session->config.get_punch_out()) {
6502 // Second press - update end range marker and set punch_out
6503 if (now < tpl->start()) {
6504 // playhead has been rewound - move start back and pretend nothing happened
6506 set_punch_range (begin, end, _("Auto Punch In/Out"));
6508 // normal case for 2nd press - set the punch out
6509 end = playhead_cursor->current_frame ();
6510 set_punch_range (tpl->start(), now, _("Auto Punch In/Out"));
6511 _session->config.set_punch_out(true);
6514 if (_session->config.get_punch_out()) {
6515 _session->config.set_punch_out(false);
6518 if (_session->config.get_punch_in()) {
6519 _session->config.set_punch_in(false);
6524 // third press - unset punch in/out and remove range
6525 _session->locations()->remove(tpl);
6532 Editor::set_session_extents_from_selection ()
6534 if (_session == 0) {
6538 framepos_t start, end;
6539 if (!get_selection_extents ( start, end))
6543 if ((loc = _session->locations()->session_range_location()) == 0) {
6544 _session->set_session_extents (start, end); // this will create a new session range; no need for UNDO
6546 XMLNode &before = loc->get_state();
6548 _session->set_session_extents (start, end);
6550 XMLNode &after = loc->get_state();
6552 begin_reversible_command (_("set session start/end from selection"));
6554 _session->add_command (new MementoCommand<Location>(*loc, &before, &after));
6556 commit_reversible_command ();
6559 _session->set_end_is_free (false);
6563 Editor::set_punch_start_from_edit_point ()
6567 MusicFrame start (0, 0);
6568 framepos_t end = max_framepos;
6570 //use the existing punch end, if any
6571 Location* tpl = transport_punch_location();
6576 if ((_edit_point == EditAtPlayhead) && _session->transport_rolling()) {
6577 start.frame = _session->audible_frame();
6579 start.frame = get_preferred_edit_position();
6582 //snap the selection start/end
6585 //if there's not already a sensible selection endpoint, go "forever"
6586 if (start.frame > end ) {
6590 set_punch_range (start.frame, end, _("set punch start from EP"));
6596 Editor::set_punch_end_from_edit_point ()
6600 framepos_t start = 0;
6601 MusicFrame end (max_framepos, 0);
6603 //use the existing punch start, if any
6604 Location* tpl = transport_punch_location();
6606 start = tpl->start();
6609 if ((_edit_point == EditAtPlayhead) && _session->transport_rolling()) {
6610 end.frame = _session->audible_frame();
6612 end.frame = get_preferred_edit_position();
6615 //snap the selection start/end
6618 set_punch_range (start, end.frame, _("set punch end from EP"));
6624 Editor::set_loop_start_from_edit_point ()
6628 MusicFrame start (0, 0);
6629 framepos_t end = max_framepos;
6631 //use the existing loop end, if any
6632 Location* tpl = transport_loop_location();
6637 if ((_edit_point == EditAtPlayhead) && _session->transport_rolling()) {
6638 start.frame = _session->audible_frame();
6640 start.frame = get_preferred_edit_position();
6643 //snap the selection start/end
6646 //if there's not already a sensible selection endpoint, go "forever"
6647 if (start.frame > end ) {
6651 set_loop_range (start.frame, end, _("set loop start from EP"));
6657 Editor::set_loop_end_from_edit_point ()
6661 framepos_t start = 0;
6662 MusicFrame end (max_framepos, 0);
6664 //use the existing loop start, if any
6665 Location* tpl = transport_loop_location();
6667 start = tpl->start();
6670 if ((_edit_point == EditAtPlayhead) && _session->transport_rolling()) {
6671 end.frame = _session->audible_frame();
6673 end.frame = get_preferred_edit_position();
6676 //snap the selection start/end
6679 set_loop_range (start, end.frame, _("set loop end from EP"));
6684 Editor::set_punch_from_region ()
6686 framepos_t start, end;
6687 if (!get_selection_extents ( start, end))
6690 set_punch_range (start, end, _("set punch range from region"));
6694 Editor::pitch_shift_region ()
6696 RegionSelection rs = get_regions_from_selection_and_entered ();
6698 RegionSelection audio_rs;
6699 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
6700 if (dynamic_cast<AudioRegionView*> (*i)) {
6701 audio_rs.push_back (*i);
6705 if (audio_rs.empty()) {
6709 pitch_shift (audio_rs, 1.2);
6713 Editor::set_tempo_from_region ()
6715 RegionSelection rs = get_regions_from_selection_and_entered ();
6717 if (!_session || rs.empty()) {
6721 RegionView* rv = rs.front();
6723 define_one_bar (rv->region()->position(), rv->region()->last_frame() + 1);
6727 Editor::use_range_as_bar ()
6729 framepos_t start, end;
6730 if (get_edit_op_range (start, end)) {
6731 define_one_bar (start, end);
6736 Editor::define_one_bar (framepos_t start, framepos_t end)
6738 framepos_t length = end - start;
6740 const Meter& m (_session->tempo_map().meter_at_frame (start));
6742 /* length = 1 bar */
6744 /* We're going to deliver a constant tempo here,
6745 so we can use frames per beat to determine length.
6746 now we want frames per beat.
6747 we have frames per bar, and beats per bar, so ...
6750 /* XXXX METER MATH */
6752 double frames_per_beat = length / m.divisions_per_bar();
6754 /* beats per minute = */
6756 double beats_per_minute = (_session->frame_rate() * 60.0) / frames_per_beat;
6758 /* now decide whether to:
6760 (a) set global tempo
6761 (b) add a new tempo marker
6765 const TempoSection& t (_session->tempo_map().tempo_section_at_frame (start));
6767 bool do_global = false;
6769 if ((_session->tempo_map().n_tempos() == 1) && (_session->tempo_map().n_meters() == 1)) {
6771 /* only 1 tempo & 1 meter: ask if the user wants to set the tempo
6772 at the start, or create a new marker
6775 vector<string> options;
6776 options.push_back (_("Cancel"));
6777 options.push_back (_("Add new marker"));
6778 options.push_back (_("Set global tempo"));
6781 _("Define one bar"),
6782 _("Do you want to set the global tempo or add a new tempo marker?"),
6786 c.set_default_response (2);
6802 /* more than 1 tempo and/or meter section already, go ahead do the "usual":
6803 if the marker is at the region starter, change it, otherwise add
6808 begin_reversible_command (_("set tempo from region"));
6809 XMLNode& before (_session->tempo_map().get_state());
6812 _session->tempo_map().change_initial_tempo (beats_per_minute, t.note_type(), t.end_note_types_per_minute());
6813 } else if (t.frame() == start) {
6814 _session->tempo_map().change_existing_tempo_at (start, beats_per_minute, t.note_type(), t.end_note_types_per_minute());
6816 /* constant tempo */
6817 const Tempo tempo (beats_per_minute, t.note_type());
6818 _session->tempo_map().add_tempo (tempo, 0.0, start, AudioTime);
6821 XMLNode& after (_session->tempo_map().get_state());
6823 _session->add_command (new MementoCommand<TempoMap>(_session->tempo_map(), &before, &after));
6824 commit_reversible_command ();
6828 Editor::split_region_at_transients ()
6830 AnalysisFeatureList positions;
6832 RegionSelection rs = get_regions_from_selection_and_entered ();
6834 if (!_session || rs.empty()) {
6838 begin_reversible_command (_("split regions"));
6840 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ) {
6842 RegionSelection::iterator tmp;
6847 boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion> ((*i)->region());
6850 ar->transients (positions);
6851 split_region_at_points ((*i)->region(), positions, true);
6858 commit_reversible_command ();
6863 Editor::split_region_at_points (boost::shared_ptr<Region> r, AnalysisFeatureList& positions, bool can_ferret, bool select_new)
6865 bool use_rhythmic_rodent = false;
6867 boost::shared_ptr<Playlist> pl = r->playlist();
6869 list<boost::shared_ptr<Region> > new_regions;
6875 if (positions.empty()) {
6879 if (positions.size() > 20 && can_ferret) {
6880 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);
6881 MessageDialog msg (msgstr,
6884 Gtk::BUTTONS_OK_CANCEL);
6887 msg.add_button (_("Call for the Ferret!"), RESPONSE_APPLY);
6888 msg.set_secondary_text (_("Press OK to continue with this split operation\nor ask the Ferret dialog to tune the analysis"));
6890 msg.set_secondary_text (_("Press OK to continue with this split operation"));
6893 msg.set_title (_("Excessive split?"));
6896 int response = msg.run();
6902 case RESPONSE_APPLY:
6903 use_rhythmic_rodent = true;
6910 if (use_rhythmic_rodent) {
6911 show_rhythm_ferret ();
6915 AnalysisFeatureList::const_iterator x;
6917 pl->clear_changes ();
6918 pl->clear_owned_changes ();
6920 x = positions.begin();
6922 if (x == positions.end()) {
6927 pl->remove_region (r);
6931 framepos_t rstart = r->first_frame ();
6932 framepos_t rend = r->last_frame ();
6934 while (x != positions.end()) {
6936 /* deal with positons that are out of scope of present region bounds */
6937 if (*x <= rstart || *x > rend) {
6942 /* file start = original start + how far we from the initial position ? */
6944 framepos_t file_start = r->start() + pos;
6946 /* length = next position - current position */
6948 framepos_t len = (*x) - pos - rstart;
6950 /* XXX we do we really want to allow even single-sample regions?
6951 * shouldn't we have some kind of lower limit on region size?
6960 if (RegionFactory::region_name (new_name, r->name())) {
6964 /* do NOT announce new regions 1 by one, just wait till they are all done */
6968 plist.add (ARDOUR::Properties::start, file_start);
6969 plist.add (ARDOUR::Properties::length, len);
6970 plist.add (ARDOUR::Properties::name, new_name);
6971 plist.add (ARDOUR::Properties::layer, 0);
6972 // TODO set transients_offset
6974 boost::shared_ptr<Region> nr = RegionFactory::create (r->sources(), plist, false);
6975 /* because we set annouce to false, manually add the new region to the
6978 RegionFactory::map_add (nr);
6980 pl->add_region (nr, rstart + pos);
6983 new_regions.push_front(nr);
6992 RegionFactory::region_name (new_name, r->name());
6994 /* Add the final region */
6997 plist.add (ARDOUR::Properties::start, r->start() + pos);
6998 plist.add (ARDOUR::Properties::length, r->last_frame() - (r->position() + pos) + 1);
6999 plist.add (ARDOUR::Properties::name, new_name);
7000 plist.add (ARDOUR::Properties::layer, 0);
7002 boost::shared_ptr<Region> nr = RegionFactory::create (r->sources(), plist, false);
7003 /* because we set annouce to false, manually add the new region to the
7006 RegionFactory::map_add (nr);
7007 pl->add_region (nr, r->position() + pos);
7010 new_regions.push_front(nr);
7015 /* We might have removed regions, which alters other regions' layering_index,
7016 so we need to do a recursive diff here.
7018 vector<Command*> cmds;
7020 _session->add_commands (cmds);
7022 _session->add_command (new StatefulDiffCommand (pl));
7026 for (list<boost::shared_ptr<Region> >::iterator i = new_regions.begin(); i != new_regions.end(); ++i){
7027 set_selected_regionview_from_region_list ((*i), Selection::Add);
7033 Editor::place_transient()
7039 RegionSelection rs = get_regions_from_selection_and_edit_point ();
7045 framepos_t where = get_preferred_edit_position();
7047 begin_reversible_command (_("place transient"));
7049 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
7050 (*r)->region()->add_transient(where);
7053 commit_reversible_command ();
7057 Editor::remove_transient(ArdourCanvas::Item* item)
7063 ArdourCanvas::Line* _line = reinterpret_cast<ArdourCanvas::Line*> (item);
7066 AudioRegionView* _arv = reinterpret_cast<AudioRegionView*> (item->get_data ("regionview"));
7067 _arv->remove_transient (*(float*) _line->get_data ("position"));
7071 Editor::snap_regions_to_grid ()
7073 list <boost::shared_ptr<Playlist > > used_playlists;
7075 RegionSelection rs = get_regions_from_selection_and_entered ();
7077 if (!_session || rs.empty()) {
7081 begin_reversible_command (_("snap regions to grid"));
7083 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
7085 boost::shared_ptr<Playlist> pl = (*r)->region()->playlist();
7087 if (!pl->frozen()) {
7088 /* we haven't seen this playlist before */
7090 /* remember used playlists so we can thaw them later */
7091 used_playlists.push_back(pl);
7094 (*r)->region()->clear_changes ();
7096 MusicFrame start ((*r)->region()->first_frame (), 0);
7098 (*r)->region()->set_position (start.frame, start.division);
7099 _session->add_command(new StatefulDiffCommand ((*r)->region()));
7102 while (used_playlists.size() > 0) {
7103 list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
7105 used_playlists.pop_front();
7108 commit_reversible_command ();
7112 Editor::close_region_gaps ()
7114 list <boost::shared_ptr<Playlist > > used_playlists;
7116 RegionSelection rs = get_regions_from_selection_and_entered ();
7118 if (!_session || rs.empty()) {
7122 Dialog dialog (_("Close Region Gaps"));
7125 table.set_spacings (12);
7126 table.set_border_width (12);
7127 Label* l = manage (left_aligned_label (_("Crossfade length")));
7128 table.attach (*l, 0, 1, 0, 1);
7130 SpinButton spin_crossfade (1, 0);
7131 spin_crossfade.set_range (0, 15);
7132 spin_crossfade.set_increments (1, 1);
7133 spin_crossfade.set_value (5);
7134 table.attach (spin_crossfade, 1, 2, 0, 1);
7136 table.attach (*manage (new Label (_("ms"))), 2, 3, 0, 1);
7138 l = manage (left_aligned_label (_("Pull-back length")));
7139 table.attach (*l, 0, 1, 1, 2);
7141 SpinButton spin_pullback (1, 0);
7142 spin_pullback.set_range (0, 100);
7143 spin_pullback.set_increments (1, 1);
7144 spin_pullback.set_value(30);
7145 table.attach (spin_pullback, 1, 2, 1, 2);
7147 table.attach (*manage (new Label (_("ms"))), 2, 3, 1, 2);
7149 dialog.get_vbox()->pack_start (table);
7150 dialog.add_button (Stock::CANCEL, RESPONSE_CANCEL);
7151 dialog.add_button (_("Ok"), RESPONSE_ACCEPT);
7154 if (dialog.run () == RESPONSE_CANCEL) {
7158 framepos_t crossfade_len = spin_crossfade.get_value();
7159 framepos_t pull_back_frames = spin_pullback.get_value();
7161 crossfade_len = lrintf (crossfade_len * _session->frame_rate()/1000);
7162 pull_back_frames = lrintf (pull_back_frames * _session->frame_rate()/1000);
7164 /* Iterate over the region list and make adjacent regions overlap by crossfade_len_ms */
7166 begin_reversible_command (_("close region gaps"));
7169 boost::shared_ptr<Region> last_region;
7171 rs.sort_by_position_and_track();
7173 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
7175 boost::shared_ptr<Playlist> pl = (*r)->region()->playlist();
7177 if (!pl->frozen()) {
7178 /* we haven't seen this playlist before */
7180 /* remember used playlists so we can thaw them later */
7181 used_playlists.push_back(pl);
7185 framepos_t position = (*r)->region()->position();
7187 if (idx == 0 || position < last_region->position()){
7188 last_region = (*r)->region();
7193 (*r)->region()->clear_changes ();
7194 (*r)->region()->trim_front( (position - pull_back_frames));
7196 last_region->clear_changes ();
7197 last_region->trim_end( (position - pull_back_frames + crossfade_len));
7199 _session->add_command (new StatefulDiffCommand ((*r)->region()));
7200 _session->add_command (new StatefulDiffCommand (last_region));
7202 last_region = (*r)->region();
7206 while (used_playlists.size() > 0) {
7207 list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
7209 used_playlists.pop_front();
7212 commit_reversible_command ();
7216 Editor::tab_to_transient (bool forward)
7218 AnalysisFeatureList positions;
7220 RegionSelection rs = get_regions_from_selection_and_entered ();
7226 framepos_t pos = _session->audible_frame ();
7228 if (!selection->tracks.empty()) {
7230 /* don't waste time searching for transients in duplicate playlists.
7233 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
7235 for (TrackViewList::iterator t = ts.begin(); t != ts.end(); ++t) {
7237 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*t);
7240 boost::shared_ptr<Track> tr = rtv->track();
7242 boost::shared_ptr<Playlist> pl = tr->playlist ();
7244 framepos_t result = pl->find_next_transient (pos, forward ? 1 : -1);
7247 positions.push_back (result);
7260 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
7261 (*r)->region()->get_transients (positions);
7265 TransientDetector::cleanup_transients (positions, _session->frame_rate(), 3.0);
7268 AnalysisFeatureList::iterator x;
7270 for (x = positions.begin(); x != positions.end(); ++x) {
7276 if (x != positions.end ()) {
7277 _session->request_locate (*x);
7281 AnalysisFeatureList::reverse_iterator x;
7283 for (x = positions.rbegin(); x != positions.rend(); ++x) {
7289 if (x != positions.rend ()) {
7290 _session->request_locate (*x);
7296 Editor::playhead_forward_to_grid ()
7302 MusicFrame pos (playhead_cursor->current_frame (), 0);
7304 if (pos.frame < max_framepos - 1) {
7306 snap_to_internal (pos, RoundUpAlways, false);
7307 _session->request_locate (pos.frame);
7313 Editor::playhead_backward_to_grid ()
7319 MusicFrame pos (playhead_cursor->current_frame (), 0);
7321 if (pos.frame > 2) {
7323 snap_to_internal (pos, RoundDownAlways, false);
7324 _session->request_locate (pos.frame);
7329 Editor::set_track_height (Height h)
7331 TrackSelection& ts (selection->tracks);
7333 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
7334 (*x)->set_height_enum (h);
7339 Editor::toggle_tracks_active ()
7341 TrackSelection& ts (selection->tracks);
7343 bool target = false;
7349 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
7350 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*x);
7354 target = !rtv->_route->active();
7357 rtv->_route->set_active (target, this);
7363 Editor::remove_tracks ()
7365 /* this will delete GUI objects that may be the subject of an event
7366 handler in which this method is called. Defer actual deletion to the
7367 next idle callback, when all event handling is finished.
7369 Glib::signal_idle().connect (sigc::mem_fun (*this, &Editor::idle_remove_tracks));
7373 Editor::idle_remove_tracks ()
7375 Session::StateProtector sp (_session);
7377 return false; /* do not call again */
7381 Editor::_remove_tracks ()
7383 TrackSelection& ts (selection->tracks);
7389 vector<string> choices;
7393 const char* trackstr;
7395 vector<boost::shared_ptr<Route> > routes;
7396 bool special_bus = false;
7398 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
7399 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*x);
7403 if (rtv->is_track()) {
7408 routes.push_back (rtv->_route);
7410 if (rtv->route()->is_master() || rtv->route()->is_monitor()) {
7415 if (special_bus && !Config->get_allow_special_bus_removal()) {
7416 MessageDialog msg (_("That would be bad news ...."),
7420 msg.set_secondary_text (string_compose (_(
7421 "Removing the master or monitor bus is such a bad idea\n\
7422 that %1 is not going to allow it.\n\
7424 If you really want to do this sort of thing\n\
7425 edit your ardour.rc file to set the\n\
7426 \"allow-special-bus-removal\" option to be \"yes\""), PROGRAM_NAME));
7433 if (ntracks + nbusses == 0) {
7437 trackstr = P_("track", "tracks", ntracks);
7438 busstr = P_("bus", "busses", nbusses);
7442 prompt = string_compose (_("Do you really want to remove %1 %2 and %3 %4?\n"
7443 "(You may also lose the playlists associated with the %2)\n\n"
7444 "This action cannot be undone, and the session file will be overwritten!"),
7445 ntracks, trackstr, nbusses, busstr);
7447 prompt = string_compose (_("Do you really want to remove %1 %2?\n"
7448 "(You may also lose the playlists associated with the %2)\n\n"
7449 "This action cannot be undone, and the session file will be overwritten!"),
7452 } else if (nbusses) {
7453 prompt = string_compose (_("Do you really want to remove %1 %2?\n\n"
7454 "This action cannot be undone, and the session file will be overwritten"),
7458 choices.push_back (_("No, do nothing."));
7459 if (ntracks + nbusses > 1) {
7460 choices.push_back (_("Yes, remove them."));
7462 choices.push_back (_("Yes, remove it."));
7467 title = string_compose (_("Remove %1"), trackstr);
7469 title = string_compose (_("Remove %1"), busstr);
7472 Choice prompter (title, prompt, choices);
7474 if (prompter.run () != 1) {
7478 if (current_mixer_strip && routes.size () > 1 && std::find (routes.begin(), routes.end(), current_mixer_strip->route()) != routes.end ()) {
7479 /* Route deletion calls Editor::timeaxisview_deleted() iteratively (for each deleted
7480 * route). If the deleted route is currently displayed in the Editor-Mixer (highly
7481 * likely because deletion requires selection) this will call
7482 * Editor::set_selected_mixer_strip () which is expensive ( MixerStrip::set_route() ).
7483 * It's likewise likely that the route that has just been displayed in the
7484 * Editor-Mixer will be next in line for deletion.
7486 * So simply switch to the master-bus (if present)
7488 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
7489 if ((*i)->stripable ()->is_master ()) {
7490 set_selected_mixer_strip (*(*i));
7497 PresentationInfo::ChangeSuspender cs;
7498 DisplaySuspender ds;
7500 boost::shared_ptr<RouteList> rl (new RouteList);
7501 for (vector<boost::shared_ptr<Route> >::iterator x = routes.begin(); x != routes.end(); ++x) {
7504 _session->remove_routes (rl);
7506 /* TrackSelection and RouteList leave scope,
7507 * destructors are called,
7508 * diskstream drops references, save_state is called (again for every track)
7513 Editor::do_insert_time ()
7515 if (selection->tracks.empty()) {
7519 InsertRemoveTimeDialog d (*this);
7520 int response = d.run ();
7522 if (response != RESPONSE_OK) {
7526 if (d.distance() == 0) {
7533 d.intersected_region_action (),
7537 d.move_glued_markers(),
7538 d.move_locked_markers(),
7544 Editor::insert_time (
7545 framepos_t pos, framecnt_t frames, InsertTimeOption opt,
7546 bool all_playlists, bool ignore_music_glue, bool markers_too, bool glued_markers_too, bool locked_markers_too, bool tempo_too
7550 if (Config->get_edit_mode() == Lock) {
7553 bool in_command = false;
7555 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
7557 for (TrackViewList::iterator x = ts.begin(); x != ts.end(); ++x) {
7561 /* don't operate on any playlist more than once, which could
7562 * happen if "all playlists" is enabled, but there is more
7563 * than 1 track using playlists "from" a given track.
7566 set<boost::shared_ptr<Playlist> > pl;
7568 if (all_playlists) {
7569 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*x);
7570 if (rtav && rtav->track ()) {
7571 vector<boost::shared_ptr<Playlist> > all = _session->playlists->playlists_for_track (rtav->track ());
7572 for (vector<boost::shared_ptr<Playlist> >::iterator p = all.begin(); p != all.end(); ++p) {
7577 if ((*x)->playlist ()) {
7578 pl.insert ((*x)->playlist ());
7582 for (set<boost::shared_ptr<Playlist> >::iterator i = pl.begin(); i != pl.end(); ++i) {
7584 (*i)->clear_changes ();
7585 (*i)->clear_owned_changes ();
7588 begin_reversible_command (_("insert time"));
7592 if (opt == SplitIntersected) {
7593 /* non musical split */
7594 (*i)->split (MusicFrame (pos, 0));
7597 (*i)->shift (pos, frames, (opt == MoveIntersected), ignore_music_glue);
7599 vector<Command*> cmds;
7601 _session->add_commands (cmds);
7603 _session->add_command (new StatefulDiffCommand (*i));
7607 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*x);
7610 begin_reversible_command (_("insert time"));
7613 rtav->route ()->shift (pos, frames);
7620 const int32_t divisions = get_grid_music_divisions (0);
7621 XMLNode& before (_session->locations()->get_state());
7622 Locations::LocationList copy (_session->locations()->list());
7624 for (Locations::LocationList::iterator i = copy.begin(); i != copy.end(); ++i) {
7626 Locations::LocationList::const_iterator tmp;
7628 if ((*i)->position_lock_style() == AudioTime || glued_markers_too) {
7629 bool const was_locked = (*i)->locked ();
7630 if (locked_markers_too) {
7634 if ((*i)->start() >= pos) {
7635 // move end first, in case we're moving by more than the length of the range
7636 if (!(*i)->is_mark()) {
7637 (*i)->set_end ((*i)->end() + frames, false, true, divisions);
7639 (*i)->set_start ((*i)->start() + frames, false, true, divisions);
7651 begin_reversible_command (_("insert time"));
7654 XMLNode& after (_session->locations()->get_state());
7655 _session->add_command (new MementoCommand<Locations>(*_session->locations(), &before, &after));
7661 begin_reversible_command (_("insert time"));
7664 XMLNode& before (_session->tempo_map().get_state());
7665 _session->tempo_map().insert_time (pos, frames);
7666 XMLNode& after (_session->tempo_map().get_state());
7667 _session->add_command (new MementoCommand<TempoMap>(_session->tempo_map(), &before, &after));
7671 commit_reversible_command ();
7676 Editor::do_remove_time ()
7678 if (selection->tracks.empty()) {
7682 InsertRemoveTimeDialog d (*this, true);
7684 int response = d.run ();
7686 if (response != RESPONSE_OK) {
7690 framecnt_t distance = d.distance();
7692 if (distance == 0) {
7702 d.move_glued_markers(),
7703 d.move_locked_markers(),
7709 Editor::remove_time (framepos_t pos, framecnt_t frames, InsertTimeOption opt,
7710 bool ignore_music_glue, bool markers_too, bool glued_markers_too, bool locked_markers_too, bool tempo_too)
7712 if (Config->get_edit_mode() == Lock) {
7713 error << (_("Cannot insert or delete time when in Lock edit.")) << endmsg;
7716 bool in_command = false;
7718 for (TrackSelection::iterator x = selection->tracks.begin(); x != selection->tracks.end(); ++x) {
7720 boost::shared_ptr<Playlist> pl = (*x)->playlist();
7724 XMLNode &before = pl->get_state();
7727 begin_reversible_command (_("remove time"));
7731 std::list<AudioRange> rl;
7732 AudioRange ar(pos, pos+frames, 0);
7735 pl->shift (pos, -frames, true, ignore_music_glue);
7737 XMLNode &after = pl->get_state();
7739 _session->add_command (new MementoCommand<Playlist> (*pl, &before, &after));
7743 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*x);
7746 begin_reversible_command (_("remove time"));
7749 rtav->route ()->shift (pos, -frames);
7753 const int32_t divisions = get_grid_music_divisions (0);
7754 std::list<Location*> loc_kill_list;
7759 XMLNode& before (_session->locations()->get_state());
7760 Locations::LocationList copy (_session->locations()->list());
7762 for (Locations::LocationList::iterator i = copy.begin(); i != copy.end(); ++i) {
7763 if ((*i)->position_lock_style() == AudioTime || glued_markers_too) {
7765 bool const was_locked = (*i)->locked ();
7766 if (locked_markers_too) {
7770 if (!(*i)->is_mark()) { // it's a range; have to handle both start and end
7771 if ((*i)->end() >= pos
7772 && (*i)->end() < pos+frames
7773 && (*i)->start() >= pos
7774 && (*i)->end() < pos+frames) { // range is completely enclosed; kill it
7776 loc_kill_list.push_back(*i);
7777 } else { // only start or end is included, try to do the right thing
7778 // move start before moving end, to avoid trying to move the end to before the start
7779 // if we're removing more time than the length of the range
7780 if ((*i)->start() >= pos && (*i)->start() < pos+frames) {
7781 // start is within cut
7782 (*i)->set_start (pos, false, true,divisions); // bring the start marker to the beginning of the cut
7784 } else if ((*i)->start() >= pos+frames) {
7785 // start (and thus entire range) lies beyond end of cut
7786 (*i)->set_start ((*i)->start() - frames, false, true, divisions); // slip the start marker back
7789 if ((*i)->end() >= pos && (*i)->end() < pos+frames) {
7790 // end is inside cut
7791 (*i)->set_end (pos, false, true, divisions); // bring the end to the cut
7793 } else if ((*i)->end() >= pos+frames) {
7794 // end is beyond end of cut
7795 (*i)->set_end ((*i)->end() - frames, false, true, divisions); // slip the end marker back
7800 } else if ((*i)->start() >= pos && (*i)->start() < pos+frames ) {
7801 loc_kill_list.push_back(*i);
7803 } else if ((*i)->start() >= pos) {
7804 (*i)->set_start ((*i)->start() -frames, false, true, divisions);
7814 for (list<Location*>::iterator i = loc_kill_list.begin(); i != loc_kill_list.end(); ++i) {
7815 _session->locations()->remove( *i );
7820 begin_reversible_command (_("remove time"));
7823 XMLNode& after (_session->locations()->get_state());
7824 _session->add_command (new MementoCommand<Locations>(*_session->locations(), &before, &after));
7829 XMLNode& before (_session->tempo_map().get_state());
7831 if (_session->tempo_map().remove_time (pos, frames) ) {
7833 begin_reversible_command (_("remove time"));
7836 XMLNode& after (_session->tempo_map().get_state());
7837 _session->add_command (new MementoCommand<TempoMap>(_session->tempo_map(), &before, &after));
7842 commit_reversible_command ();
7847 Editor::fit_selection ()
7849 if (!selection->tracks.empty()) {
7850 fit_tracks (selection->tracks);
7854 /* no selected tracks - use tracks with selected regions */
7856 if (!selection->regions.empty()) {
7857 for (RegionSelection::iterator r = selection->regions.begin(); r != selection->regions.end(); ++r) {
7858 tvl.push_back (&(*r)->get_time_axis_view ());
7864 } else if (internal_editing()) {
7865 /* no selected tracks, or regions, but in internal edit mode, so follow the mouse and use
7868 if (entered_track) {
7869 tvl.push_back (entered_track);
7877 Editor::fit_tracks (TrackViewList & tracks)
7879 if (tracks.empty()) {
7883 uint32_t child_heights = 0;
7884 int visible_tracks = 0;
7886 for (TrackSelection::iterator t = tracks.begin(); t != tracks.end(); ++t) {
7888 if (!(*t)->marked_for_display()) {
7892 child_heights += (*t)->effective_height() - (*t)->current_height();
7896 /* compute the per-track height from:
7898 * total canvas visible height
7899 * - height that will be taken by visible children of selected tracks
7900 * - height of the ruler/hscroll area
7902 uint32_t h = (uint32_t) floor ((trackviews_height() - child_heights) / visible_tracks);
7903 double first_y_pos = DBL_MAX;
7905 if (h < TimeAxisView::preset_height (HeightSmall)) {
7906 MessageDialog msg (_("There are too many tracks to fit in the current window"));
7907 /* too small to be displayed */
7911 undo_visual_stack.push_back (current_visual_state (true));
7912 PBD::Unwinder<bool> nsv (no_save_visual, true);
7914 /* build a list of all tracks, including children */
7917 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
7919 TimeAxisView::Children c = (*i)->get_child_list ();
7920 for (TimeAxisView::Children::iterator j = c.begin(); j != c.end(); ++j) {
7921 all.push_back (j->get());
7926 // find selection range.
7927 // if someone knows how to user TrackViewList::iterator for this
7929 int selected_top = -1;
7930 int selected_bottom = -1;
7932 for (TrackViewList::iterator t = all.begin(); t != all.end(); ++t, ++i) {
7933 if ((*t)->marked_for_display ()) {
7934 if (tracks.contains(*t)) {
7935 if (selected_top == -1) {
7938 selected_bottom = i;
7944 for (TrackViewList::iterator t = all.begin(); t != all.end(); ++t, ++i) {
7945 if ((*t)->marked_for_display ()) {
7946 if (tracks.contains(*t)) {
7947 (*t)->set_height (h);
7948 first_y_pos = std::min ((*t)->y_position (), first_y_pos);
7950 if (i > selected_top && i < selected_bottom) {
7951 hide_track_in_display (*t);
7958 set the controls_layout height now, because waiting for its size
7959 request signal handler will cause the vertical adjustment setting to fail
7962 controls_layout.property_height () = _full_canvas_height;
7963 vertical_adjustment.set_value (first_y_pos);
7965 redo_visual_stack.push_back (current_visual_state (true));
7967 visible_tracks_selector.set_text (_("Sel"));
7971 Editor::save_visual_state (uint32_t n)
7973 while (visual_states.size() <= n) {
7974 visual_states.push_back (0);
7977 if (visual_states[n] != 0) {
7978 delete visual_states[n];
7981 visual_states[n] = current_visual_state (true);
7986 Editor::goto_visual_state (uint32_t n)
7988 if (visual_states.size() <= n) {
7992 if (visual_states[n] == 0) {
7996 use_visual_state (*visual_states[n]);
8000 Editor::start_visual_state_op (uint32_t n)
8002 save_visual_state (n);
8004 PopUp* pup = new PopUp (WIN_POS_MOUSE, 1000, true);
8006 snprintf (buf, sizeof (buf), _("Saved view %u"), n+1);
8007 pup->set_text (buf);
8012 Editor::cancel_visual_state_op (uint32_t n)
8014 goto_visual_state (n);
8018 Editor::toggle_region_mute ()
8020 if (_ignore_region_action) {
8024 RegionSelection rs = get_regions_from_selection_and_entered ();
8030 if (rs.size() > 1) {
8031 begin_reversible_command (_("mute regions"));
8033 begin_reversible_command (_("mute region"));
8036 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
8038 (*i)->region()->playlist()->clear_changes ();
8039 (*i)->region()->set_muted (!(*i)->region()->muted ());
8040 _session->add_command (new StatefulDiffCommand ((*i)->region()));
8044 commit_reversible_command ();
8048 Editor::combine_regions ()
8050 /* foreach track with selected regions, take all selected regions
8051 and join them into a new region containing the subregions (as a
8055 typedef set<RouteTimeAxisView*> RTVS;
8058 if (selection->regions.empty()) {
8062 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
8063 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(&(*i)->get_time_axis_view());
8066 tracks.insert (rtv);
8070 begin_reversible_command (_("combine regions"));
8072 vector<RegionView*> new_selection;
8074 for (RTVS::iterator i = tracks.begin(); i != tracks.end(); ++i) {
8077 if ((rv = (*i)->combine_regions ()) != 0) {
8078 new_selection.push_back (rv);
8082 selection->clear_regions ();
8083 for (vector<RegionView*>::iterator i = new_selection.begin(); i != new_selection.end(); ++i) {
8084 selection->add (*i);
8087 commit_reversible_command ();
8091 Editor::uncombine_regions ()
8093 typedef set<RouteTimeAxisView*> RTVS;
8096 if (selection->regions.empty()) {
8100 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
8101 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(&(*i)->get_time_axis_view());
8104 tracks.insert (rtv);
8108 begin_reversible_command (_("uncombine regions"));
8110 for (RTVS::iterator i = tracks.begin(); i != tracks.end(); ++i) {
8111 (*i)->uncombine_regions ();
8114 commit_reversible_command ();
8118 Editor::toggle_midi_input_active (bool flip_others)
8121 boost::shared_ptr<RouteList> rl (new RouteList);
8123 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
8124 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
8130 boost::shared_ptr<MidiTrack> mt = rtav->midi_track();
8133 rl->push_back (rtav->route());
8134 onoff = !mt->input_active();
8138 _session->set_exclusive_input_active (rl, onoff, flip_others);
8141 static bool ok_fine (GdkEventAny*) { return true; }
8147 lock_dialog = new Gtk::Dialog (string_compose (_("%1: Locked"), PROGRAM_NAME), true);
8149 Gtk::Image* padlock = manage (new Gtk::Image (ARDOUR_UI_UTILS::get_icon ("padlock_closed")));
8150 lock_dialog->get_vbox()->pack_start (*padlock);
8151 lock_dialog->signal_delete_event ().connect (sigc::ptr_fun (ok_fine));
8153 ArdourButton* b = manage (new ArdourButton);
8154 b->set_name ("lock button");
8155 b->set_text (_("Click to unlock"));
8156 b->signal_clicked.connect (sigc::mem_fun (*this, &Editor::unlock));
8157 lock_dialog->get_vbox()->pack_start (*b);
8159 lock_dialog->get_vbox()->show_all ();
8160 lock_dialog->set_size_request (200, 200);
8163 delete _main_menu_disabler;
8164 _main_menu_disabler = new MainMenuDisabler;
8166 lock_dialog->present ();
8168 lock_dialog->get_window()->set_decorations (Gdk::WMDecoration (0));
8174 lock_dialog->hide ();
8176 delete _main_menu_disabler;
8177 _main_menu_disabler = 0;
8179 if (UIConfiguration::instance().get_lock_gui_after_seconds()) {
8180 start_lock_event_timing ();
8185 Editor::bring_in_callback (Gtk::Label* label, uint32_t n, uint32_t total, string name)
8187 Gtkmm2ext::UI::instance()->call_slot (invalidator (*this), boost::bind (&Editor::update_bring_in_message, this, label, n, total, name));
8191 Editor::update_bring_in_message (Gtk::Label* label, uint32_t n, uint32_t total, string name)
8193 Timers::TimerSuspender t;
8194 label->set_text (string_compose ("Copying %1, %2 of %3", name, n, total));
8195 Gtkmm2ext::UI::instance()->flush_pending (1);
8199 Editor::bring_all_sources_into_session ()
8206 ArdourDialog w (_("Moving embedded files into session folder"));
8207 w.get_vbox()->pack_start (msg);
8210 /* flush all pending GUI events because we're about to start copying
8214 Timers::TimerSuspender t;
8215 Gtkmm2ext::UI::instance()->flush_pending (3);
8219 _session->bring_all_sources_into_session (boost::bind (&Editor::bring_in_callback, this, &msg, _1, _2, _3));