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 "pbd/error.h"
32 #include "pbd/basename.h"
33 #include "pbd/pthread_utils.h"
34 #include "pbd/memento_command.h"
35 #include "pbd/unwind.h"
36 #include "pbd/whitespace.h"
37 #include "pbd/stateful_diff_command.h"
39 #include <gtkmm2ext/utils.h>
40 #include <gtkmm2ext/choice.h>
41 #include <gtkmm2ext/popup.h>
43 #include "ardour/audio_track.h"
44 #include "ardour/audioregion.h"
45 #include "ardour/boost_debug.h"
46 #include "ardour/dB.h"
47 #include "ardour/location.h"
48 #include "ardour/midi_region.h"
49 #include "ardour/midi_track.h"
50 #include "ardour/operations.h"
51 #include "ardour/playlist_factory.h"
52 #include "ardour/profile.h"
53 #include "ardour/quantize.h"
54 #include "ardour/legatize.h"
55 #include "ardour/region_factory.h"
56 #include "ardour/reverse.h"
57 #include "ardour/session.h"
58 #include "ardour/session_playlists.h"
59 #include "ardour/strip_silence.h"
60 #include "ardour/transient_detector.h"
61 #include "ardour/transpose.h"
63 #include "canvas/canvas.h"
66 #include "audio_region_view.h"
67 #include "audio_streamview.h"
68 #include "audio_time_axis.h"
69 #include "automation_region_view.h"
70 #include "automation_time_axis.h"
71 #include "control_point.h"
75 #include "editor_cursors.h"
76 #include "editor_drag.h"
77 #include "editor_regions.h"
78 #include "editor_routes.h"
79 #include "gui_thread.h"
80 #include "insert_remove_time_dialog.h"
81 #include "interthread_progress_window.h"
82 #include "item_counts.h"
84 #include "midi_region_view.h"
86 #include "mixer_strip.h"
87 #include "mouse_cursors.h"
88 #include "normalize_dialog.h"
90 #include "paste_context.h"
91 #include "patch_change_dialog.h"
92 #include "quantize_dialog.h"
93 #include "region_gain_line.h"
94 #include "rgb_macros.h"
95 #include "route_time_axis.h"
96 #include "selection.h"
97 #include "selection_templates.h"
98 #include "streamview.h"
99 #include "strip_silence_dialog.h"
100 #include "time_axis_view.h"
102 #include "transpose_dialog.h"
103 #include "transform_dialog.h"
104 #include "ui_config.h"
106 #include "pbd/i18n.h"
109 using namespace ARDOUR;
112 using namespace Gtkmm2ext;
113 using namespace Editing;
114 using Gtkmm2ext::Keyboard;
116 /***********************************************************************
118 ***********************************************************************/
121 Editor::undo (uint32_t n)
123 if (_session && _session->actively_recording()) {
124 /* no undo allowed while recording. Session will check also,
125 but we don't even want to get to that.
130 if (_drags->active ()) {
136 if (_session->undo_depth() == 0) {
137 undo_action->set_sensitive(false);
139 redo_action->set_sensitive(true);
140 begin_selection_op_history ();
145 Editor::redo (uint32_t n)
147 if (_session && _session->actively_recording()) {
148 /* no redo allowed while recording. Session will check also,
149 but we don't even want to get to that.
154 if (_drags->active ()) {
160 if (_session->redo_depth() == 0) {
161 redo_action->set_sensitive(false);
163 undo_action->set_sensitive(true);
164 begin_selection_op_history ();
169 Editor::split_regions_at (MusicFrame where, RegionSelection& regions, bool snap_frame)
173 RegionSelection pre_selected_regions = selection->regions;
174 bool working_on_selection = !pre_selected_regions.empty();
176 list<boost::shared_ptr<Playlist> > used_playlists;
177 list<RouteTimeAxisView*> used_trackviews;
179 if (regions.empty()) {
183 begin_reversible_command (_("split"));
185 // if splitting a single region, and snap-to is using
186 // region boundaries, don't pay attention to them
188 if (regions.size() == 1) {
189 switch (_snap_type) {
190 case SnapToRegionStart:
191 case SnapToRegionSync:
192 case SnapToRegionEnd:
205 EditorFreeze(); /* Emit Signal */
208 for (RegionSelection::iterator a = regions.begin(); a != regions.end(); ) {
210 RegionSelection::iterator tmp;
212 /* XXX this test needs to be more complicated, to make sure we really
213 have something to split.
216 if (!(*a)->region()->covers (where.frame)) {
224 boost::shared_ptr<Playlist> pl = (*a)->region()->playlist();
232 /* we haven't seen this playlist before */
234 /* remember used playlists so we can thaw them later */
235 used_playlists.push_back(pl);
237 TimeAxisView& tv = (*a)->get_time_axis_view();
238 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (&tv);
240 used_trackviews.push_back (rtv);
247 pl->clear_changes ();
248 pl->split_region ((*a)->region(), where);
249 _session->add_command (new StatefulDiffCommand (pl));
255 latest_regionviews.clear ();
257 vector<sigc::connection> region_added_connections;
259 for (list<RouteTimeAxisView*>::iterator i = used_trackviews.begin(); i != used_trackviews.end(); ++i) {
260 region_added_connections.push_back ((*i)->view()->RegionViewAdded.connect (sigc::mem_fun(*this, &Editor::collect_new_region_view)));
263 while (used_playlists.size() > 0) {
264 list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
266 used_playlists.pop_front();
269 for (vector<sigc::connection>::iterator c = region_added_connections.begin(); c != region_added_connections.end(); ++c) {
274 EditorThaw(); /* Emit Signal */
277 if (working_on_selection) {
278 // IFF we were working on selected regions, try to reinstate the other region selections that existed before the freeze/thaw.
280 RegionSelectionAfterSplit rsas = Config->get_region_selection_after_split();
281 /* There are three classes of regions that we might want selected after
282 splitting selected regions:
283 - regions selected before the split operation, and unaffected by it
284 - newly-created regions before the split
285 - newly-created regions after the split
288 if (rsas & Existing) {
289 // region selections that existed before the split.
290 selection->add ( pre_selected_regions );
293 for (RegionSelection::iterator ri = latest_regionviews.begin(); ri != latest_regionviews.end(); ri++) {
294 if ((*ri)->region()->position() < where.frame) {
295 // new regions created before the split
296 if (rsas & NewlyCreatedLeft) {
297 selection->add (*ri);
300 // new regions created after the split
301 if (rsas & NewlyCreatedRight) {
302 selection->add (*ri);
307 if( working_on_selection ) {
308 selection->add (latest_regionviews); //these are the new regions created after the split
312 commit_reversible_command ();
315 /** Move one extreme of the current range selection. If more than one range is selected,
316 * the start of the earliest range or the end of the latest range is moved.
318 * @param move_end true to move the end of the current range selection, false to move
320 * @param next true to move the extreme to the next region boundary, false to move to
324 Editor::move_range_selection_start_or_end_to_region_boundary (bool move_end, bool next)
326 if (selection->time.start() == selection->time.end_frame()) {
330 framepos_t start = selection->time.start ();
331 framepos_t end = selection->time.end_frame ();
333 /* the position of the thing we may move */
334 framepos_t pos = move_end ? end : start;
335 int dir = next ? 1 : -1;
337 /* so we don't find the current region again */
338 if (dir > 0 || pos > 0) {
342 framepos_t const target = get_region_boundary (pos, dir, true, false);
357 begin_reversible_selection_op (_("alter selection"));
358 selection->set_preserving_all_ranges (start, end);
359 commit_reversible_selection_op ();
363 Editor::nudge_forward_release (GdkEventButton* ev)
365 if (ev->state & Keyboard::PrimaryModifier) {
366 nudge_forward (false, true);
368 nudge_forward (false, false);
374 Editor::nudge_backward_release (GdkEventButton* ev)
376 if (ev->state & Keyboard::PrimaryModifier) {
377 nudge_backward (false, true);
379 nudge_backward (false, false);
386 Editor::nudge_forward (bool next, bool force_playhead)
389 framepos_t next_distance;
395 RegionSelection rs = get_regions_from_selection_and_entered ();
397 if (!force_playhead && !rs.empty()) {
399 begin_reversible_command (_("nudge regions forward"));
401 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
402 boost::shared_ptr<Region> r ((*i)->region());
404 distance = get_nudge_distance (r->position(), next_distance);
407 distance = next_distance;
411 r->set_position (r->position() + distance);
412 _session->add_command (new StatefulDiffCommand (r));
415 commit_reversible_command ();
418 } else if (!force_playhead && !selection->markers.empty()) {
421 bool in_command = false;
422 const int32_t divisions = get_grid_music_divisions (0);
424 for (MarkerSelection::iterator i = selection->markers.begin(); i != selection->markers.end(); ++i) {
426 Location* loc = find_location_from_marker ((*i), is_start);
430 XMLNode& before (loc->get_state());
433 distance = get_nudge_distance (loc->start(), next_distance);
435 distance = next_distance;
437 if (max_framepos - distance > loc->start() + loc->length()) {
438 loc->set_start (loc->start() + distance, false, true, divisions);
440 loc->set_start (max_framepos - loc->length(), false, true, divisions);
443 distance = get_nudge_distance (loc->end(), next_distance);
445 distance = next_distance;
447 if (max_framepos - distance > loc->end()) {
448 loc->set_end (loc->end() + distance, false, true, divisions);
450 loc->set_end (max_framepos, false, true, divisions);
452 if (loc->is_session_range()) {
453 _session->set_end_is_free (false);
457 begin_reversible_command (_("nudge location forward"));
460 XMLNode& after (loc->get_state());
461 _session->add_command (new MementoCommand<Location>(*loc, &before, &after));
466 commit_reversible_command ();
469 distance = get_nudge_distance (playhead_cursor->current_frame (), next_distance);
470 _session->request_locate (playhead_cursor->current_frame () + distance);
475 Editor::nudge_backward (bool next, bool force_playhead)
478 framepos_t next_distance;
484 RegionSelection rs = get_regions_from_selection_and_entered ();
486 if (!force_playhead && !rs.empty()) {
488 begin_reversible_command (_("nudge regions backward"));
490 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
491 boost::shared_ptr<Region> r ((*i)->region());
493 distance = get_nudge_distance (r->position(), next_distance);
496 distance = next_distance;
501 if (r->position() > distance) {
502 r->set_position (r->position() - distance);
506 _session->add_command (new StatefulDiffCommand (r));
509 commit_reversible_command ();
511 } else if (!force_playhead && !selection->markers.empty()) {
514 bool in_command = false;
516 for (MarkerSelection::iterator i = selection->markers.begin(); i != selection->markers.end(); ++i) {
518 Location* loc = find_location_from_marker ((*i), is_start);
522 XMLNode& before (loc->get_state());
525 distance = get_nudge_distance (loc->start(), next_distance);
527 distance = next_distance;
529 if (distance < loc->start()) {
530 loc->set_start (loc->start() - distance, false, true, get_grid_music_divisions(0));
532 loc->set_start (0, false, true, get_grid_music_divisions(0));
535 distance = get_nudge_distance (loc->end(), next_distance);
538 distance = next_distance;
541 if (distance < loc->end() - loc->length()) {
542 loc->set_end (loc->end() - distance, false, true, get_grid_music_divisions(0));
544 loc->set_end (loc->length(), false, true, get_grid_music_divisions(0));
546 if (loc->is_session_range()) {
547 _session->set_end_is_free (false);
551 begin_reversible_command (_("nudge location forward"));
554 XMLNode& after (loc->get_state());
555 _session->add_command (new MementoCommand<Location>(*loc, &before, &after));
559 commit_reversible_command ();
564 distance = get_nudge_distance (playhead_cursor->current_frame (), next_distance);
566 if (playhead_cursor->current_frame () > distance) {
567 _session->request_locate (playhead_cursor->current_frame () - distance);
569 _session->goto_start();
575 Editor::nudge_forward_capture_offset ()
577 RegionSelection rs = get_regions_from_selection_and_entered ();
579 if (!_session || rs.empty()) {
583 begin_reversible_command (_("nudge forward"));
585 framepos_t const distance = _session->worst_output_latency();
587 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
588 boost::shared_ptr<Region> r ((*i)->region());
591 r->set_position (r->position() + distance);
592 _session->add_command(new StatefulDiffCommand (r));
595 commit_reversible_command ();
599 Editor::nudge_backward_capture_offset ()
601 RegionSelection rs = get_regions_from_selection_and_entered ();
603 if (!_session || rs.empty()) {
607 begin_reversible_command (_("nudge backward"));
609 framepos_t const distance = _session->worst_output_latency();
611 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
612 boost::shared_ptr<Region> r ((*i)->region());
616 if (r->position() > distance) {
617 r->set_position (r->position() - distance);
621 _session->add_command(new StatefulDiffCommand (r));
624 commit_reversible_command ();
627 struct RegionSelectionPositionSorter {
628 bool operator() (RegionView* a, RegionView* b) {
629 return a->region()->position() < b->region()->position();
634 Editor::sequence_regions ()
637 framepos_t r_end_prev;
645 RegionSelection rs = get_regions_from_selection_and_entered ();
646 rs.sort(RegionSelectionPositionSorter());
650 bool in_command = false;
652 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
653 boost::shared_ptr<Region> r ((*i)->region());
661 if(r->position_locked())
668 r->set_position(r_end_prev);
672 begin_reversible_command (_("sequence regions"));
675 _session->add_command (new StatefulDiffCommand (r));
677 r_end=r->position() + r->length();
683 commit_reversible_command ();
692 Editor::move_to_start ()
694 _session->goto_start ();
698 Editor::move_to_end ()
701 _session->request_locate (_session->current_end_frame());
705 Editor::build_region_boundary_cache ()
708 vector<RegionPoint> interesting_points;
709 boost::shared_ptr<Region> r;
710 TrackViewList tracks;
713 region_boundary_cache.clear ();
719 switch (_snap_type) {
720 case SnapToRegionStart:
721 interesting_points.push_back (Start);
723 case SnapToRegionEnd:
724 interesting_points.push_back (End);
726 case SnapToRegionSync:
727 interesting_points.push_back (SyncPoint);
729 case SnapToRegionBoundary:
730 interesting_points.push_back (Start);
731 interesting_points.push_back (End);
734 fatal << string_compose (_("build_region_boundary_cache called with snap_type = %1"), _snap_type) << endmsg;
735 abort(); /*NOTREACHED*/
739 TimeAxisView *ontrack = 0;
742 if (!selection->tracks.empty()) {
743 tlist = selection->tracks.filter_to_unique_playlists ();
745 tlist = track_views.filter_to_unique_playlists ();
748 while (pos < _session->current_end_frame() && !at_end) {
751 framepos_t lpos = max_framepos;
753 for (vector<RegionPoint>::iterator p = interesting_points.begin(); p != interesting_points.end(); ++p) {
755 if ((r = find_next_region (pos, *p, 1, tlist, &ontrack)) == 0) {
756 if (*p == interesting_points.back()) {
759 /* move to next point type */
765 rpos = r->first_frame();
769 rpos = r->last_frame();
773 rpos = r->sync_position ();
781 RouteTimeAxisView *rtav;
783 if (ontrack != 0 && (rtav = dynamic_cast<RouteTimeAxisView*>(ontrack)) != 0 ) {
784 if (rtav->track() != 0) {
785 speed = rtav->track()->speed();
789 rpos = track_frame_to_session_frame (rpos, speed);
795 /* prevent duplicates, but we don't use set<> because we want to be able
799 vector<framepos_t>::iterator ri;
801 for (ri = region_boundary_cache.begin(); ri != region_boundary_cache.end(); ++ri) {
807 if (ri == region_boundary_cache.end()) {
808 region_boundary_cache.push_back (rpos);
815 /* finally sort to be sure that the order is correct */
817 sort (region_boundary_cache.begin(), region_boundary_cache.end());
820 boost::shared_ptr<Region>
821 Editor::find_next_region (framepos_t frame, RegionPoint point, int32_t dir, TrackViewList& tracks, TimeAxisView **ontrack)
823 TrackViewList::iterator i;
824 framepos_t closest = max_framepos;
825 boost::shared_ptr<Region> ret;
829 framepos_t track_frame;
830 RouteTimeAxisView *rtav;
832 for (i = tracks.begin(); i != tracks.end(); ++i) {
835 boost::shared_ptr<Region> r;
838 if ( (rtav = dynamic_cast<RouteTimeAxisView*>(*i)) != 0 ) {
839 if (rtav->track()!=0)
840 track_speed = rtav->track()->speed();
843 track_frame = session_frame_to_track_frame(frame, track_speed);
845 if ((r = (*i)->find_next_region (track_frame, point, dir)) == 0) {
851 rpos = r->first_frame ();
855 rpos = r->last_frame ();
859 rpos = r->sync_position ();
863 // rpos is a "track frame", converting it to "_session frame"
864 rpos = track_frame_to_session_frame(rpos, track_speed);
867 distance = rpos - frame;
869 distance = frame - rpos;
872 if (distance < closest) {
884 Editor::find_next_region_boundary (framepos_t pos, int32_t dir, const TrackViewList& tracks)
886 framecnt_t distance = max_framepos;
887 framepos_t current_nearest = -1;
889 for (TrackViewList::const_iterator i = tracks.begin(); i != tracks.end(); ++i) {
890 framepos_t contender;
893 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*i);
899 if ((contender = rtv->find_next_region_boundary (pos, dir)) < 0) {
903 d = ::llabs (pos - contender);
906 current_nearest = contender;
911 return current_nearest;
915 Editor::get_region_boundary (framepos_t pos, int32_t dir, bool with_selection, bool only_onscreen)
920 if (with_selection && Config->get_region_boundaries_from_selected_tracks()) {
922 if (!selection->tracks.empty()) {
924 target = find_next_region_boundary (pos, dir, selection->tracks);
928 if (only_onscreen || Config->get_region_boundaries_from_onscreen_tracks()) {
929 get_onscreen_tracks (tvl);
930 target = find_next_region_boundary (pos, dir, tvl);
932 target = find_next_region_boundary (pos, dir, track_views);
938 if (only_onscreen || Config->get_region_boundaries_from_onscreen_tracks()) {
939 get_onscreen_tracks (tvl);
940 target = find_next_region_boundary (pos, dir, tvl);
942 target = find_next_region_boundary (pos, dir, track_views);
950 Editor::cursor_to_region_boundary (bool with_selection, int32_t dir)
952 framepos_t pos = playhead_cursor->current_frame ();
959 // so we don't find the current region again..
960 if (dir > 0 || pos > 0) {
964 if ((target = get_region_boundary (pos, dir, with_selection, false)) < 0) {
968 _session->request_locate (target);
972 Editor::cursor_to_next_region_boundary (bool with_selection)
974 cursor_to_region_boundary (with_selection, 1);
978 Editor::cursor_to_previous_region_boundary (bool with_selection)
980 cursor_to_region_boundary (with_selection, -1);
984 Editor::cursor_to_region_point (EditorCursor* cursor, RegionPoint point, int32_t dir)
986 boost::shared_ptr<Region> r;
987 framepos_t pos = cursor->current_frame ();
993 TimeAxisView *ontrack = 0;
995 // so we don't find the current region again..
999 if (!selection->tracks.empty()) {
1001 r = find_next_region (pos, point, dir, selection->tracks, &ontrack);
1003 } else if (clicked_axisview) {
1006 t.push_back (clicked_axisview);
1008 r = find_next_region (pos, point, dir, t, &ontrack);
1012 r = find_next_region (pos, point, dir, track_views, &ontrack);
1021 pos = r->first_frame ();
1025 pos = r->last_frame ();
1029 pos = r->sync_position ();
1034 RouteTimeAxisView *rtav;
1036 if ( ontrack != 0 && (rtav = dynamic_cast<RouteTimeAxisView*>(ontrack)) != 0 ) {
1037 if (rtav->track() != 0) {
1038 speed = rtav->track()->speed();
1042 pos = track_frame_to_session_frame(pos, speed);
1044 if (cursor == playhead_cursor) {
1045 _session->request_locate (pos);
1047 cursor->set_position (pos);
1052 Editor::cursor_to_next_region_point (EditorCursor* cursor, RegionPoint point)
1054 cursor_to_region_point (cursor, point, 1);
1058 Editor::cursor_to_previous_region_point (EditorCursor* cursor, RegionPoint point)
1060 cursor_to_region_point (cursor, point, -1);
1064 Editor::cursor_to_selection_start (EditorCursor *cursor)
1068 switch (mouse_mode) {
1070 if (!selection->regions.empty()) {
1071 pos = selection->regions.start();
1076 if (!selection->time.empty()) {
1077 pos = selection->time.start ();
1085 if (cursor == playhead_cursor) {
1086 _session->request_locate (pos);
1088 cursor->set_position (pos);
1093 Editor::cursor_to_selection_end (EditorCursor *cursor)
1097 switch (mouse_mode) {
1099 if (!selection->regions.empty()) {
1100 pos = selection->regions.end_frame();
1105 if (!selection->time.empty()) {
1106 pos = selection->time.end_frame ();
1114 if (cursor == playhead_cursor) {
1115 _session->request_locate (pos);
1117 cursor->set_position (pos);
1122 Editor::selected_marker_to_region_boundary (bool with_selection, int32_t dir)
1132 if (selection->markers.empty()) {
1136 if (!mouse_frame (mouse, ignored)) {
1140 add_location_mark (mouse);
1143 if ((loc = find_location_from_marker (selection->markers.front(), ignored)) == 0) {
1147 framepos_t pos = loc->start();
1149 // so we don't find the current region again..
1150 if (dir > 0 || pos > 0) {
1154 if ((target = get_region_boundary (pos, dir, with_selection, false)) < 0) {
1158 loc->move_to (target, 0);
1162 Editor::selected_marker_to_next_region_boundary (bool with_selection)
1164 selected_marker_to_region_boundary (with_selection, 1);
1168 Editor::selected_marker_to_previous_region_boundary (bool with_selection)
1170 selected_marker_to_region_boundary (with_selection, -1);
1174 Editor::selected_marker_to_region_point (RegionPoint point, int32_t dir)
1176 boost::shared_ptr<Region> r;
1181 if (!_session || selection->markers.empty()) {
1185 if ((loc = find_location_from_marker (selection->markers.front(), ignored)) == 0) {
1189 TimeAxisView *ontrack = 0;
1193 // so we don't find the current region again..
1197 if (!selection->tracks.empty()) {
1199 r = find_next_region (pos, point, dir, selection->tracks, &ontrack);
1203 r = find_next_region (pos, point, dir, track_views, &ontrack);
1212 pos = r->first_frame ();
1216 pos = r->last_frame ();
1220 pos = r->adjust_to_sync (r->first_frame());
1225 RouteTimeAxisView *rtav;
1227 if (ontrack != 0 && (rtav = dynamic_cast<RouteTimeAxisView*>(ontrack)) != 0) {
1228 if (rtav->track() != 0) {
1229 speed = rtav->track()->speed();
1233 pos = track_frame_to_session_frame(pos, speed);
1235 loc->move_to (pos, 0);
1239 Editor::selected_marker_to_next_region_point (RegionPoint point)
1241 selected_marker_to_region_point (point, 1);
1245 Editor::selected_marker_to_previous_region_point (RegionPoint point)
1247 selected_marker_to_region_point (point, -1);
1251 Editor::selected_marker_to_selection_start ()
1257 if (!_session || selection->markers.empty()) {
1261 if ((loc = find_location_from_marker (selection->markers.front(), ignored)) == 0) {
1265 switch (mouse_mode) {
1267 if (!selection->regions.empty()) {
1268 pos = selection->regions.start();
1273 if (!selection->time.empty()) {
1274 pos = selection->time.start ();
1282 loc->move_to (pos, 0);
1286 Editor::selected_marker_to_selection_end ()
1292 if (!_session || selection->markers.empty()) {
1296 if ((loc = find_location_from_marker (selection->markers.front(), ignored)) == 0) {
1300 switch (mouse_mode) {
1302 if (!selection->regions.empty()) {
1303 pos = selection->regions.end_frame();
1308 if (!selection->time.empty()) {
1309 pos = selection->time.end_frame ();
1317 loc->move_to (pos, 0);
1321 Editor::scroll_playhead (bool forward)
1323 framepos_t pos = playhead_cursor->current_frame ();
1324 framecnt_t delta = (framecnt_t) floor (current_page_samples() / 0.8);
1327 if (pos == max_framepos) {
1331 if (pos < max_framepos - delta) {
1350 _session->request_locate (pos);
1354 Editor::cursor_align (bool playhead_to_edit)
1360 if (playhead_to_edit) {
1362 if (selection->markers.empty()) {
1366 _session->request_locate (selection->markers.front()->position(), _session->transport_rolling());
1369 const int32_t divisions = get_grid_music_divisions (0);
1370 /* move selected markers to playhead */
1372 for (MarkerSelection::iterator i = selection->markers.begin(); i != selection->markers.end(); ++i) {
1375 Location* loc = find_location_from_marker (*i, ignored);
1377 if (loc->is_mark()) {
1378 loc->set_start (playhead_cursor->current_frame (), false, true, divisions);
1380 loc->set (playhead_cursor->current_frame (),
1381 playhead_cursor->current_frame () + loc->length(), true, divisions);
1388 Editor::scroll_backward (float pages)
1390 framepos_t const one_page = (framepos_t) rint (_visible_canvas_width * samples_per_pixel);
1391 framepos_t const cnt = (framepos_t) floor (pages * one_page);
1394 if (leftmost_frame < cnt) {
1397 frame = leftmost_frame - cnt;
1400 reset_x_origin (frame);
1404 Editor::scroll_forward (float pages)
1406 framepos_t const one_page = (framepos_t) rint (_visible_canvas_width * samples_per_pixel);
1407 framepos_t const cnt = (framepos_t) floor (pages * one_page);
1410 if (max_framepos - cnt < leftmost_frame) {
1411 frame = max_framepos - cnt;
1413 frame = leftmost_frame + cnt;
1416 reset_x_origin (frame);
1420 Editor::scroll_tracks_down ()
1422 double vert_value = vertical_adjustment.get_value() + vertical_adjustment.get_page_size();
1423 if (vert_value > vertical_adjustment.get_upper() - _visible_canvas_height) {
1424 vert_value = vertical_adjustment.get_upper() - _visible_canvas_height;
1427 vertical_adjustment.set_value (vert_value);
1431 Editor::scroll_tracks_up ()
1433 vertical_adjustment.set_value (vertical_adjustment.get_value() - vertical_adjustment.get_page_size());
1437 Editor::scroll_tracks_down_line ()
1439 double vert_value = vertical_adjustment.get_value() + 60;
1441 if (vert_value > vertical_adjustment.get_upper() - _visible_canvas_height) {
1442 vert_value = vertical_adjustment.get_upper() - _visible_canvas_height;
1445 vertical_adjustment.set_value (vert_value);
1449 Editor::scroll_tracks_up_line ()
1451 reset_y_origin (vertical_adjustment.get_value() - 60);
1455 Editor::scroll_down_one_track (bool skip_child_views)
1457 TrackViewList::reverse_iterator next = track_views.rend();
1458 const double top_of_trackviews = vertical_adjustment.get_value();
1460 for (TrackViewList::reverse_iterator t = track_views.rbegin(); t != track_views.rend(); ++t) {
1461 if ((*t)->hidden()) {
1465 /* If this is the upper-most visible trackview, we want to display
1466 * the one above it (next)
1468 * Note that covers_y_position() is recursive and includes child views
1470 std::pair<TimeAxisView*,double> res = (*t)->covers_y_position (top_of_trackviews);
1473 if (skip_child_views) {
1476 /* automation lane (one level, non-recursive)
1478 * - if no automation lane exists -> move to next tack
1479 * - if the first (here: bottom-most) matches -> move to next tack
1480 * - if no y-axis match is found -> the current track is at the top
1481 * -> move to last (here: top-most) automation lane
1483 TimeAxisView::Children kids = (*t)->get_child_list();
1484 TimeAxisView::Children::reverse_iterator nkid = kids.rend();
1486 for (TimeAxisView::Children::reverse_iterator ci = kids.rbegin(); ci != kids.rend(); ++ci) {
1487 if ((*ci)->hidden()) {
1491 std::pair<TimeAxisView*,double> dev;
1492 dev = (*ci)->covers_y_position (top_of_trackviews);
1494 /* some automation lane is currently at the top */
1495 if (ci == kids.rbegin()) {
1496 /* first (bottom-most) autmation lane is at the top.
1497 * -> move to next track
1506 if (nkid != kids.rend()) {
1507 ensure_time_axis_view_is_visible (**nkid, true);
1515 /* move to the track below the first one that covers the */
1517 if (next != track_views.rend()) {
1518 ensure_time_axis_view_is_visible (**next, true);
1526 Editor::scroll_up_one_track (bool skip_child_views)
1528 TrackViewList::iterator prev = track_views.end();
1529 double top_of_trackviews = vertical_adjustment.get_value ();
1531 for (TrackViewList::iterator t = track_views.begin(); t != track_views.end(); ++t) {
1533 if ((*t)->hidden()) {
1537 /* find the trackview at the top of the trackview group
1539 * Note that covers_y_position() is recursive and includes child views
1541 std::pair<TimeAxisView*,double> res = (*t)->covers_y_position (top_of_trackviews);
1544 if (skip_child_views) {
1547 /* automation lane (one level, non-recursive)
1549 * - if no automation lane exists -> move to prev tack
1550 * - if no y-axis match is found -> the current track is at the top -> move to prev track
1551 * (actually last automation lane of previous track, see below)
1552 * - if first (top-most) lane is at the top -> move to this track
1553 * - else move up one lane
1555 TimeAxisView::Children kids = (*t)->get_child_list();
1556 TimeAxisView::Children::iterator pkid = kids.end();
1558 for (TimeAxisView::Children::iterator ci = kids.begin(); ci != kids.end(); ++ci) {
1559 if ((*ci)->hidden()) {
1563 std::pair<TimeAxisView*,double> dev;
1564 dev = (*ci)->covers_y_position (top_of_trackviews);
1566 /* some automation lane is currently at the top */
1567 if (ci == kids.begin()) {
1568 /* first (top-most) autmation lane is at the top.
1569 * jump directly to this track's top
1571 ensure_time_axis_view_is_visible (**t, true);
1574 else if (pkid != kids.end()) {
1575 /* some other automation lane is at the top.
1576 * move up to prev automation lane.
1578 ensure_time_axis_view_is_visible (**pkid, true);
1581 assert(0); // not reached
1592 if (prev != track_views.end()) {
1593 // move to bottom-most automation-lane of the previous track
1594 TimeAxisView::Children kids = (*prev)->get_child_list();
1595 TimeAxisView::Children::reverse_iterator pkid = kids.rend();
1596 if (!skip_child_views) {
1597 // find the last visible lane
1598 for (TimeAxisView::Children::reverse_iterator ci = kids.rbegin(); ci != kids.rend(); ++ci) {
1599 if (!(*ci)->hidden()) {
1605 if (pkid != kids.rend()) {
1606 ensure_time_axis_view_is_visible (**pkid, true);
1608 ensure_time_axis_view_is_visible (**prev, true);
1617 Editor::scroll_left_step ()
1619 framepos_t xdelta = (current_page_samples() / 8);
1621 if (leftmost_frame > xdelta) {
1622 reset_x_origin (leftmost_frame - xdelta);
1630 Editor::scroll_right_step ()
1632 framepos_t xdelta = (current_page_samples() / 8);
1634 if (max_framepos - xdelta > leftmost_frame) {
1635 reset_x_origin (leftmost_frame + xdelta);
1637 reset_x_origin (max_framepos - current_page_samples());
1642 Editor::scroll_left_half_page ()
1644 framepos_t xdelta = (current_page_samples() / 2);
1645 if (leftmost_frame > xdelta) {
1646 reset_x_origin (leftmost_frame - xdelta);
1653 Editor::scroll_right_half_page ()
1655 framepos_t xdelta = (current_page_samples() / 2);
1656 if (max_framepos - xdelta > leftmost_frame) {
1657 reset_x_origin (leftmost_frame + xdelta);
1659 reset_x_origin (max_framepos - current_page_samples());
1666 Editor::tav_zoom_step (bool coarser)
1668 DisplaySuspender ds;
1672 if (selection->tracks.empty()) {
1675 ts = &selection->tracks;
1678 for (TrackViewList::iterator i = ts->begin(); i != ts->end(); ++i) {
1679 TimeAxisView *tv = (static_cast<TimeAxisView*>(*i));
1680 tv->step_height (coarser);
1685 Editor::tav_zoom_smooth (bool coarser, bool force_all)
1687 DisplaySuspender ds;
1691 if (selection->tracks.empty() || force_all) {
1694 ts = &selection->tracks;
1697 for (TrackViewList::iterator i = ts->begin(); i != ts->end(); ++i) {
1698 TimeAxisView *tv = (static_cast<TimeAxisView*>(*i));
1699 uint32_t h = tv->current_height ();
1704 if (h >= TimeAxisView::preset_height (HeightSmall)) {
1709 tv->set_height (h + 5);
1715 Editor::temporal_zoom_step_mouse_focus_scale (bool zoom_out, double scale)
1717 Editing::ZoomFocus temp_focus = zoom_focus;
1718 zoom_focus = Editing::ZoomFocusMouse;
1719 temporal_zoom_step_scale (zoom_out, scale);
1720 zoom_focus = temp_focus;
1724 Editor::temporal_zoom_step_mouse_focus (bool zoom_out)
1726 temporal_zoom_step_mouse_focus_scale (zoom_out, 2.0);
1730 Editor::temporal_zoom_step (bool zoom_out)
1732 temporal_zoom_step_scale (zoom_out, 2.0);
1736 Editor::temporal_zoom_step_scale (bool zoom_out, double scale)
1738 ENSURE_GUI_THREAD (*this, &Editor::temporal_zoom_step, zoom_out, scale)
1740 framecnt_t nspp = samples_per_pixel;
1744 if (nspp == samples_per_pixel) {
1749 if (nspp == samples_per_pixel) {
1754 temporal_zoom (nspp);
1758 Editor::temporal_zoom (framecnt_t fpp)
1764 framepos_t current_page = current_page_samples();
1765 framepos_t current_leftmost = leftmost_frame;
1766 framepos_t current_rightmost;
1767 framepos_t current_center;
1768 framepos_t new_page_size;
1769 framepos_t half_page_size;
1770 framepos_t leftmost_after_zoom = 0;
1772 bool in_track_canvas;
1773 bool use_mouse_frame = true;
1777 if (fpp == samples_per_pixel) {
1781 // Imposing an arbitrary limit to zoom out as too much zoom out produces
1782 // segfaults for lack of memory. If somebody decides this is not high enough I
1783 // believe it can be raisen to higher values but some limit must be in place.
1785 // This constant represents 1 day @ 48kHz on a 1600 pixel wide display
1786 // all of which is used for the editor track displays. The whole day
1787 // would be 4147200000 samples, so 2592000 samples per pixel.
1789 nfpp = min (fpp, (framecnt_t) 2592000);
1790 nfpp = max ((framecnt_t) 1, nfpp);
1792 new_page_size = (framepos_t) floor (_visible_canvas_width * nfpp);
1793 half_page_size = new_page_size / 2;
1795 switch (zoom_focus) {
1797 leftmost_after_zoom = current_leftmost;
1800 case ZoomFocusRight:
1801 current_rightmost = leftmost_frame + current_page;
1802 if (current_rightmost < new_page_size) {
1803 leftmost_after_zoom = 0;
1805 leftmost_after_zoom = current_rightmost - new_page_size;
1809 case ZoomFocusCenter:
1810 current_center = current_leftmost + (current_page/2);
1811 if (current_center < half_page_size) {
1812 leftmost_after_zoom = 0;
1814 leftmost_after_zoom = current_center - half_page_size;
1818 case ZoomFocusPlayhead:
1819 /* centre playhead */
1820 l = playhead_cursor->current_frame () - (new_page_size * 0.5);
1823 leftmost_after_zoom = 0;
1824 } else if (l > max_framepos) {
1825 leftmost_after_zoom = max_framepos - new_page_size;
1827 leftmost_after_zoom = (framepos_t) l;
1831 case ZoomFocusMouse:
1832 /* try to keep the mouse over the same point in the display */
1834 if (_drags->active()) {
1835 where = _drags->current_pointer_frame ();
1836 } else if (!mouse_frame (where, in_track_canvas)) {
1837 use_mouse_frame = false;
1840 if (use_mouse_frame) {
1841 l = - ((new_page_size * ((where - current_leftmost)/(double)current_page)) - where);
1844 leftmost_after_zoom = 0;
1845 } else if (l > max_framepos) {
1846 leftmost_after_zoom = max_framepos - new_page_size;
1848 leftmost_after_zoom = (framepos_t) l;
1851 /* use playhead instead */
1852 where = playhead_cursor->current_frame ();
1854 if (where < half_page_size) {
1855 leftmost_after_zoom = 0;
1857 leftmost_after_zoom = where - half_page_size;
1863 /* try to keep the edit point in the same place */
1864 where = get_preferred_edit_position ();
1868 double l = - ((new_page_size * ((where - current_leftmost)/(double)current_page)) - where);
1871 leftmost_after_zoom = 0;
1872 } else if (l > max_framepos) {
1873 leftmost_after_zoom = max_framepos - new_page_size;
1875 leftmost_after_zoom = (framepos_t) l;
1879 /* edit point not defined */
1886 // leftmost_after_zoom = min (leftmost_after_zoom, _session->current_end_frame());
1888 reposition_and_zoom (leftmost_after_zoom, nfpp);
1892 Editor::calc_extra_zoom_edges(framepos_t &start, framepos_t &end)
1894 /* this func helps make sure we leave a little space
1895 at each end of the editor so that the zoom doesn't fit the region
1896 precisely to the screen.
1899 GdkScreen* screen = gdk_screen_get_default ();
1900 const gint pixwidth = gdk_screen_get_width (screen);
1901 const gint mmwidth = gdk_screen_get_width_mm (screen);
1902 const double pix_per_mm = (double) pixwidth/ (double) mmwidth;
1903 const double one_centimeter_in_pixels = pix_per_mm * 10.0;
1905 const framepos_t range = end - start;
1906 const framecnt_t new_fpp = (framecnt_t) ceil ((double) range / (double) _visible_canvas_width);
1907 const framepos_t extra_samples = (framepos_t) floor (one_centimeter_in_pixels * new_fpp);
1909 if (start > extra_samples) {
1910 start -= extra_samples;
1915 if (max_framepos - extra_samples > end) {
1916 end += extra_samples;
1923 Editor::get_selection_extents (framepos_t &start, framepos_t &end) const
1925 start = max_framepos;
1929 //ToDo: if notes are selected, set extents to that selection
1931 //ToDo: if control points are selected, set extents to that selection
1933 if ( !selection->regions.empty() ) {
1934 RegionSelection rs = get_regions_from_selection_and_entered ();
1936 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
1938 if ((*i)->region()->position() < start) {
1939 start = (*i)->region()->position();
1942 if ((*i)->region()->last_frame() + 1 > end) {
1943 end = (*i)->region()->last_frame() + 1;
1947 } else if (!selection->time.empty()) {
1948 start = selection->time.start();
1949 end = selection->time.end_frame();
1951 ret = false; //no selection found
1954 if ((start == 0 && end == 0) || end < start) {
1963 Editor::temporal_zoom_selection (Editing::ZoomAxis axes)
1965 if (!selection) return;
1967 //ToDo: if notes are selected, zoom to that
1969 //ToDo: if control points are selected, zoom to that
1971 if (axes == Horizontal || axes == Both) {
1973 framepos_t start, end;
1974 if (get_selection_extents (start, end)) {
1975 calc_extra_zoom_edges (start, end);
1976 temporal_zoom_by_frame (start, end);
1980 if (axes == Vertical || axes == Both) {
1986 Editor::temporal_zoom_session ()
1988 ENSURE_GUI_THREAD (*this, &Editor::temporal_zoom_session)
1991 framecnt_t start = _session->current_start_frame();
1992 framecnt_t end = _session->current_end_frame();
1994 if (_session->actively_recording () ) {
1995 framepos_t cur = playhead_cursor->current_frame ();
1997 /* recording beyond the end marker; zoom out
1998 * by 5 seconds more so that if 'follow
1999 * playhead' is active we don't immediately
2002 end = cur + _session->frame_rate() * 5;
2006 if ((start == 0 && end == 0) || end < start) {
2010 calc_extra_zoom_edges(start, end);
2012 temporal_zoom_by_frame (start, end);
2017 Editor::temporal_zoom_by_frame (framepos_t start, framepos_t end)
2019 if (!_session) return;
2021 if ((start == 0 && end == 0) || end < start) {
2025 framepos_t range = end - start;
2027 const framecnt_t new_fpp = (framecnt_t) ceil ((double) range / (double) _visible_canvas_width);
2029 framepos_t new_page = range;
2030 framepos_t middle = (framepos_t) floor ((double) start + ((double) range / 2.0f));
2031 framepos_t new_leftmost = (framepos_t) floor ((double) middle - ((double) new_page / 2.0f));
2033 if (new_leftmost > middle) {
2037 if (new_leftmost < 0) {
2041 reposition_and_zoom (new_leftmost, new_fpp);
2045 Editor::temporal_zoom_to_frame (bool coarser, framepos_t frame)
2051 framecnt_t range_before = frame - leftmost_frame;
2055 if (samples_per_pixel <= 1) {
2058 new_spp = samples_per_pixel + (samples_per_pixel/2);
2060 range_before += range_before/2;
2062 if (samples_per_pixel >= 1) {
2063 new_spp = samples_per_pixel - (samples_per_pixel/2);
2065 /* could bail out here since we cannot zoom any finer,
2066 but leave that to the equality test below
2068 new_spp = samples_per_pixel;
2071 range_before -= range_before/2;
2074 if (new_spp == samples_per_pixel) {
2078 /* zoom focus is automatically taken as @param frame when this
2082 framepos_t new_leftmost = frame - (framepos_t)range_before;
2084 if (new_leftmost > frame) {
2088 if (new_leftmost < 0) {
2092 reposition_and_zoom (new_leftmost, new_spp);
2097 Editor::choose_new_marker_name(string &name) {
2099 if (!UIConfiguration::instance().get_name_new_markers()) {
2100 /* don't prompt user for a new name */
2104 ArdourPrompter dialog (true);
2106 dialog.set_prompt (_("New Name:"));
2108 dialog.set_title (_("New Location Marker"));
2110 dialog.set_name ("MarkNameWindow");
2111 dialog.set_size_request (250, -1);
2112 dialog.set_position (Gtk::WIN_POS_MOUSE);
2114 dialog.add_button (Stock::OK, RESPONSE_ACCEPT);
2115 dialog.set_initial_text (name);
2119 switch (dialog.run ()) {
2120 case RESPONSE_ACCEPT:
2126 dialog.get_result(name);
2133 Editor::add_location_from_selection ()
2137 if (selection->time.empty()) {
2141 if (_session == 0 || clicked_axisview == 0) {
2145 framepos_t start = selection->time[clicked_selection].start;
2146 framepos_t end = selection->time[clicked_selection].end;
2148 _session->locations()->next_available_name(rangename,"selection");
2149 Location *location = new Location (*_session, start, end, rangename, Location::IsRangeMarker, get_grid_music_divisions(0));
2151 begin_reversible_command (_("add marker"));
2153 XMLNode &before = _session->locations()->get_state();
2154 _session->locations()->add (location, true);
2155 XMLNode &after = _session->locations()->get_state();
2156 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2158 commit_reversible_command ();
2162 Editor::add_location_mark (framepos_t where)
2166 select_new_marker = true;
2168 _session->locations()->next_available_name(markername,"mark");
2169 if (!choose_new_marker_name(markername)) {
2172 Location *location = new Location (*_session, where, where, markername, Location::IsMark, get_grid_music_divisions (0));
2173 begin_reversible_command (_("add marker"));
2175 XMLNode &before = _session->locations()->get_state();
2176 _session->locations()->add (location, true);
2177 XMLNode &after = _session->locations()->get_state();
2178 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2180 commit_reversible_command ();
2184 Editor::set_session_start_from_playhead ()
2190 if ((loc = _session->locations()->session_range_location()) == 0) { //should never happen
2191 _session->set_session_extents ( _session->audible_frame(), _session->audible_frame() );
2193 XMLNode &before = loc->get_state();
2195 _session->set_session_extents ( _session->audible_frame(), loc->end() );
2197 XMLNode &after = loc->get_state();
2199 begin_reversible_command (_("Set session start"));
2201 _session->add_command (new MementoCommand<Location>(*loc, &before, &after));
2203 commit_reversible_command ();
2208 Editor::set_session_end_from_playhead ()
2214 if ((loc = _session->locations()->session_range_location()) == 0) { //should never happen
2215 _session->set_session_extents ( _session->audible_frame(), _session->audible_frame() );
2217 XMLNode &before = loc->get_state();
2219 _session->set_session_extents ( loc->start(), _session->audible_frame() );
2221 XMLNode &after = loc->get_state();
2223 begin_reversible_command (_("Set session start"));
2225 _session->add_command (new MementoCommand<Location>(*loc, &before, &after));
2227 commit_reversible_command ();
2230 _session->set_end_is_free (false);
2235 Editor::toggle_location_at_playhead_cursor ()
2237 if (!do_remove_location_at_playhead_cursor())
2239 add_location_from_playhead_cursor();
2244 Editor::add_location_from_playhead_cursor ()
2246 add_location_mark (_session->audible_frame());
2250 Editor::do_remove_location_at_playhead_cursor ()
2252 bool removed = false;
2255 XMLNode &before = _session->locations()->get_state();
2257 //find location(s) at this time
2258 Locations::LocationList locs;
2259 _session->locations()->find_all_between (_session->audible_frame(), _session->audible_frame()+1, locs, Location::Flags(0));
2260 for (Locations::LocationList::iterator i = locs.begin(); i != locs.end(); ++i) {
2261 if ((*i)->is_mark()) {
2262 _session->locations()->remove (*i);
2269 begin_reversible_command (_("remove marker"));
2270 XMLNode &after = _session->locations()->get_state();
2271 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2272 commit_reversible_command ();
2279 Editor::remove_location_at_playhead_cursor ()
2281 do_remove_location_at_playhead_cursor ();
2284 /** Add a range marker around each selected region */
2286 Editor::add_locations_from_region ()
2288 RegionSelection rs = get_regions_from_selection_and_entered ();
2293 bool commit = false;
2295 XMLNode &before = _session->locations()->get_state();
2297 for (RegionSelection::iterator i = rs.begin (); i != rs.end (); ++i) {
2299 boost::shared_ptr<Region> region = (*i)->region ();
2301 Location *location = new Location (*_session, region->position(), region->last_frame(), region->name(), Location::IsRangeMarker, 0);
2303 _session->locations()->add (location, true);
2308 begin_reversible_command (selection->regions.size () > 1 ? _("add markers") : _("add marker"));
2309 XMLNode &after = _session->locations()->get_state();
2310 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2311 commit_reversible_command ();
2315 /** Add a single range marker around all selected regions */
2317 Editor::add_location_from_region ()
2319 RegionSelection rs = get_regions_from_selection_and_entered ();
2325 XMLNode &before = _session->locations()->get_state();
2329 if (rs.size() > 1) {
2330 _session->locations()->next_available_name(markername, "regions");
2332 RegionView* rv = *(rs.begin());
2333 boost::shared_ptr<Region> region = rv->region();
2334 markername = region->name();
2337 if (!choose_new_marker_name(markername)) {
2341 // single range spanning all selected
2342 Location *location = new Location (*_session, selection->regions.start(), selection->regions.end_frame(), markername, Location::IsRangeMarker, 0);
2343 _session->locations()->add (location, true);
2345 begin_reversible_command (_("add marker"));
2346 XMLNode &after = _session->locations()->get_state();
2347 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2348 commit_reversible_command ();
2354 Editor::jump_forward_to_mark ()
2360 framepos_t pos = _session->locations()->first_mark_after (playhead_cursor->current_frame());
2366 _session->request_locate (pos, _session->transport_rolling());
2370 Editor::jump_backward_to_mark ()
2376 framepos_t pos = _session->locations()->first_mark_before (playhead_cursor->current_frame());
2378 //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...
2379 if ( _session->transport_rolling() ) {
2380 if ( (playhead_cursor->current_frame() - pos) < _session->frame_rate()/2 ) {
2381 framepos_t prior = _session->locations()->first_mark_before ( pos );
2390 _session->request_locate (pos, _session->transport_rolling());
2396 framepos_t const pos = _session->audible_frame ();
2399 _session->locations()->next_available_name (markername, "mark");
2401 if (!choose_new_marker_name (markername)) {
2405 _session->locations()->add (new Location (*_session, pos, 0, markername, Location::IsMark, 0), true);
2409 Editor::clear_markers ()
2412 begin_reversible_command (_("clear markers"));
2414 XMLNode &before = _session->locations()->get_state();
2415 _session->locations()->clear_markers ();
2416 XMLNode &after = _session->locations()->get_state();
2417 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2419 commit_reversible_command ();
2424 Editor::clear_ranges ()
2427 begin_reversible_command (_("clear ranges"));
2429 XMLNode &before = _session->locations()->get_state();
2431 _session->locations()->clear_ranges ();
2433 XMLNode &after = _session->locations()->get_state();
2434 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2436 commit_reversible_command ();
2441 Editor::clear_locations ()
2443 begin_reversible_command (_("clear locations"));
2445 XMLNode &before = _session->locations()->get_state();
2446 _session->locations()->clear ();
2447 XMLNode &after = _session->locations()->get_state();
2448 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2450 commit_reversible_command ();
2454 Editor::unhide_markers ()
2456 for (LocationMarkerMap::iterator i = location_markers.begin(); i != location_markers.end(); ++i) {
2457 Location *l = (*i).first;
2458 if (l->is_hidden() && l->is_mark()) {
2459 l->set_hidden(false, this);
2465 Editor::unhide_ranges ()
2467 for (LocationMarkerMap::iterator i = location_markers.begin(); i != location_markers.end(); ++i) {
2468 Location *l = (*i).first;
2469 if (l->is_hidden() && l->is_range_marker()) {
2470 l->set_hidden(false, this);
2475 /* INSERT/REPLACE */
2478 Editor::insert_region_list_selection (float times)
2480 RouteTimeAxisView *tv = 0;
2481 boost::shared_ptr<Playlist> playlist;
2483 if (clicked_routeview != 0) {
2484 tv = clicked_routeview;
2485 } else if (!selection->tracks.empty()) {
2486 if ((tv = dynamic_cast<RouteTimeAxisView*>(selection->tracks.front())) == 0) {
2489 } else if (entered_track != 0) {
2490 if ((tv = dynamic_cast<RouteTimeAxisView*>(entered_track)) == 0) {
2497 if ((playlist = tv->playlist()) == 0) {
2501 boost::shared_ptr<Region> region = _regions->get_single_selection ();
2506 begin_reversible_command (_("insert region"));
2507 playlist->clear_changes ();
2508 playlist->add_region ((RegionFactory::create (region, true)), get_preferred_edit_position(), times);
2509 if (Config->get_edit_mode() == Ripple)
2510 playlist->ripple (get_preferred_edit_position(), region->length() * times, boost::shared_ptr<Region>());
2512 _session->add_command(new StatefulDiffCommand (playlist));
2513 commit_reversible_command ();
2516 /* BUILT-IN EFFECTS */
2519 Editor::reverse_selection ()
2524 /* GAIN ENVELOPE EDITING */
2527 Editor::edit_envelope ()
2534 Editor::transition_to_rolling (bool fwd)
2540 if (_session->config.get_external_sync()) {
2541 switch (Config->get_sync_source()) {
2545 /* transport controlled by the master */
2550 if (_session->is_auditioning()) {
2551 _session->cancel_audition ();
2555 _session->request_transport_speed (fwd ? 1.0f : -1.0f);
2559 Editor::play_from_start ()
2561 _session->request_locate (_session->current_start_frame(), true);
2565 Editor::play_from_edit_point ()
2567 _session->request_locate (get_preferred_edit_position(), true);
2571 Editor::play_from_edit_point_and_return ()
2573 framepos_t start_frame;
2574 framepos_t return_frame;
2576 start_frame = get_preferred_edit_position ( EDIT_IGNORE_PHEAD );
2578 if (_session->transport_rolling()) {
2579 _session->request_locate (start_frame, false);
2583 /* don't reset the return frame if its already set */
2585 if ((return_frame = _session->requested_return_frame()) < 0) {
2586 return_frame = _session->audible_frame();
2589 if (start_frame >= 0) {
2590 _session->request_roll_at_and_return (start_frame, return_frame);
2595 Editor::play_selection ()
2597 framepos_t start, end;
2598 if (!get_selection_extents ( start, end))
2601 AudioRange ar (start, end, 0);
2602 list<AudioRange> lar;
2605 _session->request_play_range (&lar, true);
2610 Editor::maybe_locate_with_edit_preroll (framepos_t location)
2612 if ( _session->transport_rolling() || !UIConfiguration::instance().get_follow_edits() || _session->config.get_external_sync() )
2615 location -= _session->preroll_samples (location);
2617 //don't try to locate before the beginning of time
2622 //if follow_playhead is on, keep the playhead on the screen
2623 if ( _follow_playhead )
2624 if ( location < leftmost_frame )
2625 location = leftmost_frame;
2627 _session->request_locate( location );
2631 Editor::play_with_preroll ()
2633 framepos_t start, end;
2634 if ( UIConfiguration::instance().get_follow_edits() && get_selection_extents ( start, end) ) {
2635 const framepos_t preroll = _session->preroll_samples (start);
2637 framepos_t ret = start;
2639 if (start > preroll) {
2640 start = start - preroll;
2643 end = end + preroll; //"post-roll"
2645 AudioRange ar (start, end, 0);
2646 list<AudioRange> lar;
2649 _session->request_play_range (&lar, true);
2650 _session->set_requested_return_frame (ret); //force auto-return to return to range start, without the preroll
2652 framepos_t ph = playhead_cursor->current_frame ();
2653 const framepos_t preroll = _session->preroll_samples (ph);
2656 start = ph - preroll;
2660 _session->request_locate (start, true);
2661 _session->set_requested_return_frame (ph); //force auto-return to return to playhead location, without the preroll
2666 Editor::rec_with_preroll ()
2668 framepos_t ph = playhead_cursor->current_frame ();
2669 framepos_t preroll = _session->preroll_samples (ph);
2670 _session->request_preroll_record_trim (ph, preroll);
2674 Editor::rec_with_count_in ()
2676 _session->request_count_in_record ();
2680 Editor::play_location (Location& location)
2682 if (location.start() <= location.end()) {
2686 _session->request_bounded_roll (location.start(), location.end());
2690 Editor::loop_location (Location& location)
2692 if (location.start() <= location.end()) {
2698 if ((tll = transport_loop_location()) != 0) {
2699 tll->set (location.start(), location.end());
2701 // enable looping, reposition and start rolling
2702 _session->request_locate (tll->start(), true);
2703 _session->request_play_loop (true);
2708 Editor::do_layer_operation (LayerOperation op)
2710 if (selection->regions.empty ()) {
2714 bool const multiple = selection->regions.size() > 1;
2718 begin_reversible_command (_("raise regions"));
2720 begin_reversible_command (_("raise region"));
2726 begin_reversible_command (_("raise regions to top"));
2728 begin_reversible_command (_("raise region to top"));
2734 begin_reversible_command (_("lower regions"));
2736 begin_reversible_command (_("lower region"));
2742 begin_reversible_command (_("lower regions to bottom"));
2744 begin_reversible_command (_("lower region"));
2749 set<boost::shared_ptr<Playlist> > playlists = selection->regions.playlists ();
2750 for (set<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
2751 (*i)->clear_owned_changes ();
2754 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
2755 boost::shared_ptr<Region> r = (*i)->region ();
2767 r->lower_to_bottom ();
2771 for (set<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
2772 vector<Command*> cmds;
2774 _session->add_commands (cmds);
2777 commit_reversible_command ();
2781 Editor::raise_region ()
2783 do_layer_operation (Raise);
2787 Editor::raise_region_to_top ()
2789 do_layer_operation (RaiseToTop);
2793 Editor::lower_region ()
2795 do_layer_operation (Lower);
2799 Editor::lower_region_to_bottom ()
2801 do_layer_operation (LowerToBottom);
2804 /** Show the region editor for the selected regions */
2806 Editor::show_region_properties ()
2808 selection->foreach_regionview (&RegionView::show_region_editor);
2811 /** Show the midi list editor for the selected MIDI regions */
2813 Editor::show_midi_list_editor ()
2815 selection->foreach_midi_regionview (&MidiRegionView::show_list_editor);
2819 Editor::rename_region ()
2821 RegionSelection rs = get_regions_from_selection_and_entered ();
2827 ArdourDialog d (_("Rename Region"), true, false);
2829 Label label (_("New name:"));
2832 hbox.set_spacing (6);
2833 hbox.pack_start (label, false, false);
2834 hbox.pack_start (entry, true, true);
2836 d.get_vbox()->set_border_width (12);
2837 d.get_vbox()->pack_start (hbox, false, false);
2839 d.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
2840 d.add_button(Gtk::Stock::OK, Gtk::RESPONSE_OK);
2842 d.set_size_request (300, -1);
2844 entry.set_text (rs.front()->region()->name());
2845 entry.select_region (0, -1);
2847 entry.signal_activate().connect (sigc::bind (sigc::mem_fun (d, &Dialog::response), RESPONSE_OK));
2853 int const ret = d.run();
2857 if (ret != RESPONSE_OK) {
2861 std::string str = entry.get_text();
2862 strip_whitespace_edges (str);
2864 rs.front()->region()->set_name (str);
2865 _regions->redisplay ();
2869 /** Start an audition of the first selected region */
2871 Editor::play_edit_range ()
2873 framepos_t start, end;
2875 if (get_edit_op_range (start, end)) {
2876 _session->request_bounded_roll (start, end);
2881 Editor::play_selected_region ()
2883 framepos_t start = max_framepos;
2886 RegionSelection rs = get_regions_from_selection_and_entered ();
2892 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
2893 if ((*i)->region()->position() < start) {
2894 start = (*i)->region()->position();
2896 if ((*i)->region()->last_frame() + 1 > end) {
2897 end = (*i)->region()->last_frame() + 1;
2901 _session->request_bounded_roll (start, end);
2905 Editor::audition_playlist_region_standalone (boost::shared_ptr<Region> region)
2907 _session->audition_region (region);
2911 Editor::region_from_selection ()
2913 if (clicked_axisview == 0) {
2917 if (selection->time.empty()) {
2921 framepos_t start = selection->time[clicked_selection].start;
2922 framepos_t end = selection->time[clicked_selection].end;
2924 TrackViewList tracks = get_tracks_for_range_action ();
2926 framepos_t selection_cnt = end - start + 1;
2928 for (TrackSelection::iterator i = tracks.begin(); i != tracks.end(); ++i) {
2929 boost::shared_ptr<Region> current;
2930 boost::shared_ptr<Playlist> pl;
2931 framepos_t internal_start;
2934 if ((pl = (*i)->playlist()) == 0) {
2938 if ((current = pl->top_region_at (start)) == 0) {
2942 internal_start = start - current->position();
2943 RegionFactory::region_name (new_name, current->name(), true);
2947 plist.add (ARDOUR::Properties::start, current->start() + internal_start);
2948 plist.add (ARDOUR::Properties::length, selection_cnt);
2949 plist.add (ARDOUR::Properties::name, new_name);
2950 plist.add (ARDOUR::Properties::layer, 0);
2952 boost::shared_ptr<Region> region (RegionFactory::create (current, plist));
2957 Editor::create_region_from_selection (vector<boost::shared_ptr<Region> >& new_regions)
2959 if (selection->time.empty() || selection->tracks.empty()) {
2963 framepos_t start, end;
2964 if (clicked_selection) {
2965 start = selection->time[clicked_selection].start;
2966 end = selection->time[clicked_selection].end;
2968 start = selection->time.start();
2969 end = selection->time.end_frame();
2972 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
2973 sort_track_selection (ts);
2975 for (TrackSelection::iterator i = ts.begin(); i != ts.end(); ++i) {
2976 boost::shared_ptr<Region> current;
2977 boost::shared_ptr<Playlist> playlist;
2978 framepos_t internal_start;
2981 if ((playlist = (*i)->playlist()) == 0) {
2985 if ((current = playlist->top_region_at(start)) == 0) {
2989 internal_start = start - current->position();
2990 RegionFactory::region_name (new_name, current->name(), true);
2994 plist.add (ARDOUR::Properties::start, current->start() + internal_start);
2995 plist.add (ARDOUR::Properties::length, end - start + 1);
2996 plist.add (ARDOUR::Properties::name, new_name);
2998 new_regions.push_back (RegionFactory::create (current, plist));
3003 Editor::split_multichannel_region ()
3005 RegionSelection rs = get_regions_from_selection_and_entered ();
3011 vector< boost::shared_ptr<Region> > v;
3013 for (list<RegionView*>::iterator x = rs.begin(); x != rs.end(); ++x) {
3014 (*x)->region()->separate_by_channel (*_session, v);
3019 Editor::new_region_from_selection ()
3021 region_from_selection ();
3022 cancel_selection ();
3026 add_if_covered (RegionView* rv, const AudioRange* ar, RegionSelection* rs)
3028 switch (rv->region()->coverage (ar->start, ar->end - 1)) {
3029 // n.b. -1 because AudioRange::end is one past the end, but coverage expects inclusive ranges
3030 case Evoral::OverlapNone:
3038 * - selected tracks, or if there are none...
3039 * - tracks containing selected regions, or if there are none...
3044 Editor::get_tracks_for_range_action () const
3048 if (selection->tracks.empty()) {
3050 /* use tracks with selected regions */
3052 RegionSelection rs = selection->regions;
3054 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3055 TimeAxisView* tv = &(*i)->get_time_axis_view();
3057 if (!t.contains (tv)) {
3063 /* no regions and no tracks: use all tracks */
3069 t = selection->tracks;
3072 return t.filter_to_unique_playlists();
3076 Editor::separate_regions_between (const TimeSelection& ts)
3078 bool in_command = false;
3079 boost::shared_ptr<Playlist> playlist;
3080 RegionSelection new_selection;
3082 TrackViewList tmptracks = get_tracks_for_range_action ();
3083 sort_track_selection (tmptracks);
3085 for (TrackSelection::iterator i = tmptracks.begin(); i != tmptracks.end(); ++i) {
3087 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> ((*i));
3093 if (!rtv->is_track()) {
3097 /* no edits to destructive tracks */
3099 if (rtv->track()->destructive()) {
3103 if ((playlist = rtv->playlist()) != 0) {
3105 playlist->clear_changes ();
3107 /* XXX need to consider musical time selections here at some point */
3109 double speed = rtv->track()->speed();
3111 for (list<AudioRange>::const_iterator t = ts.begin(); t != ts.end(); ++t) {
3113 sigc::connection c = rtv->view()->RegionViewAdded.connect (
3114 sigc::mem_fun(*this, &Editor::collect_new_region_view));
3116 latest_regionviews.clear ();
3118 playlist->partition ((framepos_t)((*t).start * speed),
3119 (framepos_t)((*t).end * speed), false);
3123 if (!latest_regionviews.empty()) {
3125 rtv->view()->foreach_regionview (sigc::bind (
3126 sigc::ptr_fun (add_if_covered),
3127 &(*t), &new_selection));
3130 begin_reversible_command (_("separate"));
3134 /* pick up changes to existing regions */
3136 vector<Command*> cmds;
3137 playlist->rdiff (cmds);
3138 _session->add_commands (cmds);
3140 /* pick up changes to the playlist itself (adds/removes)
3143 _session->add_command(new StatefulDiffCommand (playlist));
3150 // selection->set (new_selection);
3152 commit_reversible_command ();
3156 struct PlaylistState {
3157 boost::shared_ptr<Playlist> playlist;
3161 /** Take tracks from get_tracks_for_range_action and cut any regions
3162 * on those tracks so that the tracks are empty over the time
3166 Editor::separate_region_from_selection ()
3168 /* preferentially use *all* ranges in the time selection if we're in range mode
3169 to allow discontiguous operation, since get_edit_op_range() currently
3170 returns a single range.
3173 if (!selection->time.empty()) {
3175 separate_regions_between (selection->time);
3182 if (get_edit_op_range (start, end)) {
3184 AudioRange ar (start, end, 1);
3188 separate_regions_between (ts);
3194 Editor::separate_region_from_punch ()
3196 Location* loc = _session->locations()->auto_punch_location();
3198 separate_regions_using_location (*loc);
3203 Editor::separate_region_from_loop ()
3205 Location* loc = _session->locations()->auto_loop_location();
3207 separate_regions_using_location (*loc);
3212 Editor::separate_regions_using_location (Location& loc)
3214 if (loc.is_mark()) {
3218 AudioRange ar (loc.start(), loc.end(), 1);
3223 separate_regions_between (ts);
3226 /** Separate regions under the selected region */
3228 Editor::separate_under_selected_regions ()
3230 vector<PlaylistState> playlists;
3234 rs = get_regions_from_selection_and_entered();
3236 if (!_session || rs.empty()) {
3240 begin_reversible_command (_("separate region under"));
3242 list<boost::shared_ptr<Region> > regions_to_remove;
3244 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3245 // we can't just remove the region(s) in this loop because
3246 // this removes them from the RegionSelection, and they thus
3247 // disappear from underneath the iterator, and the ++i above
3248 // SEGVs in a puzzling fashion.
3250 // so, first iterate over the regions to be removed from rs and
3251 // add them to the regions_to_remove list, and then
3252 // iterate over the list to actually remove them.
3254 regions_to_remove.push_back ((*i)->region());
3257 for (list<boost::shared_ptr<Region> >::iterator rl = regions_to_remove.begin(); rl != regions_to_remove.end(); ++rl) {
3259 boost::shared_ptr<Playlist> playlist = (*rl)->playlist();
3262 // is this check necessary?
3266 vector<PlaylistState>::iterator i;
3268 //only take state if this is a new playlist.
3269 for (i = playlists.begin(); i != playlists.end(); ++i) {
3270 if ((*i).playlist == playlist) {
3275 if (i == playlists.end()) {
3277 PlaylistState before;
3278 before.playlist = playlist;
3279 before.before = &playlist->get_state();
3281 playlist->freeze ();
3282 playlists.push_back(before);
3285 //Partition on the region bounds
3286 playlist->partition ((*rl)->first_frame() - 1, (*rl)->last_frame() + 1, true);
3288 //Re-add region that was just removed due to the partition operation
3289 playlist->add_region( (*rl), (*rl)->first_frame() );
3292 vector<PlaylistState>::iterator pl;
3294 for (pl = playlists.begin(); pl != playlists.end(); ++pl) {
3295 (*pl).playlist->thaw ();
3296 _session->add_command(new MementoCommand<Playlist>(*(*pl).playlist, (*pl).before, &(*pl).playlist->get_state()));
3299 commit_reversible_command ();
3303 Editor::crop_region_to_selection ()
3305 if (!selection->time.empty()) {
3307 crop_region_to (selection->time.start(), selection->time.end_frame());
3314 if (get_edit_op_range (start, end)) {
3315 crop_region_to (start, end);
3322 Editor::crop_region_to (framepos_t start, framepos_t end)
3324 vector<boost::shared_ptr<Playlist> > playlists;
3325 boost::shared_ptr<Playlist> playlist;
3328 if (selection->tracks.empty()) {
3329 ts = track_views.filter_to_unique_playlists();
3331 ts = selection->tracks.filter_to_unique_playlists ();
3334 sort_track_selection (ts);
3336 for (TrackSelection::iterator i = ts.begin(); i != ts.end(); ++i) {
3338 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> ((*i));
3344 boost::shared_ptr<Track> t = rtv->track();
3346 if (t != 0 && ! t->destructive()) {
3348 if ((playlist = rtv->playlist()) != 0) {
3349 playlists.push_back (playlist);
3354 if (playlists.empty()) {
3359 framepos_t new_start;
3361 framecnt_t new_length;
3362 bool in_command = false;
3364 for (vector<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
3366 /* Only the top regions at start and end have to be cropped */
3367 boost::shared_ptr<Region> region_at_start = (*i)->top_region_at(start);
3368 boost::shared_ptr<Region> region_at_end = (*i)->top_region_at(end);
3370 vector<boost::shared_ptr<Region> > regions;
3372 if (region_at_start != 0) {
3373 regions.push_back (region_at_start);
3375 if (region_at_end != 0) {
3376 regions.push_back (region_at_end);
3379 /* now adjust lengths */
3380 for (vector<boost::shared_ptr<Region> >::iterator i = regions.begin(); i != regions.end(); ++i) {
3382 pos = (*i)->position();
3383 new_start = max (start, pos);
3384 if (max_framepos - pos > (*i)->length()) {
3385 new_end = pos + (*i)->length() - 1;
3387 new_end = max_framepos;
3389 new_end = min (end, new_end);
3390 new_length = new_end - new_start + 1;
3393 begin_reversible_command (_("trim to selection"));
3396 (*i)->clear_changes ();
3397 (*i)->trim_to (new_start, new_length);
3398 _session->add_command (new StatefulDiffCommand (*i));
3403 commit_reversible_command ();
3408 Editor::region_fill_track ()
3410 boost::shared_ptr<Playlist> playlist;
3411 RegionSelection regions = get_regions_from_selection_and_entered ();
3412 RegionSelection foo;
3414 framepos_t const end = _session->current_end_frame ();
3416 if (regions.empty () || regions.end_frame () + 1 >= end) {
3420 framepos_t const start_frame = regions.start ();
3421 framepos_t const end_frame = regions.end_frame ();
3422 framecnt_t const gap = end_frame - start_frame + 1;
3424 begin_reversible_command (Operations::region_fill);
3426 selection->clear_regions ();
3428 for (RegionSelection::iterator i = regions.begin(); i != regions.end(); ++i) {
3430 boost::shared_ptr<Region> r ((*i)->region());
3432 TimeAxisView& tv = (*i)->get_time_axis_view();
3433 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (&tv);
3434 latest_regionviews.clear ();
3435 sigc::connection c = rtv->view()->RegionViewAdded.connect (sigc::mem_fun(*this, &Editor::collect_new_region_view));
3437 framepos_t const position = end_frame + (r->first_frame() - start_frame + 1);
3438 playlist = (*i)->region()->playlist();
3439 playlist->clear_changes ();
3440 playlist->duplicate_until (r, position, gap, end);
3441 _session->add_command(new StatefulDiffCommand (playlist));
3445 foo.insert (foo.end(), latest_regionviews.begin(), latest_regionviews.end());
3449 selection->set (foo);
3452 commit_reversible_command ();
3456 Editor::set_region_sync_position ()
3458 set_sync_point (get_preferred_edit_position (), get_regions_from_selection_and_edit_point ());
3462 Editor::set_sync_point (framepos_t where, const RegionSelection& rs)
3464 bool in_command = false;
3466 for (RegionSelection::const_iterator r = rs.begin(); r != rs.end(); ++r) {
3468 if (!(*r)->region()->covers (where)) {
3472 boost::shared_ptr<Region> region ((*r)->region());
3475 begin_reversible_command (_("set sync point"));
3479 region->clear_changes ();
3480 region->set_sync_position (where);
3481 _session->add_command(new StatefulDiffCommand (region));
3485 commit_reversible_command ();
3489 /** Remove the sync positions of the selection */
3491 Editor::remove_region_sync ()
3493 RegionSelection rs = get_regions_from_selection_and_entered ();
3499 begin_reversible_command (_("remove region sync"));
3501 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3503 (*i)->region()->clear_changes ();
3504 (*i)->region()->clear_sync_position ();
3505 _session->add_command(new StatefulDiffCommand ((*i)->region()));
3508 commit_reversible_command ();
3512 Editor::naturalize_region ()
3514 RegionSelection rs = get_regions_from_selection_and_entered ();
3520 if (rs.size() > 1) {
3521 begin_reversible_command (_("move regions to original position"));
3523 begin_reversible_command (_("move region to original position"));
3526 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3527 (*i)->region()->clear_changes ();
3528 (*i)->region()->move_to_natural_position ();
3529 _session->add_command (new StatefulDiffCommand ((*i)->region()));
3532 commit_reversible_command ();
3536 Editor::align_regions (RegionPoint what)
3538 RegionSelection const rs = get_regions_from_selection_and_edit_point ();
3544 begin_reversible_command (_("align selection"));
3546 framepos_t const position = get_preferred_edit_position ();
3548 for (RegionSelection::const_iterator i = rs.begin(); i != rs.end(); ++i) {
3549 align_region_internal ((*i)->region(), what, position);
3552 commit_reversible_command ();
3555 struct RegionSortByTime {
3556 bool operator() (const RegionView* a, const RegionView* b) {
3557 return a->region()->position() < b->region()->position();
3562 Editor::align_regions_relative (RegionPoint point)
3564 RegionSelection const rs = get_regions_from_selection_and_edit_point ();
3570 framepos_t const position = get_preferred_edit_position ();
3572 framepos_t distance = 0;
3576 list<RegionView*> sorted;
3577 rs.by_position (sorted);
3579 boost::shared_ptr<Region> r ((*sorted.begin())->region());
3584 if (position > r->position()) {
3585 distance = position - r->position();
3587 distance = r->position() - position;
3593 if (position > r->last_frame()) {
3594 distance = position - r->last_frame();
3595 pos = r->position() + distance;
3597 distance = r->last_frame() - position;
3598 pos = r->position() - distance;
3604 pos = r->adjust_to_sync (position);
3605 if (pos > r->position()) {
3606 distance = pos - r->position();
3608 distance = r->position() - pos;
3614 if (pos == r->position()) {
3618 begin_reversible_command (_("align selection (relative)"));
3620 /* move first one specially */
3622 r->clear_changes ();
3623 r->set_position (pos);
3624 _session->add_command(new StatefulDiffCommand (r));
3626 /* move rest by the same amount */
3630 for (list<RegionView*>::iterator i = sorted.begin(); i != sorted.end(); ++i) {
3632 boost::shared_ptr<Region> region ((*i)->region());
3634 region->clear_changes ();
3637 region->set_position (region->position() + distance);
3639 region->set_position (region->position() - distance);
3642 _session->add_command(new StatefulDiffCommand (region));
3646 commit_reversible_command ();
3650 Editor::align_region (boost::shared_ptr<Region> region, RegionPoint point, framepos_t position)
3652 begin_reversible_command (_("align region"));
3653 align_region_internal (region, point, position);
3654 commit_reversible_command ();
3658 Editor::align_region_internal (boost::shared_ptr<Region> region, RegionPoint point, framepos_t position)
3660 region->clear_changes ();
3664 region->set_position (region->adjust_to_sync (position));
3668 if (position > region->length()) {
3669 region->set_position (position - region->length());
3674 region->set_position (position);
3678 _session->add_command(new StatefulDiffCommand (region));
3682 Editor::trim_region_front ()
3688 Editor::trim_region_back ()
3690 trim_region (false);
3694 Editor::trim_region (bool front)
3696 framepos_t where = get_preferred_edit_position();
3697 RegionSelection rs = get_regions_from_selection_and_edit_point ();
3703 begin_reversible_command (front ? _("trim front") : _("trim back"));
3705 for (list<RegionView*>::const_iterator i = rs.by_layer().begin(); i != rs.by_layer().end(); ++i) {
3706 if (!(*i)->region()->locked()) {
3708 (*i)->region()->clear_changes ();
3711 (*i)->region()->trim_front (where);
3713 (*i)->region()->trim_end (where);
3716 _session->add_command (new StatefulDiffCommand ((*i)->region()));
3720 commit_reversible_command ();
3723 /** Trim the end of the selected regions to the position of the edit cursor */
3725 Editor::trim_region_to_loop ()
3727 Location* loc = _session->locations()->auto_loop_location();
3731 trim_region_to_location (*loc, _("trim to loop"));
3735 Editor::trim_region_to_punch ()
3737 Location* loc = _session->locations()->auto_punch_location();
3741 trim_region_to_location (*loc, _("trim to punch"));
3745 Editor::trim_region_to_location (const Location& loc, const char* str)
3747 RegionSelection rs = get_regions_from_selection_and_entered ();
3748 bool in_command = false;
3750 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
3751 RegionView* rv = (*x);
3753 /* require region to span proposed trim */
3754 switch (rv->region()->coverage (loc.start(), loc.end())) {
3755 case Evoral::OverlapInternal:
3761 RouteTimeAxisView* tav = dynamic_cast<RouteTimeAxisView*> (&rv->get_time_axis_view());
3770 if (tav->track() != 0) {
3771 speed = tav->track()->speed();
3774 start = session_frame_to_track_frame (loc.start(), speed);
3775 end = session_frame_to_track_frame (loc.end(), speed);
3777 rv->region()->clear_changes ();
3778 rv->region()->trim_to (start, (end - start));
3781 begin_reversible_command (str);
3784 _session->add_command(new StatefulDiffCommand (rv->region()));
3788 commit_reversible_command ();
3793 Editor::trim_region_to_previous_region_end ()
3795 return trim_to_region(false);
3799 Editor::trim_region_to_next_region_start ()
3801 return trim_to_region(true);
3805 Editor::trim_to_region(bool forward)
3807 RegionSelection rs = get_regions_from_selection_and_entered ();
3808 bool in_command = false;
3810 boost::shared_ptr<Region> next_region;
3812 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
3814 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*x);
3820 AudioTimeAxisView* atav = dynamic_cast<AudioTimeAxisView*> (&arv->get_time_axis_view());
3828 if (atav->track() != 0) {
3829 speed = atav->track()->speed();
3833 boost::shared_ptr<Region> region = arv->region();
3834 boost::shared_ptr<Playlist> playlist (region->playlist());
3836 region->clear_changes ();
3840 next_region = playlist->find_next_region (region->first_frame(), Start, 1);
3846 region->trim_end((framepos_t) ( (next_region->first_frame() - 1) * speed));
3847 arv->region_changed (PropertyChange (ARDOUR::Properties::length));
3851 next_region = playlist->find_next_region (region->first_frame(), Start, 0);
3857 region->trim_front((framepos_t) ((next_region->last_frame() + 1) * speed));
3859 arv->region_changed (ARDOUR::bounds_change);
3863 begin_reversible_command (_("trim to region"));
3866 _session->add_command(new StatefulDiffCommand (region));
3870 commit_reversible_command ();
3875 Editor::unfreeze_route ()
3877 if (clicked_routeview == 0 || !clicked_routeview->is_track()) {
3881 clicked_routeview->track()->unfreeze ();
3885 Editor::_freeze_thread (void* arg)
3887 return static_cast<Editor*>(arg)->freeze_thread ();
3891 Editor::freeze_thread ()
3893 /* create event pool because we may need to talk to the session */
3894 SessionEvent::create_per_thread_pool ("freeze events", 64);
3895 /* create per-thread buffers for process() tree to use */
3896 clicked_routeview->audio_track()->freeze_me (*current_interthread_info);
3897 current_interthread_info->done = true;
3902 Editor::freeze_route ()
3908 /* stop transport before we start. this is important */
3910 _session->request_transport_speed (0.0);
3912 /* wait for just a little while, because the above call is asynchronous */
3914 Glib::usleep (250000);
3916 if (clicked_routeview == 0 || !clicked_routeview->is_audio_track()) {
3920 if (!clicked_routeview->track()->bounceable (clicked_routeview->track()->main_outs(), true)) {
3922 _("This track/bus cannot be frozen because the signal adds or loses channels before reaching the outputs.\n"
3923 "This is typically caused by plugins that generate stereo output from mono input or vice versa.")
3925 d.set_title (_("Cannot freeze"));
3930 if (clicked_routeview->track()->has_external_redirects()) {
3931 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"
3932 "Freezing will only process the signal as far as the first send/insert/return."),
3933 clicked_routeview->track()->name()), true, MESSAGE_INFO, BUTTONS_NONE, true);
3935 d.add_button (_("Freeze anyway"), Gtk::RESPONSE_OK);
3936 d.add_button (_("Don't freeze"), Gtk::RESPONSE_CANCEL);
3937 d.set_title (_("Freeze Limits"));
3939 int response = d.run ();
3942 case Gtk::RESPONSE_CANCEL:
3949 InterThreadInfo itt;
3950 current_interthread_info = &itt;
3952 InterthreadProgressWindow ipw (current_interthread_info, _("Freeze"), _("Cancel Freeze"));
3954 pthread_create_and_store (X_("freezer"), &itt.thread, _freeze_thread, this);
3956 CursorContext::Handle cursor_ctx = CursorContext::create(*this, _cursors->wait);
3958 while (!itt.done && !itt.cancel) {
3959 gtk_main_iteration ();
3962 pthread_join (itt.thread, 0);
3963 current_interthread_info = 0;
3967 Editor::bounce_range_selection (bool replace, bool enable_processing)
3969 if (selection->time.empty()) {
3973 TrackSelection views = selection->tracks;
3975 for (TrackViewList::iterator i = views.begin(); i != views.end(); ++i) {
3977 if (enable_processing) {
3979 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*i);
3981 if (rtv && rtv->track() && replace && enable_processing && !rtv->track()->bounceable (rtv->track()->main_outs(), false)) {
3983 _("You can't perform this operation because the processing of the signal "
3984 "will cause one or more of the tracks to end up with a region with more channels than this track has inputs.\n\n"
3985 "You can do this without processing, which is a different operation.")
3987 d.set_title (_("Cannot bounce"));
3994 framepos_t start = selection->time[clicked_selection].start;
3995 framepos_t end = selection->time[clicked_selection].end;
3996 framepos_t cnt = end - start + 1;
3997 bool in_command = false;
3999 for (TrackViewList::iterator i = views.begin(); i != views.end(); ++i) {
4001 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*i);
4007 boost::shared_ptr<Playlist> playlist;
4009 if ((playlist = rtv->playlist()) == 0) {
4013 InterThreadInfo itt;
4015 playlist->clear_changes ();
4016 playlist->clear_owned_changes ();
4018 boost::shared_ptr<Region> r;
4020 if (enable_processing) {
4021 r = rtv->track()->bounce_range (start, start+cnt, itt, rtv->track()->main_outs(), false);
4023 r = rtv->track()->bounce_range (start, start+cnt, itt, boost::shared_ptr<Processor>(), false);
4031 list<AudioRange> ranges;
4032 ranges.push_back (AudioRange (start, start+cnt, 0));
4033 playlist->cut (ranges); // discard result
4034 playlist->add_region (r, start);
4038 begin_reversible_command (_("bounce range"));
4041 vector<Command*> cmds;
4042 playlist->rdiff (cmds);
4043 _session->add_commands (cmds);
4045 _session->add_command (new StatefulDiffCommand (playlist));
4049 commit_reversible_command ();
4053 /** Delete selected regions, automation points or a time range */
4057 //special case: if the user is pointing in the editor/mixer strip, they may be trying to delete a plugin.
4058 //we need this because the editor-mixer strip is in the editor window, so it doesn't get the bindings from the mix window
4059 bool deleted = false;
4060 if ( current_mixer_strip && current_mixer_strip == MixerStrip::entered_mixer_strip() )
4061 deleted = current_mixer_strip->delete_processors ();
4067 /** Cut selected regions, automation points or a time range */
4074 /** Copy selected regions, automation points or a time range */
4082 /** @return true if a Cut, Copy or Clear is possible */
4084 Editor::can_cut_copy () const
4086 if (!selection->time.empty() || !selection->regions.empty() || !selection->points.empty())
4093 /** Cut, copy or clear selected regions, automation points or a time range.
4094 * @param op Operation (Delete, Cut, Copy or Clear)
4097 Editor::cut_copy (CutCopyOp op)
4099 /* only cancel selection if cut/copy is successful.*/
4105 opname = _("delete");
4114 opname = _("clear");
4118 /* if we're deleting something, and the mouse is still pressed,
4119 the thing we started a drag for will be gone when we release
4120 the mouse button(s). avoid this. see part 2 at the end of
4124 if (op == Delete || op == Cut || op == Clear) {
4125 if (_drags->active ()) {
4130 if ( op != Delete ) //"Delete" doesn't change copy/paste buf
4131 cut_buffer->clear ();
4133 if (entered_marker) {
4135 /* cut/delete op while pointing at a marker */
4138 Location* loc = find_location_from_marker (entered_marker, ignored);
4140 if (_session && loc) {
4141 entered_marker = NULL;
4142 Glib::signal_idle().connect (sigc::bind (sigc::mem_fun(*this, &Editor::really_remove_marker), loc));
4149 switch (mouse_mode) {
4152 begin_reversible_command (opname + ' ' + X_("MIDI"));
4154 commit_reversible_command ();
4160 bool did_edit = false;
4162 if (!selection->regions.empty() || !selection->points.empty()) {
4163 begin_reversible_command (opname + ' ' + _("objects"));
4166 if (!selection->regions.empty()) {
4167 cut_copy_regions (op, selection->regions);
4169 if (op == Cut || op == Delete) {
4170 selection->clear_regions ();
4174 if (!selection->points.empty()) {
4175 cut_copy_points (op);
4177 if (op == Cut || op == Delete) {
4178 selection->clear_points ();
4181 } else if (selection->time.empty()) {
4182 framepos_t start, end;
4183 /* no time selection, see if we can get an edit range
4186 if (get_edit_op_range (start, end)) {
4187 selection->set (start, end);
4189 } else if (!selection->time.empty()) {
4190 begin_reversible_command (opname + ' ' + _("range"));
4193 cut_copy_ranges (op);
4195 if (op == Cut || op == Delete) {
4196 selection->clear_time ();
4201 /* reset repeated paste state */
4204 commit_reversible_command ();
4207 if (op == Delete || op == Cut || op == Clear) {
4213 struct AutomationRecord {
4214 AutomationRecord () : state (0) , line(NULL) {}
4215 AutomationRecord (XMLNode* s, const AutomationLine* l) : state (s) , line (l) {}
4217 XMLNode* state; ///< state before any operation
4218 const AutomationLine* line; ///< line this came from
4219 boost::shared_ptr<Evoral::ControlList> copy; ///< copied events for the cut buffer
4221 struct PointsSelectionPositionSorter {
4222 bool operator() (ControlPoint* a, ControlPoint* b) {
4223 return (*(a->model()))->when < (*(b->model()))->when;
4226 /** Cut, copy or clear selected automation points.
4227 * @param op Operation (Cut, Copy or Clear)
4230 Editor::cut_copy_points (Editing::CutCopyOp op, Evoral::Beats earliest, bool midi)
4232 if (selection->points.empty ()) {
4236 /* XXX: not ideal, as there may be more than one track involved in the point selection */
4237 _last_cut_copy_source_track = &selection->points.front()->line().trackview;
4239 /* Keep a record of the AutomationLists that we end up using in this operation */
4240 typedef std::map<boost::shared_ptr<AutomationList>, AutomationRecord> Lists;
4243 /* user could select points in any order */
4244 selection->points.sort(PointsSelectionPositionSorter ());
4246 /* Go through all selected points, making an AutomationRecord for each distinct AutomationList */
4247 for (PointSelection::iterator sel_point = selection->points.begin(); sel_point != selection->points.end(); ++sel_point) {
4248 const AutomationLine& line = (*sel_point)->line();
4249 const boost::shared_ptr<AutomationList> al = line.the_list();
4250 if (lists.find (al) == lists.end ()) {
4251 /* We haven't seen this list yet, so make a record for it. This includes
4252 taking a copy of its current state, in case this is needed for undo later.
4254 lists[al] = AutomationRecord (&al->get_state (), &line);
4258 if (op == Cut || op == Copy) {
4259 /* This operation will involve putting things in the cut buffer, so create an empty
4260 ControlList for each of our source lists to put the cut buffer data in.
4262 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
4263 i->second.copy = i->first->create (i->first->parameter (), i->first->descriptor());
4266 /* Add all selected points to the relevant copy ControlLists */
4267 MusicFrame start (std::numeric_limits<framepos_t>::max(), 0);
4268 for (PointSelection::iterator sel_point = selection->points.begin(); sel_point != selection->points.end(); ++sel_point) {
4269 boost::shared_ptr<AutomationList> al = (*sel_point)->line().the_list();
4270 AutomationList::const_iterator ctrl_evt = (*sel_point)->model ();
4272 lists[al].copy->fast_simple_add ((*ctrl_evt)->when, (*ctrl_evt)->value);
4274 /* Update earliest MIDI start time in beats */
4275 earliest = std::min(earliest, Evoral::Beats((*ctrl_evt)->when));
4277 /* Update earliest session start time in frames */
4278 start.frame = std::min(start.frame, (*sel_point)->line().session_position(ctrl_evt));
4282 /* Snap start time backwards, so copy/paste is snap aligned. */
4284 if (earliest == Evoral::Beats::max()) {
4285 earliest = Evoral::Beats(); // Weird... don't offset
4287 earliest.round_down_to_beat();
4289 if (start.frame == std::numeric_limits<double>::max()) {
4290 start.frame = 0; // Weird... don't offset
4292 snap_to(start, RoundDownMaybe);
4295 const double line_offset = midi ? earliest.to_double() : start.frame;
4296 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
4297 /* Correct this copy list so that it is relative to the earliest
4298 start time, so relative ordering between points is preserved
4299 when copying from several lists and the paste starts at the
4300 earliest copied piece of data. */
4301 boost::shared_ptr<Evoral::ControlList> &al_cpy = i->second.copy;
4302 for (AutomationList::iterator ctrl_evt = al_cpy->begin(); ctrl_evt != al_cpy->end(); ++ctrl_evt) {
4303 (*ctrl_evt)->when -= line_offset;
4306 /* And add it to the cut buffer */
4307 cut_buffer->add (al_cpy);
4311 if (op == Delete || op == Cut) {
4312 /* This operation needs to remove things from the main AutomationList, so do that now */
4314 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
4315 i->first->freeze ();
4318 /* Remove each selected point from its AutomationList */
4319 for (PointSelection::iterator sel_point = selection->points.begin(); sel_point != selection->points.end(); ++sel_point) {
4320 AutomationLine& line = (*sel_point)->line ();
4321 boost::shared_ptr<AutomationList> al = line.the_list();
4325 if (dynamic_cast<AudioRegionGainLine*> (&line)) {
4326 /* removing of first and last gain point in region gain lines is prohibited*/
4327 if (line.is_last_point (*(*sel_point)) || line.is_first_point (*(*sel_point))) {
4333 al->erase ((*sel_point)->model ());
4337 /* Thaw the lists and add undo records for them */
4338 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
4339 boost::shared_ptr<AutomationList> al = i->first;
4341 _session->add_command (new MementoCommand<AutomationList> (*al.get(), i->second.state, &(al->get_state ())));
4346 /** Cut, copy or clear selected automation points.
4347 * @param op Operation (Cut, Copy or Clear)
4350 Editor::cut_copy_midi (CutCopyOp op)
4352 Evoral::Beats earliest = Evoral::Beats::max();
4353 for (MidiRegionSelection::iterator i = selection->midi_regions.begin(); i != selection->midi_regions.end(); ++i) {
4354 MidiRegionView* mrv = dynamic_cast<MidiRegionView*>(*i);
4356 if (!mrv->selection().empty()) {
4357 earliest = std::min(earliest, (*mrv->selection().begin())->note()->time());
4359 mrv->cut_copy_clear (op);
4361 /* XXX: not ideal, as there may be more than one track involved in the selection */
4362 _last_cut_copy_source_track = &mrv->get_time_axis_view();
4366 if (!selection->points.empty()) {
4367 cut_copy_points (op, earliest, true);
4368 if (op == Cut || op == Delete) {
4369 selection->clear_points ();
4374 struct lt_playlist {
4375 bool operator () (const PlaylistState& a, const PlaylistState& b) {
4376 return a.playlist < b.playlist;
4380 struct PlaylistMapping {
4382 boost::shared_ptr<Playlist> pl;
4384 PlaylistMapping (TimeAxisView* tvp) : tv (tvp) {}
4387 /** Remove `clicked_regionview' */
4389 Editor::remove_clicked_region ()
4391 if (clicked_routeview == 0 || clicked_regionview == 0) {
4395 begin_reversible_command (_("remove region"));
4397 boost::shared_ptr<Playlist> playlist = clicked_routeview->playlist();
4399 playlist->clear_changes ();
4400 playlist->clear_owned_changes ();
4401 playlist->remove_region (clicked_regionview->region());
4402 if (Config->get_edit_mode() == Ripple)
4403 playlist->ripple (clicked_regionview->region()->position(), -clicked_regionview->region()->length(), boost::shared_ptr<Region>());
4405 /* We might have removed regions, which alters other regions' layering_index,
4406 so we need to do a recursive diff here.
4408 vector<Command*> cmds;
4409 playlist->rdiff (cmds);
4410 _session->add_commands (cmds);
4412 _session->add_command(new StatefulDiffCommand (playlist));
4413 commit_reversible_command ();
4417 /** Remove the selected regions */
4419 Editor::remove_selected_regions ()
4421 RegionSelection rs = get_regions_from_selection_and_entered ();
4423 if (!_session || rs.empty()) {
4427 list<boost::shared_ptr<Region> > regions_to_remove;
4429 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
4430 // we can't just remove the region(s) in this loop because
4431 // this removes them from the RegionSelection, and they thus
4432 // disappear from underneath the iterator, and the ++i above
4433 // SEGVs in a puzzling fashion.
4435 // so, first iterate over the regions to be removed from rs and
4436 // add them to the regions_to_remove list, and then
4437 // iterate over the list to actually remove them.
4439 regions_to_remove.push_back ((*i)->region());
4442 vector<boost::shared_ptr<Playlist> > playlists;
4444 for (list<boost::shared_ptr<Region> >::iterator rl = regions_to_remove.begin(); rl != regions_to_remove.end(); ++rl) {
4446 boost::shared_ptr<Playlist> playlist = (*rl)->playlist();
4449 // is this check necessary?
4453 /* get_regions_from_selection_and_entered() guarantees that
4454 the playlists involved are unique, so there is no need
4458 playlists.push_back (playlist);
4460 playlist->clear_changes ();
4461 playlist->clear_owned_changes ();
4462 playlist->freeze ();
4463 playlist->remove_region (*rl);
4464 if (Config->get_edit_mode() == Ripple)
4465 playlist->ripple ((*rl)->position(), -(*rl)->length(), boost::shared_ptr<Region>());
4469 vector<boost::shared_ptr<Playlist> >::iterator pl;
4470 bool in_command = false;
4472 for (pl = playlists.begin(); pl != playlists.end(); ++pl) {
4475 /* We might have removed regions, which alters other regions' layering_index,
4476 so we need to do a recursive diff here.
4480 begin_reversible_command (_("remove region"));
4483 vector<Command*> cmds;
4484 (*pl)->rdiff (cmds);
4485 _session->add_commands (cmds);
4487 _session->add_command(new StatefulDiffCommand (*pl));
4491 commit_reversible_command ();
4495 /** Cut, copy or clear selected regions.
4496 * @param op Operation (Cut, Copy or Clear)
4499 Editor::cut_copy_regions (CutCopyOp op, RegionSelection& rs)
4501 /* we can't use a std::map here because the ordering is important, and we can't trivially sort
4502 a map when we want ordered access to both elements. i think.
4505 vector<PlaylistMapping> pmap;
4507 framepos_t first_position = max_framepos;
4509 typedef set<boost::shared_ptr<Playlist> > FreezeList;
4510 FreezeList freezelist;
4512 /* get ordering correct before we cut/copy */
4514 rs.sort_by_position_and_track ();
4516 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
4518 first_position = min ((framepos_t) (*x)->region()->position(), first_position);
4520 if (op == Cut || op == Clear || op == Delete) {
4521 boost::shared_ptr<Playlist> pl = (*x)->region()->playlist();
4524 FreezeList::iterator fl;
4526 // only take state if this is a new playlist.
4527 for (fl = freezelist.begin(); fl != freezelist.end(); ++fl) {
4533 if (fl == freezelist.end()) {
4534 pl->clear_changes();
4535 pl->clear_owned_changes ();
4537 freezelist.insert (pl);
4542 TimeAxisView* tv = &(*x)->get_time_axis_view();
4543 vector<PlaylistMapping>::iterator z;
4545 for (z = pmap.begin(); z != pmap.end(); ++z) {
4546 if ((*z).tv == tv) {
4551 if (z == pmap.end()) {
4552 pmap.push_back (PlaylistMapping (tv));
4556 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ) {
4558 boost::shared_ptr<Playlist> pl = (*x)->region()->playlist();
4561 /* region not yet associated with a playlist (e.g. unfinished
4568 TimeAxisView& tv = (*x)->get_time_axis_view();
4569 boost::shared_ptr<Playlist> npl;
4570 RegionSelection::iterator tmp;
4577 vector<PlaylistMapping>::iterator z;
4579 for (z = pmap.begin(); z != pmap.end(); ++z) {
4580 if ((*z).tv == &tv) {
4585 assert (z != pmap.end());
4588 npl = PlaylistFactory::create (pl->data_type(), *_session, "cutlist", true);
4596 boost::shared_ptr<Region> r = (*x)->region();
4597 boost::shared_ptr<Region> _xx;
4603 pl->remove_region (r);
4604 if (Config->get_edit_mode() == Ripple)
4605 pl->ripple (r->position(), -r->length(), boost::shared_ptr<Region>());
4609 _xx = RegionFactory::create (r);
4610 npl->add_region (_xx, r->position() - first_position);
4611 pl->remove_region (r);
4612 if (Config->get_edit_mode() == Ripple)
4613 pl->ripple (r->position(), -r->length(), boost::shared_ptr<Region>());
4617 /* copy region before adding, so we're not putting same object into two different playlists */
4618 npl->add_region (RegionFactory::create (r), r->position() - first_position);
4622 pl->remove_region (r);
4623 if (Config->get_edit_mode() == Ripple)
4624 pl->ripple (r->position(), -r->length(), boost::shared_ptr<Region>());
4633 list<boost::shared_ptr<Playlist> > foo;
4635 /* the pmap is in the same order as the tracks in which selected regions occurred */
4637 for (vector<PlaylistMapping>::iterator i = pmap.begin(); i != pmap.end(); ++i) {
4640 foo.push_back ((*i).pl);
4645 cut_buffer->set (foo);
4649 _last_cut_copy_source_track = 0;
4651 _last_cut_copy_source_track = pmap.front().tv;
4655 for (FreezeList::iterator pl = freezelist.begin(); pl != freezelist.end(); ++pl) {
4658 /* We might have removed regions, which alters other regions' layering_index,
4659 so we need to do a recursive diff here.
4661 vector<Command*> cmds;
4662 (*pl)->rdiff (cmds);
4663 _session->add_commands (cmds);
4665 _session->add_command (new StatefulDiffCommand (*pl));
4670 Editor::cut_copy_ranges (CutCopyOp op)
4672 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4674 /* Sort the track selection now, so that it if is used, the playlists
4675 selected by the calls below to cut_copy_clear are in the order that
4676 their tracks appear in the editor. This makes things like paste
4677 of ranges work properly.
4680 sort_track_selection (ts);
4683 if (!entered_track) {
4686 ts.push_back (entered_track);
4689 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4690 (*i)->cut_copy_clear (*selection, op);
4695 Editor::paste (float times, bool from_context)
4697 DEBUG_TRACE (DEBUG::CutNPaste, "paste to preferred edit pos\n");
4698 MusicFrame where (get_preferred_edit_position (EDIT_IGNORE_NONE, from_context), 0);
4699 paste_internal (where.frame, times, 0);
4703 Editor::mouse_paste ()
4705 MusicFrame where (0, 0);
4707 if (!mouse_frame (where.frame, ignored)) {
4712 paste_internal (where.frame, 1, where.division);
4716 Editor::paste_internal (framepos_t position, float times, const int32_t sub_num)
4718 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("apparent paste position is %1\n", position));
4720 if (cut_buffer->empty(internal_editing())) {
4724 if (position == max_framepos) {
4725 position = get_preferred_edit_position();
4726 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("preferred edit position is %1\n", position));
4729 if (position == last_paste_pos) {
4730 /* repeated paste in the same position */
4733 /* paste in new location, reset repeated paste state */
4735 last_paste_pos = position;
4738 /* get everything in the correct order */
4741 if (!selection->tracks.empty()) {
4742 /* If there is a track selection, paste into exactly those tracks and
4743 only those tracks. This allows the user to be explicit and override
4744 the below "do the reasonable thing" logic. */
4745 ts = selection->tracks.filter_to_unique_playlists ();
4746 sort_track_selection (ts);
4748 /* Figure out which track to base the paste at. */
4749 TimeAxisView* base_track = NULL;
4750 if (_edit_point == Editing::EditAtMouse && entered_track) {
4751 /* With the mouse edit point, paste onto the track under the mouse. */
4752 base_track = entered_track;
4753 } else if (_edit_point == Editing::EditAtMouse && entered_regionview) {
4754 /* With the mouse edit point, paste onto the track of the region under the mouse. */
4755 base_track = &entered_regionview->get_time_axis_view();
4756 } else if (_last_cut_copy_source_track) {
4757 /* Paste to the track that the cut/copy came from (see mantis #333). */
4758 base_track = _last_cut_copy_source_track;
4760 /* This is "impossible" since we've copied... well, do nothing. */
4764 /* Walk up to parent if necessary, so base track is a route. */
4765 while (base_track->get_parent()) {
4766 base_track = base_track->get_parent();
4769 /* Add base track and all tracks below it. The paste logic will select
4770 the appropriate object types from the cut buffer in relative order. */
4771 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4772 if ((*i)->order() >= base_track->order()) {
4777 /* Sort tracks so the nth track of type T will pick the nth object of type T. */
4778 sort_track_selection (ts);
4780 /* Add automation children of each track in order, for pasting several lines. */
4781 for (TrackViewList::iterator i = ts.begin(); i != ts.end();) {
4782 /* Add any automation children for pasting several lines */
4783 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*i++);
4788 typedef RouteTimeAxisView::AutomationTracks ATracks;
4789 const ATracks& atracks = rtv->automation_tracks();
4790 for (ATracks::const_iterator a = atracks.begin(); a != atracks.end(); ++a) {
4791 i = ts.insert(i, a->second.get());
4796 /* We now have a list of trackviews starting at base_track, including
4797 automation children, in the order shown in the editor, e.g. R1,
4798 R1.A1, R1.A2, R2, R2.A1, ... */
4801 begin_reversible_command (Operations::paste);
4803 if (ts.size() == 1 && cut_buffer->lines.size() == 1 &&
4804 dynamic_cast<AutomationTimeAxisView*>(ts.front())) {
4805 /* Only one line copied, and one automation track selected. Do a
4806 "greedy" paste from one automation type to another. */
4808 PasteContext ctx(paste_count, times, ItemCounts(), true);
4809 ts.front()->paste (position, *cut_buffer, ctx, sub_num);
4813 /* Paste into tracks */
4815 PasteContext ctx(paste_count, times, ItemCounts(), false);
4816 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4817 (*i)->paste (position, *cut_buffer, ctx, sub_num);
4821 commit_reversible_command ();
4825 Editor::duplicate_regions (float times)
4827 RegionSelection rs (get_regions_from_selection_and_entered());
4828 duplicate_some_regions (rs, times);
4832 Editor::duplicate_some_regions (RegionSelection& regions, float times)
4834 if (regions.empty ()) {
4838 boost::shared_ptr<Playlist> playlist;
4839 RegionSelection sel = regions; // clear (below) may clear the argument list if its the current region selection
4840 RegionSelection foo;
4842 framepos_t const start_frame = regions.start ();
4843 framepos_t const end_frame = regions.end_frame ();
4844 framecnt_t const gap = end_frame - start_frame + 1;
4846 begin_reversible_command (Operations::duplicate_region);
4848 selection->clear_regions ();
4850 for (RegionSelection::iterator i = sel.begin(); i != sel.end(); ++i) {
4852 boost::shared_ptr<Region> r ((*i)->region());
4854 TimeAxisView& tv = (*i)->get_time_axis_view();
4855 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (&tv);
4856 latest_regionviews.clear ();
4857 sigc::connection c = rtv->view()->RegionViewAdded.connect (sigc::mem_fun(*this, &Editor::collect_new_region_view));
4859 framepos_t const position = end_frame + (r->first_frame() - start_frame + 1);
4860 playlist = (*i)->region()->playlist();
4861 playlist->clear_changes ();
4862 playlist->duplicate (r, position, gap, times);
4863 _session->add_command(new StatefulDiffCommand (playlist));
4867 foo.insert (foo.end(), latest_regionviews.begin(), latest_regionviews.end());
4871 selection->set (foo);
4874 commit_reversible_command ();
4878 Editor::duplicate_selection (float times)
4880 if (selection->time.empty() || selection->tracks.empty()) {
4884 boost::shared_ptr<Playlist> playlist;
4886 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4888 bool in_command = false;
4890 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4891 if ((playlist = (*i)->playlist()) == 0) {
4894 playlist->clear_changes ();
4896 if (clicked_selection) {
4897 playlist->duplicate_range (selection->time[clicked_selection], times);
4899 playlist->duplicate_ranges (selection->time, times);
4903 begin_reversible_command (_("duplicate range selection"));
4906 _session->add_command (new StatefulDiffCommand (playlist));
4911 if (times == 1.0f) {
4912 // now "move" range selection to after the current range selection
4913 framecnt_t distance = 0;
4915 if (clicked_selection) {
4917 selection->time[clicked_selection].end - selection->time[clicked_selection].start;
4919 distance = selection->time.end_frame () - selection->time.start ();
4922 selection->move_time (distance);
4924 commit_reversible_command ();
4928 /** Reset all selected points to the relevant default value */
4930 Editor::reset_point_selection ()
4932 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
4933 ARDOUR::AutomationList::iterator j = (*i)->model ();
4934 (*j)->value = (*i)->line().the_list()->default_value ();
4939 Editor::center_playhead ()
4941 float const page = _visible_canvas_width * samples_per_pixel;
4942 center_screen_internal (playhead_cursor->current_frame (), page);
4946 Editor::center_edit_point ()
4948 float const page = _visible_canvas_width * samples_per_pixel;
4949 center_screen_internal (get_preferred_edit_position(), page);
4952 /** Caller must begin and commit a reversible command */
4954 Editor::clear_playlist (boost::shared_ptr<Playlist> playlist)
4956 playlist->clear_changes ();
4958 _session->add_command (new StatefulDiffCommand (playlist));
4962 Editor::nudge_track (bool use_edit, bool forwards)
4964 boost::shared_ptr<Playlist> playlist;
4965 framepos_t distance;
4966 framepos_t next_distance;
4970 start = get_preferred_edit_position();
4975 if ((distance = get_nudge_distance (start, next_distance)) == 0) {
4979 if (selection->tracks.empty()) {
4983 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4984 bool in_command = false;
4986 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4988 if ((playlist = (*i)->playlist()) == 0) {
4992 playlist->clear_changes ();
4993 playlist->clear_owned_changes ();
4995 playlist->nudge_after (start, distance, forwards);
4998 begin_reversible_command (_("nudge track"));
5001 vector<Command*> cmds;
5003 playlist->rdiff (cmds);
5004 _session->add_commands (cmds);
5006 _session->add_command (new StatefulDiffCommand (playlist));
5010 commit_reversible_command ();
5015 Editor::remove_last_capture ()
5017 vector<string> choices;
5024 if (Config->get_verify_remove_last_capture()) {
5025 prompt = _("Do you really want to destroy the last capture?"
5026 "\n(This is destructive and cannot be undone)");
5028 choices.push_back (_("No, do nothing."));
5029 choices.push_back (_("Yes, destroy it."));
5031 Gtkmm2ext::Choice prompter (_("Destroy last capture"), prompt, choices);
5033 if (prompter.run () == 1) {
5034 _session->remove_last_capture ();
5035 _regions->redisplay ();
5039 _session->remove_last_capture();
5040 _regions->redisplay ();
5045 Editor::normalize_region ()
5051 RegionSelection rs = get_regions_from_selection_and_entered ();
5057 NormalizeDialog dialog (rs.size() > 1);
5059 if (dialog.run () != RESPONSE_ACCEPT) {
5063 CursorContext::Handle cursor_ctx = CursorContext::create(*this, _cursors->wait);
5066 /* XXX: should really only count audio regions here */
5067 int const regions = rs.size ();
5069 /* Make a list of the selected audio regions' maximum amplitudes, and also
5070 obtain the maximum amplitude of them all.
5072 list<double> max_amps;
5073 list<double> rms_vals;
5076 bool use_rms = dialog.constrain_rms ();
5078 for (RegionSelection::const_iterator i = rs.begin(); i != rs.end(); ++i) {
5079 AudioRegionView const * arv = dynamic_cast<AudioRegionView const *> (*i);
5083 dialog.descend (1.0 / regions);
5084 double const a = arv->audio_region()->maximum_amplitude (&dialog);
5086 double r = arv->audio_region()->rms (&dialog);
5087 max_rms = max (max_rms, r);
5088 rms_vals.push_back (r);
5092 /* the user cancelled the operation */
5096 max_amps.push_back (a);
5097 max_amp = max (max_amp, a);
5101 list<double>::const_iterator a = max_amps.begin ();
5102 list<double>::const_iterator l = rms_vals.begin ();
5103 bool in_command = false;
5105 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
5106 AudioRegionView* const arv = dynamic_cast<AudioRegionView*> (*r);
5111 arv->region()->clear_changes ();
5113 double amp = dialog.normalize_individually() ? *a : max_amp;
5114 double target = dialog.target_peak (); // dB
5117 double const amp_rms = dialog.normalize_individually() ? *l : max_rms;
5118 const double t_rms = dialog.target_rms ();
5119 const gain_t c_peak = dB_to_coefficient (target);
5120 const gain_t c_rms = dB_to_coefficient (t_rms);
5121 if ((amp_rms / c_rms) > (amp / c_peak)) {
5127 arv->audio_region()->normalize (amp, target);
5130 begin_reversible_command (_("normalize"));
5133 _session->add_command (new StatefulDiffCommand (arv->region()));
5140 commit_reversible_command ();
5146 Editor::reset_region_scale_amplitude ()
5152 RegionSelection rs = get_regions_from_selection_and_entered ();
5158 bool in_command = false;
5160 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
5161 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
5164 arv->region()->clear_changes ();
5165 arv->audio_region()->set_scale_amplitude (1.0f);
5168 begin_reversible_command ("reset gain");
5171 _session->add_command (new StatefulDiffCommand (arv->region()));
5175 commit_reversible_command ();
5180 Editor::adjust_region_gain (bool up)
5182 RegionSelection rs = get_regions_from_selection_and_entered ();
5184 if (!_session || rs.empty()) {
5188 bool in_command = false;
5190 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
5191 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
5196 arv->region()->clear_changes ();
5198 double dB = accurate_coefficient_to_dB (arv->audio_region()->scale_amplitude ());
5206 arv->audio_region()->set_scale_amplitude (dB_to_coefficient (dB));
5209 begin_reversible_command ("adjust region gain");
5212 _session->add_command (new StatefulDiffCommand (arv->region()));
5216 commit_reversible_command ();
5222 Editor::reverse_region ()
5228 Reverse rev (*_session);
5229 apply_filter (rev, _("reverse regions"));
5233 Editor::strip_region_silence ()
5239 RegionSelection rs = get_regions_from_selection_and_entered ();
5245 std::list<RegionView*> audio_only;
5247 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5248 AudioRegionView* const arv = dynamic_cast<AudioRegionView*> (*i);
5250 audio_only.push_back (arv);
5254 assert (!audio_only.empty());
5256 StripSilenceDialog d (_session, audio_only);
5257 int const r = d.run ();
5261 if (r == Gtk::RESPONSE_OK) {
5262 ARDOUR::AudioIntervalMap silences;
5263 d.silences (silences);
5264 StripSilence s (*_session, silences, d.fade_length());
5266 apply_filter (s, _("strip silence"), &d);
5271 Editor::apply_midi_note_edit_op_to_region (MidiOperator& op, MidiRegionView& mrv)
5273 Evoral::Sequence<Evoral::Beats>::Notes selected;
5274 mrv.selection_as_notelist (selected, true);
5276 vector<Evoral::Sequence<Evoral::Beats>::Notes> v;
5277 v.push_back (selected);
5279 Evoral::Beats pos_beats = Evoral::Beats (mrv.midi_region()->beat()) - mrv.midi_region()->start_beats();
5281 return op (mrv.midi_region()->model(), pos_beats, v);
5285 Editor::apply_midi_note_edit_op (MidiOperator& op, const RegionSelection& rs)
5291 bool in_command = false;
5293 for (RegionSelection::const_iterator r = rs.begin(); r != rs.end(); ) {
5294 RegionSelection::const_iterator tmp = r;
5297 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*r);
5300 Command* cmd = apply_midi_note_edit_op_to_region (op, *mrv);
5303 begin_reversible_command (op.name ());
5307 _session->add_command (cmd);
5315 commit_reversible_command ();
5320 Editor::fork_region ()
5322 RegionSelection rs = get_regions_from_selection_and_entered ();
5328 CursorContext::Handle cursor_ctx = CursorContext::create(*this, _cursors->wait);
5329 bool in_command = false;
5333 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
5334 RegionSelection::iterator tmp = r;
5337 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*>(*r);
5341 boost::shared_ptr<Playlist> playlist = mrv->region()->playlist();
5342 boost::shared_ptr<MidiSource> new_source = _session->create_midi_source_by_stealing_name (mrv->midi_view()->track());
5343 boost::shared_ptr<MidiRegion> newregion = mrv->midi_region()->clone (new_source);
5346 begin_reversible_command (_("Fork Region(s)"));
5349 playlist->clear_changes ();
5350 playlist->replace_region (mrv->region(), newregion, mrv->region()->position());
5351 _session->add_command(new StatefulDiffCommand (playlist));
5353 error << string_compose (_("Could not unlink %1"), mrv->region()->name()) << endmsg;
5361 commit_reversible_command ();
5366 Editor::quantize_region ()
5369 quantize_regions(get_regions_from_selection_and_entered ());
5374 Editor::quantize_regions (const RegionSelection& rs)
5376 if (rs.n_midi_regions() == 0) {
5380 if (!quantize_dialog) {
5381 quantize_dialog = new QuantizeDialog (*this);
5384 if (quantize_dialog->is_mapped()) {
5385 /* in progress already */
5389 quantize_dialog->present ();
5390 const int r = quantize_dialog->run ();
5391 quantize_dialog->hide ();
5393 if (r == Gtk::RESPONSE_OK) {
5394 Quantize quant (quantize_dialog->snap_start(),
5395 quantize_dialog->snap_end(),
5396 quantize_dialog->start_grid_size(),
5397 quantize_dialog->end_grid_size(),
5398 quantize_dialog->strength(),
5399 quantize_dialog->swing(),
5400 quantize_dialog->threshold());
5402 apply_midi_note_edit_op (quant, rs);
5407 Editor::legatize_region (bool shrink_only)
5410 legatize_regions(get_regions_from_selection_and_entered (), shrink_only);
5415 Editor::legatize_regions (const RegionSelection& rs, bool shrink_only)
5417 if (rs.n_midi_regions() == 0) {
5421 Legatize legatize(shrink_only);
5422 apply_midi_note_edit_op (legatize, rs);
5426 Editor::transform_region ()
5429 transform_regions(get_regions_from_selection_and_entered ());
5434 Editor::transform_regions (const RegionSelection& rs)
5436 if (rs.n_midi_regions() == 0) {
5443 const int r = td.run();
5446 if (r == Gtk::RESPONSE_OK) {
5447 Transform transform(td.get());
5448 apply_midi_note_edit_op(transform, rs);
5453 Editor::transpose_region ()
5456 transpose_regions(get_regions_from_selection_and_entered ());
5461 Editor::transpose_regions (const RegionSelection& rs)
5463 if (rs.n_midi_regions() == 0) {
5468 int const r = d.run ();
5470 if (r == RESPONSE_ACCEPT) {
5471 Transpose transpose(d.semitones ());
5472 apply_midi_note_edit_op (transpose, rs);
5477 Editor::insert_patch_change (bool from_context)
5479 RegionSelection rs = get_regions_from_selection_and_entered ();
5485 const framepos_t p = get_preferred_edit_position (EDIT_IGNORE_NONE, from_context);
5487 /* XXX: bit of a hack; use the MIDNAM from the first selected region;
5488 there may be more than one, but the PatchChangeDialog can only offer
5489 one set of patch menus.
5491 MidiRegionView* first = dynamic_cast<MidiRegionView*> (rs.front ());
5493 Evoral::PatchChange<Evoral::Beats> empty (Evoral::Beats(), 0, 0, 0);
5494 PatchChangeDialog d (0, _session, empty, first->instrument_info(), Gtk::Stock::ADD);
5496 if (d.run() == RESPONSE_CANCEL) {
5500 for (RegionSelection::iterator i = rs.begin (); i != rs.end(); ++i) {
5501 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*i);
5503 if (p >= mrv->region()->first_frame() && p <= mrv->region()->last_frame()) {
5504 mrv->add_patch_change (p - mrv->region()->position(), d.patch ());
5511 Editor::apply_filter (Filter& filter, string command, ProgressReporter* progress)
5513 RegionSelection rs = get_regions_from_selection_and_entered ();
5519 CursorContext::Handle cursor_ctx = CursorContext::create(*this, _cursors->wait);
5520 bool in_command = false;
5525 int const N = rs.size ();
5527 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
5528 RegionSelection::iterator tmp = r;
5531 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
5533 boost::shared_ptr<Playlist> playlist = arv->region()->playlist();
5536 progress->descend (1.0 / N);
5539 if (arv->audio_region()->apply (filter, progress) == 0) {
5541 playlist->clear_changes ();
5542 playlist->clear_owned_changes ();
5545 begin_reversible_command (command);
5549 if (filter.results.empty ()) {
5551 /* no regions returned; remove the old one */
5552 playlist->remove_region (arv->region ());
5556 std::vector<boost::shared_ptr<Region> >::iterator res = filter.results.begin ();
5558 /* first region replaces the old one */
5559 playlist->replace_region (arv->region(), *res, (*res)->position());
5563 while (res != filter.results.end()) {
5564 playlist->add_region (*res, (*res)->position());
5570 /* We might have removed regions, which alters other regions' layering_index,
5571 so we need to do a recursive diff here.
5573 vector<Command*> cmds;
5574 playlist->rdiff (cmds);
5575 _session->add_commands (cmds);
5577 _session->add_command(new StatefulDiffCommand (playlist));
5581 progress->ascend ();
5590 commit_reversible_command ();
5595 Editor::external_edit_region ()
5601 Editor::reset_region_gain_envelopes ()
5603 RegionSelection rs = get_regions_from_selection_and_entered ();
5605 if (!_session || rs.empty()) {
5609 bool in_command = false;
5611 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5612 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
5614 boost::shared_ptr<AutomationList> alist (arv->audio_region()->envelope());
5615 XMLNode& before (alist->get_state());
5617 arv->audio_region()->set_default_envelope ();
5620 begin_reversible_command (_("reset region gain"));
5623 _session->add_command (new MementoCommand<AutomationList>(*arv->audio_region()->envelope().get(), &before, &alist->get_state()));
5628 commit_reversible_command ();
5633 Editor::set_region_gain_visibility (RegionView* rv)
5635 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (rv);
5637 arv->update_envelope_visibility();
5642 Editor::set_gain_envelope_visibility ()
5648 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5649 AudioTimeAxisView* v = dynamic_cast<AudioTimeAxisView*>(*i);
5651 v->audio_view()->foreach_regionview (sigc::mem_fun (this, &Editor::set_region_gain_visibility));
5657 Editor::toggle_gain_envelope_active ()
5659 if (_ignore_region_action) {
5663 RegionSelection rs = get_regions_from_selection_and_entered ();
5665 if (!_session || rs.empty()) {
5669 bool in_command = false;
5671 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5672 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
5674 arv->region()->clear_changes ();
5675 arv->audio_region()->set_envelope_active (!arv->audio_region()->envelope_active());
5678 begin_reversible_command (_("region gain envelope active"));
5681 _session->add_command (new StatefulDiffCommand (arv->region()));
5686 commit_reversible_command ();
5691 Editor::toggle_region_lock ()
5693 if (_ignore_region_action) {
5697 RegionSelection rs = get_regions_from_selection_and_entered ();
5699 if (!_session || rs.empty()) {
5703 begin_reversible_command (_("toggle region lock"));
5705 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5706 (*i)->region()->clear_changes ();
5707 (*i)->region()->set_locked (!(*i)->region()->locked());
5708 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5711 commit_reversible_command ();
5715 Editor::toggle_region_video_lock ()
5717 if (_ignore_region_action) {
5721 RegionSelection rs = get_regions_from_selection_and_entered ();
5723 if (!_session || rs.empty()) {
5727 begin_reversible_command (_("Toggle Video Lock"));
5729 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5730 (*i)->region()->clear_changes ();
5731 (*i)->region()->set_video_locked (!(*i)->region()->video_locked());
5732 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5735 commit_reversible_command ();
5739 Editor::toggle_region_lock_style ()
5741 if (_ignore_region_action) {
5745 RegionSelection rs = get_regions_from_selection_and_entered ();
5747 if (!_session || rs.empty()) {
5751 Glib::RefPtr<ToggleAction> a = Glib::RefPtr<ToggleAction>::cast_dynamic (_region_actions->get_action("toggle-region-lock-style"));
5752 vector<Widget*> proxies = a->get_proxies();
5753 Gtk::CheckMenuItem* cmi = dynamic_cast<Gtk::CheckMenuItem*> (proxies.front());
5757 begin_reversible_command (_("toggle region lock style"));
5759 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5760 (*i)->region()->clear_changes ();
5761 PositionLockStyle const ns = ((*i)->region()->position_lock_style() == AudioTime && !cmi->get_inconsistent()) ? MusicTime : AudioTime;
5762 (*i)->region()->set_position_lock_style (ns);
5763 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5766 commit_reversible_command ();
5770 Editor::toggle_opaque_region ()
5772 if (_ignore_region_action) {
5776 RegionSelection rs = get_regions_from_selection_and_entered ();
5778 if (!_session || rs.empty()) {
5782 begin_reversible_command (_("change region opacity"));
5784 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5785 (*i)->region()->clear_changes ();
5786 (*i)->region()->set_opaque (!(*i)->region()->opaque());
5787 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5790 commit_reversible_command ();
5794 Editor::toggle_record_enable ()
5796 bool new_state = false;
5798 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5799 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5802 if (!rtav->is_track())
5806 new_state = !rtav->track()->rec_enable_control()->get_value();
5810 rtav->track()->rec_enable_control()->set_value (new_state, Controllable::UseGroup);
5815 Editor::toggle_solo ()
5817 bool new_state = false;
5819 boost::shared_ptr<ControlList> cl (new ControlList);
5821 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5822 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5829 new_state = !rtav->route()->soloed ();
5833 cl->push_back (rtav->route()->solo_control());
5836 _session->set_controls (cl, new_state ? 1.0 : 0.0, Controllable::UseGroup);
5840 Editor::toggle_mute ()
5842 bool new_state = false;
5844 boost::shared_ptr<RouteList> rl (new RouteList);
5846 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5847 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5854 new_state = !rtav->route()->muted();
5858 rl->push_back (rtav->route());
5861 _session->set_controls (route_list_to_control_list (rl, &Stripable::mute_control), new_state, Controllable::UseGroup);
5865 Editor::toggle_solo_isolate ()
5871 Editor::fade_range ()
5873 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
5875 begin_reversible_command (_("fade range"));
5877 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
5878 (*i)->fade_range (selection->time);
5881 commit_reversible_command ();
5886 Editor::set_fade_length (bool in)
5888 RegionSelection rs = get_regions_from_selection_and_entered ();
5894 /* we need a region to measure the offset from the start */
5896 RegionView* rv = rs.front ();
5898 framepos_t pos = get_preferred_edit_position();
5902 if (pos > rv->region()->last_frame() || pos < rv->region()->first_frame()) {
5903 /* edit point is outside the relevant region */
5908 if (pos <= rv->region()->position()) {
5912 len = pos - rv->region()->position();
5913 cmd = _("set fade in length");
5915 if (pos >= rv->region()->last_frame()) {
5919 len = rv->region()->last_frame() - pos;
5920 cmd = _("set fade out length");
5923 bool in_command = false;
5925 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5926 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5932 boost::shared_ptr<AutomationList> alist;
5934 alist = tmp->audio_region()->fade_in();
5936 alist = tmp->audio_region()->fade_out();
5939 XMLNode &before = alist->get_state();
5942 tmp->audio_region()->set_fade_in_length (len);
5943 tmp->audio_region()->set_fade_in_active (true);
5945 tmp->audio_region()->set_fade_out_length (len);
5946 tmp->audio_region()->set_fade_out_active (true);
5950 begin_reversible_command (cmd);
5953 XMLNode &after = alist->get_state();
5954 _session->add_command(new MementoCommand<AutomationList>(*alist, &before, &after));
5958 commit_reversible_command ();
5963 Editor::set_fade_in_shape (FadeShape shape)
5965 RegionSelection rs = get_regions_from_selection_and_entered ();
5970 bool in_command = false;
5972 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5973 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5979 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_in();
5980 XMLNode &before = alist->get_state();
5982 tmp->audio_region()->set_fade_in_shape (shape);
5985 begin_reversible_command (_("set fade in shape"));
5988 XMLNode &after = alist->get_state();
5989 _session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
5993 commit_reversible_command ();
5998 Editor::set_fade_out_shape (FadeShape shape)
6000 RegionSelection rs = get_regions_from_selection_and_entered ();
6005 bool in_command = false;
6007 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
6008 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
6014 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_out();
6015 XMLNode &before = alist->get_state();
6017 tmp->audio_region()->set_fade_out_shape (shape);
6020 begin_reversible_command (_("set fade out shape"));
6023 XMLNode &after = alist->get_state();
6024 _session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
6028 commit_reversible_command ();
6033 Editor::set_fade_in_active (bool yn)
6035 RegionSelection rs = get_regions_from_selection_and_entered ();
6040 bool in_command = false;
6042 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
6043 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
6050 boost::shared_ptr<AudioRegion> ar (tmp->audio_region());
6052 ar->clear_changes ();
6053 ar->set_fade_in_active (yn);
6056 begin_reversible_command (_("set fade in active"));
6059 _session->add_command (new StatefulDiffCommand (ar));
6063 commit_reversible_command ();
6068 Editor::set_fade_out_active (bool yn)
6070 RegionSelection rs = get_regions_from_selection_and_entered ();
6075 bool in_command = false;
6077 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
6078 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
6084 boost::shared_ptr<AudioRegion> ar (tmp->audio_region());
6086 ar->clear_changes ();
6087 ar->set_fade_out_active (yn);
6090 begin_reversible_command (_("set fade out active"));
6093 _session->add_command(new StatefulDiffCommand (ar));
6097 commit_reversible_command ();
6102 Editor::toggle_region_fades (int dir)
6104 if (_ignore_region_action) {
6108 boost::shared_ptr<AudioRegion> ar;
6111 RegionSelection rs = get_regions_from_selection_and_entered ();
6117 RegionSelection::iterator i;
6118 for (i = rs.begin(); i != rs.end(); ++i) {
6119 if ((ar = boost::dynamic_pointer_cast<AudioRegion>((*i)->region())) != 0) {
6121 yn = ar->fade_out_active ();
6123 yn = ar->fade_in_active ();
6129 if (i == rs.end()) {
6133 /* XXX should this undo-able? */
6134 bool in_command = false;
6136 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
6137 if ((ar = boost::dynamic_pointer_cast<AudioRegion>((*i)->region())) == 0) {
6140 ar->clear_changes ();
6142 if (dir == 1 || dir == 0) {
6143 ar->set_fade_in_active (!yn);
6146 if (dir == -1 || dir == 0) {
6147 ar->set_fade_out_active (!yn);
6150 begin_reversible_command (_("toggle fade active"));
6153 _session->add_command(new StatefulDiffCommand (ar));
6157 commit_reversible_command ();
6162 /** Update region fade visibility after its configuration has been changed */
6164 Editor::update_region_fade_visibility ()
6166 bool _fade_visibility = _session->config.get_show_region_fades ();
6168 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
6169 AudioTimeAxisView* v = dynamic_cast<AudioTimeAxisView*>(*i);
6171 if (_fade_visibility) {
6172 v->audio_view()->show_all_fades ();
6174 v->audio_view()->hide_all_fades ();
6181 Editor::set_edit_point ()
6184 MusicFrame where (0, 0);
6186 if (!mouse_frame (where.frame, ignored)) {
6192 if (selection->markers.empty()) {
6194 mouse_add_new_marker (where.frame);
6199 Location* loc = find_location_from_marker (selection->markers.front(), ignored);
6202 loc->move_to (where.frame, where.division);
6208 Editor::set_playhead_cursor ()
6210 if (entered_marker) {
6211 _session->request_locate (entered_marker->position(), _session->transport_rolling());
6213 MusicFrame where (0, 0);
6216 if (!mouse_frame (where.frame, ignored)) {
6223 _session->request_locate (where.frame, _session->transport_rolling());
6227 //not sure what this was for; remove it for now.
6228 // if (UIConfiguration::instance().get_follow_edits() && (!_session || !_session->config.get_external_sync())) {
6229 // cancel_time_selection();
6235 Editor::split_region ()
6237 if (_drags->active ()) {
6241 //if a range is selected, separate it
6242 if ( !selection->time.empty()) {
6243 separate_regions_between (selection->time);
6247 //if no range was selected, try to find some regions to split
6248 if (current_mouse_mode() == MouseObject) { //don't try this for Internal Edit, Stretch, Draw, etc.
6250 RegionSelection rs = get_regions_from_selection_and_edit_point ();
6251 const framepos_t pos = get_preferred_edit_position();
6252 const int32_t division = get_grid_music_divisions (0);
6253 MusicFrame where (pos, division);
6259 split_regions_at (where, rs);
6265 Editor::select_next_route()
6267 if (selection->tracks.empty()) {
6268 selection->set (track_views.front());
6272 TimeAxisView* current = selection->tracks.front();
6276 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
6278 if (*i == current) {
6280 if (i != track_views.end()) {
6283 current = (*(track_views.begin()));
6284 //selection->set (*(track_views.begin()));
6290 rui = dynamic_cast<RouteUI *>(current);
6292 } while (current->hidden() || (rui == NULL) || !rui->route()->active());
6294 selection->set (current);
6296 ensure_time_axis_view_is_visible (*current, false);
6300 Editor::select_prev_route()
6302 if (selection->tracks.empty()) {
6303 selection->set (track_views.front());
6307 TimeAxisView* current = selection->tracks.front();
6311 for (TrackViewList::reverse_iterator i = track_views.rbegin(); i != track_views.rend(); ++i) {
6313 if (*i == current) {
6315 if (i != track_views.rend()) {
6318 current = *(track_views.rbegin());
6323 rui = dynamic_cast<RouteUI *>(current);
6325 } while (current->hidden() || (rui == NULL) || !rui->route()->active());
6327 selection->set (current);
6329 ensure_time_axis_view_is_visible (*current, false);
6333 Editor::set_loop_from_selection (bool play)
6335 if (_session == 0) {
6339 framepos_t start, end;
6340 if (!get_selection_extents ( start, end))
6343 set_loop_range (start, end, _("set loop range from selection"));
6346 _session->request_play_loop (true, true);
6351 Editor::set_loop_from_region (bool play)
6353 framepos_t start, end;
6354 if (!get_selection_extents ( start, end))
6357 set_loop_range (start, end, _("set loop range from region"));
6360 _session->request_locate (start, true);
6361 _session->request_play_loop (true);
6366 Editor::set_punch_from_selection ()
6368 if (_session == 0) {
6372 framepos_t start, end;
6373 if (!get_selection_extents ( start, end))
6376 set_punch_range (start, end, _("set punch range from selection"));
6380 Editor::set_auto_punch_range ()
6382 // auto punch in/out button from a single button
6383 // If Punch In is unset, set punch range from playhead to end, enable punch in
6384 // If Punch In is set, the next punch sets Punch Out, unless the playhead has been
6385 // rewound beyond the Punch In marker, in which case that marker will be moved back
6386 // to the current playhead position.
6387 // If punch out is set, it clears the punch range and Punch In/Out buttons
6389 if (_session == 0) {
6393 Location* tpl = transport_punch_location();
6394 framepos_t now = playhead_cursor->current_frame();
6395 framepos_t begin = now;
6396 framepos_t end = _session->current_end_frame();
6398 if (!_session->config.get_punch_in()) {
6399 // First Press - set punch in and create range from here to eternity
6400 set_punch_range (begin, end, _("Auto Punch In"));
6401 _session->config.set_punch_in(true);
6402 } else if (tpl && !_session->config.get_punch_out()) {
6403 // Second press - update end range marker and set punch_out
6404 if (now < tpl->start()) {
6405 // playhead has been rewound - move start back and pretend nothing happened
6407 set_punch_range (begin, end, _("Auto Punch In/Out"));
6409 // normal case for 2nd press - set the punch out
6410 end = playhead_cursor->current_frame ();
6411 set_punch_range (tpl->start(), now, _("Auto Punch In/Out"));
6412 _session->config.set_punch_out(true);
6415 if (_session->config.get_punch_out()) {
6416 _session->config.set_punch_out(false);
6419 if (_session->config.get_punch_in()) {
6420 _session->config.set_punch_in(false);
6425 // third press - unset punch in/out and remove range
6426 _session->locations()->remove(tpl);
6433 Editor::set_session_extents_from_selection ()
6435 if (_session == 0) {
6439 framepos_t start, end;
6440 if (!get_selection_extents ( start, end))
6444 if ((loc = _session->locations()->session_range_location()) == 0) {
6445 _session->set_session_extents (start, end); // this will create a new session range; no need for UNDO
6447 XMLNode &before = loc->get_state();
6449 _session->set_session_extents (start, end);
6451 XMLNode &after = loc->get_state();
6453 begin_reversible_command (_("set session start/end from selection"));
6455 _session->add_command (new MementoCommand<Location>(*loc, &before, &after));
6457 commit_reversible_command ();
6460 _session->set_end_is_free (false);
6464 Editor::set_punch_start_from_edit_point ()
6468 MusicFrame start (0, 0);
6469 framepos_t end = max_framepos;
6471 //use the existing punch end, if any
6472 Location* tpl = transport_punch_location();
6477 if ((_edit_point == EditAtPlayhead) && _session->transport_rolling()) {
6478 start.frame = _session->audible_frame();
6480 start.frame = get_preferred_edit_position();
6483 //snap the selection start/end
6486 //if there's not already a sensible selection endpoint, go "forever"
6487 if (start.frame > end ) {
6491 set_punch_range (start.frame, end, _("set punch start from EP"));
6497 Editor::set_punch_end_from_edit_point ()
6501 framepos_t start = 0;
6502 MusicFrame end (max_framepos, 0);
6504 //use the existing punch start, if any
6505 Location* tpl = transport_punch_location();
6507 start = tpl->start();
6510 if ((_edit_point == EditAtPlayhead) && _session->transport_rolling()) {
6511 end.frame = _session->audible_frame();
6513 end.frame = get_preferred_edit_position();
6516 //snap the selection start/end
6519 set_punch_range (start, end.frame, _("set punch end from EP"));
6525 Editor::set_loop_start_from_edit_point ()
6529 MusicFrame start (0, 0);
6530 framepos_t end = max_framepos;
6532 //use the existing loop end, if any
6533 Location* tpl = transport_loop_location();
6538 if ((_edit_point == EditAtPlayhead) && _session->transport_rolling()) {
6539 start.frame = _session->audible_frame();
6541 start.frame = get_preferred_edit_position();
6544 //snap the selection start/end
6547 //if there's not already a sensible selection endpoint, go "forever"
6548 if (start.frame > end ) {
6552 set_loop_range (start.frame, end, _("set loop start from EP"));
6558 Editor::set_loop_end_from_edit_point ()
6562 framepos_t start = 0;
6563 MusicFrame end (max_framepos, 0);
6565 //use the existing loop start, if any
6566 Location* tpl = transport_loop_location();
6568 start = tpl->start();
6571 if ((_edit_point == EditAtPlayhead) && _session->transport_rolling()) {
6572 end.frame = _session->audible_frame();
6574 end.frame = get_preferred_edit_position();
6577 //snap the selection start/end
6580 set_loop_range (start, end.frame, _("set loop end from EP"));
6585 Editor::set_punch_from_region ()
6587 framepos_t start, end;
6588 if (!get_selection_extents ( start, end))
6591 set_punch_range (start, end, _("set punch range from region"));
6595 Editor::pitch_shift_region ()
6597 RegionSelection rs = get_regions_from_selection_and_entered ();
6599 RegionSelection audio_rs;
6600 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
6601 if (dynamic_cast<AudioRegionView*> (*i)) {
6602 audio_rs.push_back (*i);
6606 if (audio_rs.empty()) {
6610 pitch_shift (audio_rs, 1.2);
6614 Editor::set_tempo_from_region ()
6616 RegionSelection rs = get_regions_from_selection_and_entered ();
6618 if (!_session || rs.empty()) {
6622 RegionView* rv = rs.front();
6624 define_one_bar (rv->region()->position(), rv->region()->last_frame() + 1);
6628 Editor::use_range_as_bar ()
6630 framepos_t start, end;
6631 if (get_edit_op_range (start, end)) {
6632 define_one_bar (start, end);
6637 Editor::define_one_bar (framepos_t start, framepos_t end)
6639 framepos_t length = end - start;
6641 const Meter& m (_session->tempo_map().meter_at_frame (start));
6643 /* length = 1 bar */
6645 /* We're going to deliver a constant tempo here,
6646 so we can use frames per beat to determine length.
6647 now we want frames per beat.
6648 we have frames per bar, and beats per bar, so ...
6651 /* XXXX METER MATH */
6653 double frames_per_beat = length / m.divisions_per_bar();
6655 /* beats per minute = */
6657 double beats_per_minute = (_session->frame_rate() * 60.0) / frames_per_beat;
6659 /* now decide whether to:
6661 (a) set global tempo
6662 (b) add a new tempo marker
6666 const TempoSection& t (_session->tempo_map().tempo_section_at_frame (start));
6668 bool do_global = false;
6670 if ((_session->tempo_map().n_tempos() == 1) && (_session->tempo_map().n_meters() == 1)) {
6672 /* only 1 tempo & 1 meter: ask if the user wants to set the tempo
6673 at the start, or create a new marker
6676 vector<string> options;
6677 options.push_back (_("Cancel"));
6678 options.push_back (_("Add new marker"));
6679 options.push_back (_("Set global tempo"));
6682 _("Define one bar"),
6683 _("Do you want to set the global tempo or add a new tempo marker?"),
6687 c.set_default_response (2);
6703 /* more than 1 tempo and/or meter section already, go ahead do the "usual":
6704 if the marker is at the region starter, change it, otherwise add
6709 begin_reversible_command (_("set tempo from region"));
6710 XMLNode& before (_session->tempo_map().get_state());
6713 _session->tempo_map().change_initial_tempo (beats_per_minute, t.note_type());
6714 } else if (t.frame() == start) {
6715 _session->tempo_map().change_existing_tempo_at (start, beats_per_minute, t.note_type());
6717 const Tempo tempo (beats_per_minute, t.note_type());
6718 _session->tempo_map().add_tempo (tempo, 0.0, start, TempoSection::Constant, AudioTime);
6721 XMLNode& after (_session->tempo_map().get_state());
6723 _session->add_command (new MementoCommand<TempoMap>(_session->tempo_map(), &before, &after));
6724 commit_reversible_command ();
6728 Editor::split_region_at_transients ()
6730 AnalysisFeatureList positions;
6732 RegionSelection rs = get_regions_from_selection_and_entered ();
6734 if (!_session || rs.empty()) {
6738 begin_reversible_command (_("split regions"));
6740 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ) {
6742 RegionSelection::iterator tmp;
6747 boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion> ((*i)->region());
6750 ar->transients (positions);
6751 split_region_at_points ((*i)->region(), positions, true);
6758 commit_reversible_command ();
6763 Editor::split_region_at_points (boost::shared_ptr<Region> r, AnalysisFeatureList& positions, bool can_ferret, bool select_new)
6765 bool use_rhythmic_rodent = false;
6767 boost::shared_ptr<Playlist> pl = r->playlist();
6769 list<boost::shared_ptr<Region> > new_regions;
6775 if (positions.empty()) {
6779 if (positions.size() > 20 && can_ferret) {
6780 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);
6781 MessageDialog msg (msgstr,
6784 Gtk::BUTTONS_OK_CANCEL);
6787 msg.add_button (_("Call for the Ferret!"), RESPONSE_APPLY);
6788 msg.set_secondary_text (_("Press OK to continue with this split operation\nor ask the Ferret dialog to tune the analysis"));
6790 msg.set_secondary_text (_("Press OK to continue with this split operation"));
6793 msg.set_title (_("Excessive split?"));
6796 int response = msg.run();
6802 case RESPONSE_APPLY:
6803 use_rhythmic_rodent = true;
6810 if (use_rhythmic_rodent) {
6811 show_rhythm_ferret ();
6815 AnalysisFeatureList::const_iterator x;
6817 pl->clear_changes ();
6818 pl->clear_owned_changes ();
6820 x = positions.begin();
6822 if (x == positions.end()) {
6827 pl->remove_region (r);
6831 framepos_t rstart = r->first_frame ();
6832 framepos_t rend = r->last_frame ();
6834 while (x != positions.end()) {
6836 /* deal with positons that are out of scope of present region bounds */
6837 if (*x <= rstart || *x > rend) {
6842 /* file start = original start + how far we from the initial position ? */
6844 framepos_t file_start = r->start() + pos;
6846 /* length = next position - current position */
6848 framepos_t len = (*x) - pos - rstart;
6850 /* XXX we do we really want to allow even single-sample regions?
6851 * shouldn't we have some kind of lower limit on region size?
6860 if (RegionFactory::region_name (new_name, r->name())) {
6864 /* do NOT announce new regions 1 by one, just wait till they are all done */
6868 plist.add (ARDOUR::Properties::start, file_start);
6869 plist.add (ARDOUR::Properties::length, len);
6870 plist.add (ARDOUR::Properties::name, new_name);
6871 plist.add (ARDOUR::Properties::layer, 0);
6872 // TODO set transients_offset
6874 boost::shared_ptr<Region> nr = RegionFactory::create (r->sources(), plist, false);
6875 /* because we set annouce to false, manually add the new region to the
6878 RegionFactory::map_add (nr);
6880 pl->add_region (nr, rstart + pos);
6883 new_regions.push_front(nr);
6892 RegionFactory::region_name (new_name, r->name());
6894 /* Add the final region */
6897 plist.add (ARDOUR::Properties::start, r->start() + pos);
6898 plist.add (ARDOUR::Properties::length, r->last_frame() - (r->position() + pos) + 1);
6899 plist.add (ARDOUR::Properties::name, new_name);
6900 plist.add (ARDOUR::Properties::layer, 0);
6902 boost::shared_ptr<Region> nr = RegionFactory::create (r->sources(), plist, false);
6903 /* because we set annouce to false, manually add the new region to the
6906 RegionFactory::map_add (nr);
6907 pl->add_region (nr, r->position() + pos);
6910 new_regions.push_front(nr);
6915 /* We might have removed regions, which alters other regions' layering_index,
6916 so we need to do a recursive diff here.
6918 vector<Command*> cmds;
6920 _session->add_commands (cmds);
6922 _session->add_command (new StatefulDiffCommand (pl));
6926 for (list<boost::shared_ptr<Region> >::iterator i = new_regions.begin(); i != new_regions.end(); ++i){
6927 set_selected_regionview_from_region_list ((*i), Selection::Add);
6933 Editor::place_transient()
6939 RegionSelection rs = get_regions_from_selection_and_edit_point ();
6945 framepos_t where = get_preferred_edit_position();
6947 begin_reversible_command (_("place transient"));
6949 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6950 (*r)->region()->add_transient(where);
6953 commit_reversible_command ();
6957 Editor::remove_transient(ArdourCanvas::Item* item)
6963 ArdourCanvas::Line* _line = reinterpret_cast<ArdourCanvas::Line*> (item);
6966 AudioRegionView* _arv = reinterpret_cast<AudioRegionView*> (item->get_data ("regionview"));
6967 _arv->remove_transient (*(float*) _line->get_data ("position"));
6971 Editor::snap_regions_to_grid ()
6973 list <boost::shared_ptr<Playlist > > used_playlists;
6975 RegionSelection rs = get_regions_from_selection_and_entered ();
6977 if (!_session || rs.empty()) {
6981 begin_reversible_command (_("snap regions to grid"));
6983 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6985 boost::shared_ptr<Playlist> pl = (*r)->region()->playlist();
6987 if (!pl->frozen()) {
6988 /* we haven't seen this playlist before */
6990 /* remember used playlists so we can thaw them later */
6991 used_playlists.push_back(pl);
6994 (*r)->region()->clear_changes ();
6996 MusicFrame start ((*r)->region()->first_frame (), 0);
6998 (*r)->region()->set_position (start.frame, start.division);
6999 _session->add_command(new StatefulDiffCommand ((*r)->region()));
7002 while (used_playlists.size() > 0) {
7003 list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
7005 used_playlists.pop_front();
7008 commit_reversible_command ();
7012 Editor::close_region_gaps ()
7014 list <boost::shared_ptr<Playlist > > used_playlists;
7016 RegionSelection rs = get_regions_from_selection_and_entered ();
7018 if (!_session || rs.empty()) {
7022 Dialog dialog (_("Close Region Gaps"));
7025 table.set_spacings (12);
7026 table.set_border_width (12);
7027 Label* l = manage (left_aligned_label (_("Crossfade length")));
7028 table.attach (*l, 0, 1, 0, 1);
7030 SpinButton spin_crossfade (1, 0);
7031 spin_crossfade.set_range (0, 15);
7032 spin_crossfade.set_increments (1, 1);
7033 spin_crossfade.set_value (5);
7034 table.attach (spin_crossfade, 1, 2, 0, 1);
7036 table.attach (*manage (new Label (_("ms"))), 2, 3, 0, 1);
7038 l = manage (left_aligned_label (_("Pull-back length")));
7039 table.attach (*l, 0, 1, 1, 2);
7041 SpinButton spin_pullback (1, 0);
7042 spin_pullback.set_range (0, 100);
7043 spin_pullback.set_increments (1, 1);
7044 spin_pullback.set_value(30);
7045 table.attach (spin_pullback, 1, 2, 1, 2);
7047 table.attach (*manage (new Label (_("ms"))), 2, 3, 1, 2);
7049 dialog.get_vbox()->pack_start (table);
7050 dialog.add_button (Stock::CANCEL, RESPONSE_CANCEL);
7051 dialog.add_button (_("Ok"), RESPONSE_ACCEPT);
7054 if (dialog.run () == RESPONSE_CANCEL) {
7058 framepos_t crossfade_len = spin_crossfade.get_value();
7059 framepos_t pull_back_frames = spin_pullback.get_value();
7061 crossfade_len = lrintf (crossfade_len * _session->frame_rate()/1000);
7062 pull_back_frames = lrintf (pull_back_frames * _session->frame_rate()/1000);
7064 /* Iterate over the region list and make adjacent regions overlap by crossfade_len_ms */
7066 begin_reversible_command (_("close region gaps"));
7069 boost::shared_ptr<Region> last_region;
7071 rs.sort_by_position_and_track();
7073 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
7075 boost::shared_ptr<Playlist> pl = (*r)->region()->playlist();
7077 if (!pl->frozen()) {
7078 /* we haven't seen this playlist before */
7080 /* remember used playlists so we can thaw them later */
7081 used_playlists.push_back(pl);
7085 framepos_t position = (*r)->region()->position();
7087 if (idx == 0 || position < last_region->position()){
7088 last_region = (*r)->region();
7093 (*r)->region()->clear_changes ();
7094 (*r)->region()->trim_front( (position - pull_back_frames));
7096 last_region->clear_changes ();
7097 last_region->trim_end( (position - pull_back_frames + crossfade_len));
7099 _session->add_command (new StatefulDiffCommand ((*r)->region()));
7100 _session->add_command (new StatefulDiffCommand (last_region));
7102 last_region = (*r)->region();
7106 while (used_playlists.size() > 0) {
7107 list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
7109 used_playlists.pop_front();
7112 commit_reversible_command ();
7116 Editor::tab_to_transient (bool forward)
7118 AnalysisFeatureList positions;
7120 RegionSelection rs = get_regions_from_selection_and_entered ();
7126 framepos_t pos = _session->audible_frame ();
7128 if (!selection->tracks.empty()) {
7130 /* don't waste time searching for transients in duplicate playlists.
7133 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
7135 for (TrackViewList::iterator t = ts.begin(); t != ts.end(); ++t) {
7137 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*t);
7140 boost::shared_ptr<Track> tr = rtv->track();
7142 boost::shared_ptr<Playlist> pl = tr->playlist ();
7144 framepos_t result = pl->find_next_transient (pos, forward ? 1 : -1);
7147 positions.push_back (result);
7160 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
7161 (*r)->region()->get_transients (positions);
7165 TransientDetector::cleanup_transients (positions, _session->frame_rate(), 3.0);
7168 AnalysisFeatureList::iterator x;
7170 for (x = positions.begin(); x != positions.end(); ++x) {
7176 if (x != positions.end ()) {
7177 _session->request_locate (*x);
7181 AnalysisFeatureList::reverse_iterator x;
7183 for (x = positions.rbegin(); x != positions.rend(); ++x) {
7189 if (x != positions.rend ()) {
7190 _session->request_locate (*x);
7196 Editor::playhead_forward_to_grid ()
7202 MusicFrame pos (playhead_cursor->current_frame (), 0);
7204 if (pos.frame < max_framepos - 1) {
7206 snap_to_internal (pos, RoundUpAlways, false);
7207 _session->request_locate (pos.frame);
7213 Editor::playhead_backward_to_grid ()
7219 MusicFrame pos (playhead_cursor->current_frame (), 0);
7221 if (pos.frame > 2) {
7223 snap_to_internal (pos, RoundDownAlways, false);
7224 _session->request_locate (pos.frame);
7229 Editor::set_track_height (Height h)
7231 TrackSelection& ts (selection->tracks);
7233 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
7234 (*x)->set_height_enum (h);
7239 Editor::toggle_tracks_active ()
7241 TrackSelection& ts (selection->tracks);
7243 bool target = false;
7249 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
7250 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*x);
7254 target = !rtv->_route->active();
7257 rtv->_route->set_active (target, this);
7263 Editor::remove_tracks ()
7265 /* this will delete GUI objects that may be the subject of an event
7266 handler in which this method is called. Defer actual deletion to the
7267 next idle callback, when all event handling is finished.
7269 Glib::signal_idle().connect (sigc::mem_fun (*this, &Editor::idle_remove_tracks));
7273 Editor::idle_remove_tracks ()
7275 Session::StateProtector sp (_session);
7277 return false; /* do not call again */
7281 Editor::_remove_tracks ()
7283 TrackSelection& ts (selection->tracks);
7289 vector<string> choices;
7293 const char* trackstr;
7295 vector<boost::shared_ptr<Route> > routes;
7296 bool special_bus = false;
7298 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
7299 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*x);
7303 if (rtv->is_track()) {
7308 routes.push_back (rtv->_route);
7310 if (rtv->route()->is_master() || rtv->route()->is_monitor()) {
7315 if (special_bus && !Config->get_allow_special_bus_removal()) {
7316 MessageDialog msg (_("That would be bad news ...."),
7320 msg.set_secondary_text (string_compose (_(
7321 "Removing the master or monitor bus is such a bad idea\n\
7322 that %1 is not going to allow it.\n\
7324 If you really want to do this sort of thing\n\
7325 edit your ardour.rc file to set the\n\
7326 \"allow-special-bus-removal\" option to be \"yes\""), PROGRAM_NAME));
7333 if (ntracks + nbusses == 0) {
7337 trackstr = P_("track", "tracks", ntracks);
7338 busstr = P_("bus", "busses", nbusses);
7342 prompt = string_compose (_("Do you really want to remove %1 %2 and %3 %4?\n"
7343 "(You may also lose the playlists associated with the %2)\n\n"
7344 "This action cannot be undone, and the session file will be overwritten!"),
7345 ntracks, trackstr, nbusses, busstr);
7347 prompt = string_compose (_("Do you really want to remove %1 %2?\n"
7348 "(You may also lose the playlists associated with the %2)\n\n"
7349 "This action cannot be undone, and the session file will be overwritten!"),
7352 } else if (nbusses) {
7353 prompt = string_compose (_("Do you really want to remove %1 %2?\n\n"
7354 "This action cannot be undone, and the session file will be overwritten"),
7358 choices.push_back (_("No, do nothing."));
7359 if (ntracks + nbusses > 1) {
7360 choices.push_back (_("Yes, remove them."));
7362 choices.push_back (_("Yes, remove it."));
7367 title = string_compose (_("Remove %1"), trackstr);
7369 title = string_compose (_("Remove %1"), busstr);
7372 Choice prompter (title, prompt, choices);
7374 if (prompter.run () != 1) {
7378 if (current_mixer_strip && routes.size () > 1 && std::find (routes.begin(), routes.end(), current_mixer_strip->route()) != routes.end ()) {
7379 /* Route deletion calls Editor::timeaxisview_deleted() iteratively (for each deleted
7380 * route). If the deleted route is currently displayed in the Editor-Mixer (highly
7381 * likely because deletion requires selection) this will call
7382 * Editor::set_selected_mixer_strip () which is expensive ( MixerStrip::set_route() ).
7383 * It's likewise likely that the route that has just been displayed in the
7384 * Editor-Mixer will be next in line for deletion.
7386 * So simply switch to the master-bus (if present)
7388 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
7389 if ((*i)->stripable ()->is_master ()) {
7390 set_selected_mixer_strip (*(*i));
7397 PresentationInfo::ChangeSuspender cs;
7398 DisplaySuspender ds;
7400 boost::shared_ptr<RouteList> rl (new RouteList);
7401 for (vector<boost::shared_ptr<Route> >::iterator x = routes.begin(); x != routes.end(); ++x) {
7404 _session->remove_routes (rl);
7406 /* TrackSelection and RouteList leave scope,
7407 * destructors are called,
7408 * diskstream drops references, save_state is called (again for every track)
7413 Editor::do_insert_time ()
7415 if (selection->tracks.empty()) {
7419 InsertRemoveTimeDialog d (*this);
7420 int response = d.run ();
7422 if (response != RESPONSE_OK) {
7426 if (d.distance() == 0) {
7433 d.intersected_region_action (),
7437 d.move_glued_markers(),
7438 d.move_locked_markers(),
7444 Editor::insert_time (
7445 framepos_t pos, framecnt_t frames, InsertTimeOption opt,
7446 bool all_playlists, bool ignore_music_glue, bool markers_too, bool glued_markers_too, bool locked_markers_too, bool tempo_too
7450 if (Config->get_edit_mode() == Lock) {
7453 bool in_command = false;
7455 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
7457 for (TrackViewList::iterator x = ts.begin(); x != ts.end(); ++x) {
7461 /* don't operate on any playlist more than once, which could
7462 * happen if "all playlists" is enabled, but there is more
7463 * than 1 track using playlists "from" a given track.
7466 set<boost::shared_ptr<Playlist> > pl;
7468 if (all_playlists) {
7469 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*x);
7470 if (rtav && rtav->track ()) {
7471 vector<boost::shared_ptr<Playlist> > all = _session->playlists->playlists_for_track (rtav->track ());
7472 for (vector<boost::shared_ptr<Playlist> >::iterator p = all.begin(); p != all.end(); ++p) {
7477 if ((*x)->playlist ()) {
7478 pl.insert ((*x)->playlist ());
7482 for (set<boost::shared_ptr<Playlist> >::iterator i = pl.begin(); i != pl.end(); ++i) {
7484 (*i)->clear_changes ();
7485 (*i)->clear_owned_changes ();
7487 if (opt == SplitIntersected) {
7488 /* non musical split */
7489 (*i)->split (MusicFrame (pos, 0));
7492 (*i)->shift (pos, frames, (opt == MoveIntersected), ignore_music_glue);
7495 begin_reversible_command (_("insert time"));
7498 vector<Command*> cmds;
7500 _session->add_commands (cmds);
7502 _session->add_command (new StatefulDiffCommand (*i));
7506 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*x);
7509 begin_reversible_command (_("insert time"));
7512 rtav->route ()->shift (pos, frames);
7519 const int32_t divisions = get_grid_music_divisions (0);
7520 XMLNode& before (_session->locations()->get_state());
7521 Locations::LocationList copy (_session->locations()->list());
7523 for (Locations::LocationList::iterator i = copy.begin(); i != copy.end(); ++i) {
7525 Locations::LocationList::const_iterator tmp;
7527 if ((*i)->position_lock_style() == AudioTime || glued_markers_too) {
7528 bool const was_locked = (*i)->locked ();
7529 if (locked_markers_too) {
7533 if ((*i)->start() >= pos) {
7534 // move end first, in case we're moving by more than the length of the range
7535 if (!(*i)->is_mark()) {
7536 (*i)->set_end ((*i)->end() + frames, false, true, divisions);
7538 (*i)->set_start ((*i)->start() + frames, false, true, divisions);
7550 begin_reversible_command (_("insert time"));
7553 XMLNode& after (_session->locations()->get_state());
7554 _session->add_command (new MementoCommand<Locations>(*_session->locations(), &before, &after));
7560 begin_reversible_command (_("insert time"));
7563 XMLNode& before (_session->tempo_map().get_state());
7564 _session->tempo_map().insert_time (pos, frames);
7565 XMLNode& after (_session->tempo_map().get_state());
7566 _session->add_command (new MementoCommand<TempoMap>(_session->tempo_map(), &before, &after));
7570 commit_reversible_command ();
7575 Editor::do_remove_time ()
7577 if (selection->tracks.empty()) {
7581 InsertRemoveTimeDialog d (*this, true);
7583 int response = d.run ();
7585 if (response != RESPONSE_OK) {
7589 framecnt_t distance = d.distance();
7591 if (distance == 0) {
7601 d.move_glued_markers(),
7602 d.move_locked_markers(),
7608 Editor::remove_time (framepos_t pos, framecnt_t frames, InsertTimeOption opt,
7609 bool ignore_music_glue, bool markers_too, bool glued_markers_too, bool locked_markers_too, bool tempo_too)
7611 if (Config->get_edit_mode() == Lock) {
7612 error << (_("Cannot insert or delete time when in Lock edit.")) << endmsg;
7615 bool in_command = false;
7617 for (TrackSelection::iterator x = selection->tracks.begin(); x != selection->tracks.end(); ++x) {
7619 boost::shared_ptr<Playlist> pl = (*x)->playlist();
7623 XMLNode &before = pl->get_state();
7625 std::list<AudioRange> rl;
7626 AudioRange ar(pos, pos+frames, 0);
7629 pl->shift (pos, -frames, true, ignore_music_glue);
7632 begin_reversible_command (_("remove time"));
7635 XMLNode &after = pl->get_state();
7637 _session->add_command (new MementoCommand<Playlist> (*pl, &before, &after));
7641 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*x);
7644 begin_reversible_command (_("remove time"));
7647 rtav->route ()->shift (pos, -frames);
7651 const int32_t divisions = get_grid_music_divisions (0);
7652 std::list<Location*> loc_kill_list;
7657 XMLNode& before (_session->locations()->get_state());
7658 Locations::LocationList copy (_session->locations()->list());
7660 for (Locations::LocationList::iterator i = copy.begin(); i != copy.end(); ++i) {
7661 if ((*i)->position_lock_style() == AudioTime || glued_markers_too) {
7663 bool const was_locked = (*i)->locked ();
7664 if (locked_markers_too) {
7668 if (!(*i)->is_mark()) { // it's a range; have to handle both start and end
7669 if ((*i)->end() >= pos
7670 && (*i)->end() < pos+frames
7671 && (*i)->start() >= pos
7672 && (*i)->end() < pos+frames) { // range is completely enclosed; kill it
7674 loc_kill_list.push_back(*i);
7675 } else { // only start or end is included, try to do the right thing
7676 // move start before moving end, to avoid trying to move the end to before the start
7677 // if we're removing more time than the length of the range
7678 if ((*i)->start() >= pos && (*i)->start() < pos+frames) {
7679 // start is within cut
7680 (*i)->set_start (pos, false, true,divisions); // bring the start marker to the beginning of the cut
7682 } else if ((*i)->start() >= pos+frames) {
7683 // start (and thus entire range) lies beyond end of cut
7684 (*i)->set_start ((*i)->start() - frames, false, true, divisions); // slip the start marker back
7687 if ((*i)->end() >= pos && (*i)->end() < pos+frames) {
7688 // end is inside cut
7689 (*i)->set_end (pos, false, true, divisions); // bring the end to the cut
7691 } else if ((*i)->end() >= pos+frames) {
7692 // end is beyond end of cut
7693 (*i)->set_end ((*i)->end() - frames, false, true, divisions); // slip the end marker back
7698 } else if ((*i)->start() >= pos && (*i)->start() < pos+frames ) {
7699 loc_kill_list.push_back(*i);
7701 } else if ((*i)->start() >= pos) {
7702 (*i)->set_start ((*i)->start() -frames, false, true, divisions);
7712 for (list<Location*>::iterator i = loc_kill_list.begin(); i != loc_kill_list.end(); ++i) {
7713 _session->locations()->remove( *i );
7718 begin_reversible_command (_("remove time"));
7721 XMLNode& after (_session->locations()->get_state());
7722 _session->add_command (new MementoCommand<Locations>(*_session->locations(), &before, &after));
7727 XMLNode& before (_session->tempo_map().get_state());
7729 if (_session->tempo_map().remove_time (pos, frames) ) {
7731 begin_reversible_command (_("remove time"));
7734 XMLNode& after (_session->tempo_map().get_state());
7735 _session->add_command (new MementoCommand<TempoMap>(_session->tempo_map(), &before, &after));
7740 commit_reversible_command ();
7745 Editor::fit_selection ()
7747 if (!selection->tracks.empty()) {
7748 fit_tracks (selection->tracks);
7752 /* no selected tracks - use tracks with selected regions */
7754 if (!selection->regions.empty()) {
7755 for (RegionSelection::iterator r = selection->regions.begin(); r != selection->regions.end(); ++r) {
7756 tvl.push_back (&(*r)->get_time_axis_view ());
7762 } else if (internal_editing()) {
7763 /* no selected tracks, or regions, but in internal edit mode, so follow the mouse and use
7766 if (entered_track) {
7767 tvl.push_back (entered_track);
7776 Editor::fit_tracks (TrackViewList & tracks)
7778 if (tracks.empty()) {
7782 uint32_t child_heights = 0;
7783 int visible_tracks = 0;
7785 for (TrackSelection::iterator t = tracks.begin(); t != tracks.end(); ++t) {
7787 if (!(*t)->marked_for_display()) {
7791 child_heights += (*t)->effective_height() - (*t)->current_height();
7795 /* compute the per-track height from:
7797 total canvas visible height -
7798 height that will be taken by visible children of selected
7799 tracks - height of the ruler/hscroll area
7801 uint32_t h = (uint32_t) floor ((trackviews_height() - child_heights) / visible_tracks);
7802 double first_y_pos = DBL_MAX;
7804 if (h < TimeAxisView::preset_height (HeightSmall)) {
7805 MessageDialog msg (_("There are too many tracks to fit in the current window"));
7806 /* too small to be displayed */
7810 undo_visual_stack.push_back (current_visual_state (true));
7811 PBD::Unwinder<bool> nsv (no_save_visual, true);
7813 /* build a list of all tracks, including children */
7816 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
7818 TimeAxisView::Children c = (*i)->get_child_list ();
7819 for (TimeAxisView::Children::iterator j = c.begin(); j != c.end(); ++j) {
7820 all.push_back (j->get());
7825 // find selection range.
7826 // if someone knows how to user TrackViewList::iterator for this
7828 int selected_top = -1;
7829 int selected_bottom = -1;
7831 for (TrackViewList::iterator t = all.begin(); t != all.end(); ++t, ++i) {
7832 if ((*t)->marked_for_display ()) {
7833 if (tracks.contains(*t)) {
7834 if (selected_top == -1) {
7837 selected_bottom = i;
7843 for (TrackViewList::iterator t = all.begin(); t != all.end(); ++t, ++i) {
7844 if ((*t)->marked_for_display ()) {
7845 if (tracks.contains(*t)) {
7846 (*t)->set_height (h);
7847 first_y_pos = std::min ((*t)->y_position (), first_y_pos);
7849 if (i > selected_top && i < selected_bottom) {
7850 hide_track_in_display (*t);
7857 set the controls_layout height now, because waiting for its size
7858 request signal handler will cause the vertical adjustment setting to fail
7861 controls_layout.property_height () = _full_canvas_height;
7862 vertical_adjustment.set_value (first_y_pos);
7864 redo_visual_stack.push_back (current_visual_state (true));
7866 visible_tracks_selector.set_text (_("Sel"));
7870 Editor::save_visual_state (uint32_t n)
7872 while (visual_states.size() <= n) {
7873 visual_states.push_back (0);
7876 if (visual_states[n] != 0) {
7877 delete visual_states[n];
7880 visual_states[n] = current_visual_state (true);
7885 Editor::goto_visual_state (uint32_t n)
7887 if (visual_states.size() <= n) {
7891 if (visual_states[n] == 0) {
7895 use_visual_state (*visual_states[n]);
7899 Editor::start_visual_state_op (uint32_t n)
7901 save_visual_state (n);
7903 PopUp* pup = new PopUp (WIN_POS_MOUSE, 1000, true);
7905 snprintf (buf, sizeof (buf), _("Saved view %u"), n+1);
7906 pup->set_text (buf);
7911 Editor::cancel_visual_state_op (uint32_t n)
7913 goto_visual_state (n);
7917 Editor::toggle_region_mute ()
7919 if (_ignore_region_action) {
7923 RegionSelection rs = get_regions_from_selection_and_entered ();
7929 if (rs.size() > 1) {
7930 begin_reversible_command (_("mute regions"));
7932 begin_reversible_command (_("mute region"));
7935 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
7937 (*i)->region()->playlist()->clear_changes ();
7938 (*i)->region()->set_muted (!(*i)->region()->muted ());
7939 _session->add_command (new StatefulDiffCommand ((*i)->region()));
7943 commit_reversible_command ();
7947 Editor::combine_regions ()
7949 /* foreach track with selected regions, take all selected regions
7950 and join them into a new region containing the subregions (as a
7954 typedef set<RouteTimeAxisView*> RTVS;
7957 if (selection->regions.empty()) {
7961 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
7962 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(&(*i)->get_time_axis_view());
7965 tracks.insert (rtv);
7969 begin_reversible_command (_("combine regions"));
7971 vector<RegionView*> new_selection;
7973 for (RTVS::iterator i = tracks.begin(); i != tracks.end(); ++i) {
7976 if ((rv = (*i)->combine_regions ()) != 0) {
7977 new_selection.push_back (rv);
7981 selection->clear_regions ();
7982 for (vector<RegionView*>::iterator i = new_selection.begin(); i != new_selection.end(); ++i) {
7983 selection->add (*i);
7986 commit_reversible_command ();
7990 Editor::uncombine_regions ()
7992 typedef set<RouteTimeAxisView*> RTVS;
7995 if (selection->regions.empty()) {
7999 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
8000 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(&(*i)->get_time_axis_view());
8003 tracks.insert (rtv);
8007 begin_reversible_command (_("uncombine regions"));
8009 for (RTVS::iterator i = tracks.begin(); i != tracks.end(); ++i) {
8010 (*i)->uncombine_regions ();
8013 commit_reversible_command ();
8017 Editor::toggle_midi_input_active (bool flip_others)
8020 boost::shared_ptr<RouteList> rl (new RouteList);
8022 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
8023 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
8029 boost::shared_ptr<MidiTrack> mt = rtav->midi_track();
8032 rl->push_back (rtav->route());
8033 onoff = !mt->input_active();
8037 _session->set_exclusive_input_active (rl, onoff, flip_others);
8040 static bool ok_fine (GdkEventAny*) { return true; }
8046 lock_dialog = new Gtk::Dialog (string_compose (_("%1: Locked"), PROGRAM_NAME), true);
8048 Gtk::Image* padlock = manage (new Gtk::Image (ARDOUR_UI_UTILS::get_icon ("padlock_closed")));
8049 lock_dialog->get_vbox()->pack_start (*padlock);
8050 lock_dialog->signal_delete_event ().connect (sigc::ptr_fun (ok_fine));
8052 ArdourButton* b = manage (new ArdourButton);
8053 b->set_name ("lock button");
8054 b->set_text (_("Click to unlock"));
8055 b->signal_clicked.connect (sigc::mem_fun (*this, &Editor::unlock));
8056 lock_dialog->get_vbox()->pack_start (*b);
8058 lock_dialog->get_vbox()->show_all ();
8059 lock_dialog->set_size_request (200, 200);
8062 delete _main_menu_disabler;
8063 _main_menu_disabler = new MainMenuDisabler;
8065 lock_dialog->present ();
8067 lock_dialog->get_window()->set_decorations (Gdk::WMDecoration (0));
8073 lock_dialog->hide ();
8075 delete _main_menu_disabler;
8076 _main_menu_disabler = 0;
8078 if (UIConfiguration::instance().get_lock_gui_after_seconds()) {
8079 start_lock_event_timing ();
8084 Editor::bring_in_callback (Gtk::Label* label, uint32_t n, uint32_t total, string name)
8086 Gtkmm2ext::UI::instance()->call_slot (invalidator (*this), boost::bind (&Editor::update_bring_in_message, this, label, n, total, name));
8090 Editor::update_bring_in_message (Gtk::Label* label, uint32_t n, uint32_t total, string name)
8092 Timers::TimerSuspender t;
8093 label->set_text (string_compose ("Copying %1, %2 of %3", name, n, total));
8094 Gtkmm2ext::UI::instance()->flush_pending (1);
8098 Editor::bring_all_sources_into_session ()
8105 ArdourDialog w (_("Moving embedded files into session folder"));
8106 w.get_vbox()->pack_start (msg);
8109 /* flush all pending GUI events because we're about to start copying
8113 Timers::TimerSuspender t;
8114 Gtkmm2ext::UI::instance()->flush_pending (3);
8118 _session->bring_all_sources_into_session (boost::bind (&Editor::bring_in_callback, this, &msg, _1, _2, _3));