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 (framepos_t where, RegionSelection& regions, const int32_t sub_num,
174 RegionSelection pre_selected_regions = selection->regions;
175 bool working_on_selection = !pre_selected_regions.empty();
177 list<boost::shared_ptr<Playlist> > used_playlists;
178 list<RouteTimeAxisView*> used_trackviews;
180 if (regions.empty()) {
184 begin_reversible_command (_("split"));
186 // if splitting a single region, and snap-to is using
187 // region boundaries, don't pay attention to them
189 if (regions.size() == 1) {
190 switch (_snap_type) {
191 case SnapToRegionStart:
192 case SnapToRegionSync:
193 case SnapToRegionEnd:
206 EditorFreeze(); /* Emit Signal */
209 for (RegionSelection::iterator a = regions.begin(); a != regions.end(); ) {
211 RegionSelection::iterator tmp;
213 /* XXX this test needs to be more complicated, to make sure we really
214 have something to split.
217 if (!(*a)->region()->covers (where)) {
225 boost::shared_ptr<Playlist> pl = (*a)->region()->playlist();
233 /* we haven't seen this playlist before */
235 /* remember used playlists so we can thaw them later */
236 used_playlists.push_back(pl);
238 TimeAxisView& tv = (*a)->get_time_axis_view();
239 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (&tv);
241 used_trackviews.push_back (rtv);
248 pl->clear_changes ();
249 pl->split_region ((*a)->region(), where, sub_num);
250 _session->add_command (new StatefulDiffCommand (pl));
256 latest_regionviews.clear ();
258 vector<sigc::connection> region_added_connections;
260 for (list<RouteTimeAxisView*>::iterator i = used_trackviews.begin(); i != used_trackviews.end(); ++i) {
261 region_added_connections.push_back ((*i)->view()->RegionViewAdded.connect (sigc::mem_fun(*this, &Editor::collect_new_region_view)));
264 while (used_playlists.size() > 0) {
265 list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
267 used_playlists.pop_front();
270 for (vector<sigc::connection>::iterator c = region_added_connections.begin(); c != region_added_connections.end(); ++c) {
275 EditorThaw(); /* Emit Signal */
278 if (working_on_selection) {
279 // IFF we were working on selected regions, try to reinstate the other region selections that existed before the freeze/thaw.
281 RegionSelectionAfterSplit rsas = Config->get_region_selection_after_split();
282 /* There are three classes of regions that we might want selected after
283 splitting selected regions:
284 - regions selected before the split operation, and unaffected by it
285 - newly-created regions before the split
286 - newly-created regions after the split
289 if (rsas & Existing) {
290 // region selections that existed before the split.
291 selection->add ( pre_selected_regions );
294 for (RegionSelection::iterator ri = latest_regionviews.begin(); ri != latest_regionviews.end(); ri++) {
295 if ((*ri)->region()->position() < where) {
296 // new regions created before the split
297 if (rsas & NewlyCreatedLeft) {
298 selection->add (*ri);
301 // new regions created after the split
302 if (rsas & NewlyCreatedRight) {
303 selection->add (*ri);
308 if( working_on_selection ) {
309 selection->add (latest_regionviews); //these are the new regions created after the split
313 commit_reversible_command ();
316 /** Move one extreme of the current range selection. If more than one range is selected,
317 * the start of the earliest range or the end of the latest range is moved.
319 * @param move_end true to move the end of the current range selection, false to move
321 * @param next true to move the extreme to the next region boundary, false to move to
325 Editor::move_range_selection_start_or_end_to_region_boundary (bool move_end, bool next)
327 if (selection->time.start() == selection->time.end_frame()) {
331 framepos_t start = selection->time.start ();
332 framepos_t end = selection->time.end_frame ();
334 /* the position of the thing we may move */
335 framepos_t pos = move_end ? end : start;
336 int dir = next ? 1 : -1;
338 /* so we don't find the current region again */
339 if (dir > 0 || pos > 0) {
343 framepos_t const target = get_region_boundary (pos, dir, true, false);
358 begin_reversible_selection_op (_("alter selection"));
359 selection->set_preserving_all_ranges (start, end);
360 commit_reversible_selection_op ();
364 Editor::nudge_forward_release (GdkEventButton* ev)
366 if (ev->state & Keyboard::PrimaryModifier) {
367 nudge_forward (false, true);
369 nudge_forward (false, false);
375 Editor::nudge_backward_release (GdkEventButton* ev)
377 if (ev->state & Keyboard::PrimaryModifier) {
378 nudge_backward (false, true);
380 nudge_backward (false, false);
387 Editor::nudge_forward (bool next, bool force_playhead)
390 framepos_t next_distance;
396 RegionSelection rs = get_regions_from_selection_and_entered ();
398 if (!force_playhead && !rs.empty()) {
400 begin_reversible_command (_("nudge regions forward"));
402 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
403 boost::shared_ptr<Region> r ((*i)->region());
405 distance = get_nudge_distance (r->position(), next_distance);
408 distance = next_distance;
412 r->set_position (r->position() + distance);
413 _session->add_command (new StatefulDiffCommand (r));
416 commit_reversible_command ();
419 } else if (!force_playhead && !selection->markers.empty()) {
422 bool in_command = false;
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);
440 loc->set_start (max_framepos - loc->length());
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);
450 loc->set_end (max_framepos);
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);
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);
544 loc->set_end (loc->length());
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);
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);
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 ();
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 ();
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 /* move selected markers to playhead */
1371 for (MarkerSelection::iterator i = selection->markers.begin(); i != selection->markers.end(); ++i) {
1374 Location* loc = find_location_from_marker (*i, ignored);
1376 if (loc->is_mark()) {
1377 loc->set_start (playhead_cursor->current_frame ());
1379 loc->set (playhead_cursor->current_frame (),
1380 playhead_cursor->current_frame () + loc->length());
1387 Editor::scroll_backward (float pages)
1389 framepos_t const one_page = (framepos_t) rint (_visible_canvas_width * samples_per_pixel);
1390 framepos_t const cnt = (framepos_t) floor (pages * one_page);
1393 if (leftmost_frame < cnt) {
1396 frame = leftmost_frame - cnt;
1399 reset_x_origin (frame);
1403 Editor::scroll_forward (float pages)
1405 framepos_t const one_page = (framepos_t) rint (_visible_canvas_width * samples_per_pixel);
1406 framepos_t const cnt = (framepos_t) floor (pages * one_page);
1409 if (max_framepos - cnt < leftmost_frame) {
1410 frame = max_framepos - cnt;
1412 frame = leftmost_frame + cnt;
1415 reset_x_origin (frame);
1419 Editor::scroll_tracks_down ()
1421 double vert_value = vertical_adjustment.get_value() + vertical_adjustment.get_page_size();
1422 if (vert_value > vertical_adjustment.get_upper() - _visible_canvas_height) {
1423 vert_value = vertical_adjustment.get_upper() - _visible_canvas_height;
1426 vertical_adjustment.set_value (vert_value);
1430 Editor::scroll_tracks_up ()
1432 vertical_adjustment.set_value (vertical_adjustment.get_value() - vertical_adjustment.get_page_size());
1436 Editor::scroll_tracks_down_line ()
1438 double vert_value = vertical_adjustment.get_value() + 60;
1440 if (vert_value > vertical_adjustment.get_upper() - _visible_canvas_height) {
1441 vert_value = vertical_adjustment.get_upper() - _visible_canvas_height;
1444 vertical_adjustment.set_value (vert_value);
1448 Editor::scroll_tracks_up_line ()
1450 reset_y_origin (vertical_adjustment.get_value() - 60);
1454 Editor::scroll_down_one_track (bool skip_child_views)
1456 TrackViewList::reverse_iterator next = track_views.rend();
1457 const double top_of_trackviews = vertical_adjustment.get_value();
1459 for (TrackViewList::reverse_iterator t = track_views.rbegin(); t != track_views.rend(); ++t) {
1460 if ((*t)->hidden()) {
1464 /* If this is the upper-most visible trackview, we want to display
1465 * the one above it (next)
1467 * Note that covers_y_position() is recursive and includes child views
1469 std::pair<TimeAxisView*,double> res = (*t)->covers_y_position (top_of_trackviews);
1472 if (skip_child_views) {
1475 /* automation lane (one level, non-recursive)
1477 * - if no automation lane exists -> move to next tack
1478 * - if the first (here: bottom-most) matches -> move to next tack
1479 * - if no y-axis match is found -> the current track is at the top
1480 * -> move to last (here: top-most) automation lane
1482 TimeAxisView::Children kids = (*t)->get_child_list();
1483 TimeAxisView::Children::reverse_iterator nkid = kids.rend();
1485 for (TimeAxisView::Children::reverse_iterator ci = kids.rbegin(); ci != kids.rend(); ++ci) {
1486 if ((*ci)->hidden()) {
1490 std::pair<TimeAxisView*,double> dev;
1491 dev = (*ci)->covers_y_position (top_of_trackviews);
1493 /* some automation lane is currently at the top */
1494 if (ci == kids.rbegin()) {
1495 /* first (bottom-most) autmation lane is at the top.
1496 * -> move to next track
1505 if (nkid != kids.rend()) {
1506 ensure_time_axis_view_is_visible (**nkid, true);
1514 /* move to the track below the first one that covers the */
1516 if (next != track_views.rend()) {
1517 ensure_time_axis_view_is_visible (**next, true);
1525 Editor::scroll_up_one_track (bool skip_child_views)
1527 TrackViewList::iterator prev = track_views.end();
1528 double top_of_trackviews = vertical_adjustment.get_value ();
1530 for (TrackViewList::iterator t = track_views.begin(); t != track_views.end(); ++t) {
1532 if ((*t)->hidden()) {
1536 /* find the trackview at the top of the trackview group
1538 * Note that covers_y_position() is recursive and includes child views
1540 std::pair<TimeAxisView*,double> res = (*t)->covers_y_position (top_of_trackviews);
1543 if (skip_child_views) {
1546 /* automation lane (one level, non-recursive)
1548 * - if no automation lane exists -> move to prev tack
1549 * - if no y-axis match is found -> the current track is at the top -> move to prev track
1550 * (actually last automation lane of previous track, see below)
1551 * - if first (top-most) lane is at the top -> move to this track
1552 * - else move up one lane
1554 TimeAxisView::Children kids = (*t)->get_child_list();
1555 TimeAxisView::Children::iterator pkid = kids.end();
1557 for (TimeAxisView::Children::iterator ci = kids.begin(); ci != kids.end(); ++ci) {
1558 if ((*ci)->hidden()) {
1562 std::pair<TimeAxisView*,double> dev;
1563 dev = (*ci)->covers_y_position (top_of_trackviews);
1565 /* some automation lane is currently at the top */
1566 if (ci == kids.begin()) {
1567 /* first (top-most) autmation lane is at the top.
1568 * jump directly to this track's top
1570 ensure_time_axis_view_is_visible (**t, true);
1573 else if (pkid != kids.end()) {
1574 /* some other automation lane is at the top.
1575 * move up to prev automation lane.
1577 ensure_time_axis_view_is_visible (**pkid, true);
1580 assert(0); // not reached
1591 if (prev != track_views.end()) {
1592 // move to bottom-most automation-lane of the previous track
1593 TimeAxisView::Children kids = (*prev)->get_child_list();
1594 TimeAxisView::Children::reverse_iterator pkid = kids.rend();
1595 if (!skip_child_views) {
1596 // find the last visible lane
1597 for (TimeAxisView::Children::reverse_iterator ci = kids.rbegin(); ci != kids.rend(); ++ci) {
1598 if (!(*ci)->hidden()) {
1604 if (pkid != kids.rend()) {
1605 ensure_time_axis_view_is_visible (**pkid, true);
1607 ensure_time_axis_view_is_visible (**prev, true);
1616 Editor::scroll_left_step ()
1618 framepos_t xdelta = (current_page_samples() / 8);
1620 if (leftmost_frame > xdelta) {
1621 reset_x_origin (leftmost_frame - xdelta);
1629 Editor::scroll_right_step ()
1631 framepos_t xdelta = (current_page_samples() / 8);
1633 if (max_framepos - xdelta > leftmost_frame) {
1634 reset_x_origin (leftmost_frame + xdelta);
1636 reset_x_origin (max_framepos - current_page_samples());
1641 Editor::scroll_left_half_page ()
1643 framepos_t xdelta = (current_page_samples() / 2);
1644 if (leftmost_frame > xdelta) {
1645 reset_x_origin (leftmost_frame - xdelta);
1652 Editor::scroll_right_half_page ()
1654 framepos_t xdelta = (current_page_samples() / 2);
1655 if (max_framepos - xdelta > leftmost_frame) {
1656 reset_x_origin (leftmost_frame + xdelta);
1658 reset_x_origin (max_framepos - current_page_samples());
1665 Editor::tav_zoom_step (bool coarser)
1667 DisplaySuspender ds;
1671 if (selection->tracks.empty()) {
1674 ts = &selection->tracks;
1677 for (TrackViewList::iterator i = ts->begin(); i != ts->end(); ++i) {
1678 TimeAxisView *tv = (static_cast<TimeAxisView*>(*i));
1679 tv->step_height (coarser);
1684 Editor::tav_zoom_smooth (bool coarser, bool force_all)
1686 DisplaySuspender ds;
1690 if (selection->tracks.empty() || force_all) {
1693 ts = &selection->tracks;
1696 for (TrackViewList::iterator i = ts->begin(); i != ts->end(); ++i) {
1697 TimeAxisView *tv = (static_cast<TimeAxisView*>(*i));
1698 uint32_t h = tv->current_height ();
1703 if (h >= TimeAxisView::preset_height (HeightSmall)) {
1708 tv->set_height (h + 5);
1714 Editor::temporal_zoom_step_mouse_focus_scale (bool zoom_out, double scale)
1716 Editing::ZoomFocus temp_focus = zoom_focus;
1717 zoom_focus = Editing::ZoomFocusMouse;
1718 temporal_zoom_step_scale (zoom_out, scale);
1719 zoom_focus = temp_focus;
1723 Editor::temporal_zoom_step_mouse_focus (bool zoom_out)
1725 temporal_zoom_step_mouse_focus_scale (zoom_out, 2.0);
1729 Editor::temporal_zoom_step (bool zoom_out)
1731 temporal_zoom_step_scale (zoom_out, 2.0);
1735 Editor::temporal_zoom_step_scale (bool zoom_out, double scale)
1737 ENSURE_GUI_THREAD (*this, &Editor::temporal_zoom_step, zoom_out, scale)
1739 framecnt_t nspp = samples_per_pixel;
1743 if (nspp == samples_per_pixel) {
1748 if (nspp == samples_per_pixel) {
1753 temporal_zoom (nspp);
1757 Editor::temporal_zoom (framecnt_t fpp)
1763 framepos_t current_page = current_page_samples();
1764 framepos_t current_leftmost = leftmost_frame;
1765 framepos_t current_rightmost;
1766 framepos_t current_center;
1767 framepos_t new_page_size;
1768 framepos_t half_page_size;
1769 framepos_t leftmost_after_zoom = 0;
1771 bool in_track_canvas;
1772 bool use_mouse_frame = true;
1776 if (fpp == samples_per_pixel) {
1780 // Imposing an arbitrary limit to zoom out as too much zoom out produces
1781 // segfaults for lack of memory. If somebody decides this is not high enough I
1782 // believe it can be raisen to higher values but some limit must be in place.
1784 // This constant represents 1 day @ 48kHz on a 1600 pixel wide display
1785 // all of which is used for the editor track displays. The whole day
1786 // would be 4147200000 samples, so 2592000 samples per pixel.
1788 nfpp = min (fpp, (framecnt_t) 2592000);
1789 nfpp = max ((framecnt_t) 1, nfpp);
1791 new_page_size = (framepos_t) floor (_visible_canvas_width * nfpp);
1792 half_page_size = new_page_size / 2;
1794 switch (zoom_focus) {
1796 leftmost_after_zoom = current_leftmost;
1799 case ZoomFocusRight:
1800 current_rightmost = leftmost_frame + current_page;
1801 if (current_rightmost < new_page_size) {
1802 leftmost_after_zoom = 0;
1804 leftmost_after_zoom = current_rightmost - new_page_size;
1808 case ZoomFocusCenter:
1809 current_center = current_leftmost + (current_page/2);
1810 if (current_center < half_page_size) {
1811 leftmost_after_zoom = 0;
1813 leftmost_after_zoom = current_center - half_page_size;
1817 case ZoomFocusPlayhead:
1818 /* centre playhead */
1819 l = playhead_cursor->current_frame () - (new_page_size * 0.5);
1822 leftmost_after_zoom = 0;
1823 } else if (l > max_framepos) {
1824 leftmost_after_zoom = max_framepos - new_page_size;
1826 leftmost_after_zoom = (framepos_t) l;
1830 case ZoomFocusMouse:
1831 /* try to keep the mouse over the same point in the display */
1833 if (_drags->active()) {
1834 where = _drags->current_pointer_frame ();
1835 } else if (!mouse_frame (where, in_track_canvas)) {
1836 use_mouse_frame = false;
1839 if (use_mouse_frame) {
1840 l = - ((new_page_size * ((where - current_leftmost)/(double)current_page)) - where);
1843 leftmost_after_zoom = 0;
1844 } else if (l > max_framepos) {
1845 leftmost_after_zoom = max_framepos - new_page_size;
1847 leftmost_after_zoom = (framepos_t) l;
1850 /* use playhead instead */
1851 where = playhead_cursor->current_frame ();
1853 if (where < half_page_size) {
1854 leftmost_after_zoom = 0;
1856 leftmost_after_zoom = where - half_page_size;
1862 /* try to keep the edit point in the same place */
1863 where = get_preferred_edit_position ();
1867 double l = - ((new_page_size * ((where - current_leftmost)/(double)current_page)) - where);
1870 leftmost_after_zoom = 0;
1871 } else if (l > max_framepos) {
1872 leftmost_after_zoom = max_framepos - new_page_size;
1874 leftmost_after_zoom = (framepos_t) l;
1878 /* edit point not defined */
1885 // leftmost_after_zoom = min (leftmost_after_zoom, _session->current_end_frame());
1887 reposition_and_zoom (leftmost_after_zoom, nfpp);
1891 Editor::calc_extra_zoom_edges(framepos_t &start, framepos_t &end)
1893 /* this func helps make sure we leave a little space
1894 at each end of the editor so that the zoom doesn't fit the region
1895 precisely to the screen.
1898 GdkScreen* screen = gdk_screen_get_default ();
1899 const gint pixwidth = gdk_screen_get_width (screen);
1900 const gint mmwidth = gdk_screen_get_width_mm (screen);
1901 const double pix_per_mm = (double) pixwidth/ (double) mmwidth;
1902 const double one_centimeter_in_pixels = pix_per_mm * 10.0;
1904 const framepos_t range = end - start;
1905 const framecnt_t new_fpp = (framecnt_t) ceil ((double) range / (double) _visible_canvas_width);
1906 const framepos_t extra_samples = (framepos_t) floor (one_centimeter_in_pixels * new_fpp);
1908 if (start > extra_samples) {
1909 start -= extra_samples;
1914 if (max_framepos - extra_samples > end) {
1915 end += extra_samples;
1922 Editor::get_selection_extents (framepos_t &start, framepos_t &end) const
1924 start = max_framepos;
1928 //ToDo: if notes are selected, set extents to that selection
1930 //ToDo: if control points are selected, set extents to that selection
1932 if ( !selection->regions.empty() ) {
1933 RegionSelection rs = get_regions_from_selection_and_entered ();
1935 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
1937 if ((*i)->region()->position() < start) {
1938 start = (*i)->region()->position();
1941 if ((*i)->region()->last_frame() + 1 > end) {
1942 end = (*i)->region()->last_frame() + 1;
1946 } else if (!selection->time.empty()) {
1947 start = selection->time.start();
1948 end = selection->time.end_frame();
1950 ret = false; //no selection found
1953 if ((start == 0 && end == 0) || end < start) {
1962 Editor::temporal_zoom_selection (Editing::ZoomAxis axes)
1964 if (!selection) return;
1966 //ToDo: if notes are selected, zoom to that
1968 //ToDo: if control points are selected, zoom to that
1970 if (axes == Horizontal || axes == Both) {
1972 framepos_t start, end;
1973 if (get_selection_extents (start, end)) {
1974 calc_extra_zoom_edges (start, end);
1975 temporal_zoom_by_frame (start, end);
1979 if (axes == Vertical || axes == Both) {
1985 Editor::temporal_zoom_session ()
1987 ENSURE_GUI_THREAD (*this, &Editor::temporal_zoom_session)
1990 framecnt_t start = _session->current_start_frame();
1991 framecnt_t end = _session->current_end_frame();
1993 if (_session->actively_recording () ) {
1994 framepos_t cur = playhead_cursor->current_frame ();
1996 /* recording beyond the end marker; zoom out
1997 * by 5 seconds more so that if 'follow
1998 * playhead' is active we don't immediately
2001 end = cur + _session->frame_rate() * 5;
2005 if ((start == 0 && end == 0) || end < start) {
2009 calc_extra_zoom_edges(start, end);
2011 temporal_zoom_by_frame (start, end);
2016 Editor::temporal_zoom_by_frame (framepos_t start, framepos_t end)
2018 if (!_session) return;
2020 if ((start == 0 && end == 0) || end < start) {
2024 framepos_t range = end - start;
2026 const framecnt_t new_fpp = (framecnt_t) ceil ((double) range / (double) _visible_canvas_width);
2028 framepos_t new_page = range;
2029 framepos_t middle = (framepos_t) floor ((double) start + ((double) range / 2.0f));
2030 framepos_t new_leftmost = (framepos_t) floor ((double) middle - ((double) new_page / 2.0f));
2032 if (new_leftmost > middle) {
2036 if (new_leftmost < 0) {
2040 reposition_and_zoom (new_leftmost, new_fpp);
2044 Editor::temporal_zoom_to_frame (bool coarser, framepos_t frame)
2050 framecnt_t range_before = frame - leftmost_frame;
2054 if (samples_per_pixel <= 1) {
2057 new_spp = samples_per_pixel + (samples_per_pixel/2);
2059 range_before += range_before/2;
2061 if (samples_per_pixel >= 1) {
2062 new_spp = samples_per_pixel - (samples_per_pixel/2);
2064 /* could bail out here since we cannot zoom any finer,
2065 but leave that to the equality test below
2067 new_spp = samples_per_pixel;
2070 range_before -= range_before/2;
2073 if (new_spp == samples_per_pixel) {
2077 /* zoom focus is automatically taken as @param frame when this
2081 framepos_t new_leftmost = frame - (framepos_t)range_before;
2083 if (new_leftmost > frame) {
2087 if (new_leftmost < 0) {
2091 reposition_and_zoom (new_leftmost, new_spp);
2096 Editor::choose_new_marker_name(string &name) {
2098 if (!UIConfiguration::instance().get_name_new_markers()) {
2099 /* don't prompt user for a new name */
2103 ArdourPrompter dialog (true);
2105 dialog.set_prompt (_("New Name:"));
2107 dialog.set_title (_("New Location Marker"));
2109 dialog.set_name ("MarkNameWindow");
2110 dialog.set_size_request (250, -1);
2111 dialog.set_position (Gtk::WIN_POS_MOUSE);
2113 dialog.add_button (Stock::OK, RESPONSE_ACCEPT);
2114 dialog.set_initial_text (name);
2118 switch (dialog.run ()) {
2119 case RESPONSE_ACCEPT:
2125 dialog.get_result(name);
2132 Editor::add_location_from_selection ()
2136 if (selection->time.empty()) {
2140 if (_session == 0 || clicked_axisview == 0) {
2144 framepos_t start = selection->time[clicked_selection].start;
2145 framepos_t end = selection->time[clicked_selection].end;
2147 _session->locations()->next_available_name(rangename,"selection");
2148 Location *location = new Location (*_session, start, end, rangename, Location::IsRangeMarker);
2150 begin_reversible_command (_("add marker"));
2152 XMLNode &before = _session->locations()->get_state();
2153 _session->locations()->add (location, true);
2154 XMLNode &after = _session->locations()->get_state();
2155 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2157 commit_reversible_command ();
2161 Editor::add_location_mark (framepos_t where)
2165 select_new_marker = true;
2167 _session->locations()->next_available_name(markername,"mark");
2168 if (!choose_new_marker_name(markername)) {
2171 Location *location = new Location (*_session, where, where, markername, Location::IsMark);
2172 begin_reversible_command (_("add marker"));
2174 XMLNode &before = _session->locations()->get_state();
2175 _session->locations()->add (location, true);
2176 XMLNode &after = _session->locations()->get_state();
2177 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2179 commit_reversible_command ();
2183 Editor::set_session_start_from_playhead ()
2189 if ((loc = _session->locations()->session_range_location()) == 0) { //should never happen
2190 _session->set_session_extents ( _session->audible_frame(), _session->audible_frame() );
2192 XMLNode &before = loc->get_state();
2194 _session->set_session_extents ( _session->audible_frame(), loc->end() );
2196 XMLNode &after = loc->get_state();
2198 begin_reversible_command (_("Set session start"));
2200 _session->add_command (new MementoCommand<Location>(*loc, &before, &after));
2202 commit_reversible_command ();
2207 Editor::set_session_end_from_playhead ()
2213 if ((loc = _session->locations()->session_range_location()) == 0) { //should never happen
2214 _session->set_session_extents ( _session->audible_frame(), _session->audible_frame() );
2216 XMLNode &before = loc->get_state();
2218 _session->set_session_extents ( loc->start(), _session->audible_frame() );
2220 XMLNode &after = loc->get_state();
2222 begin_reversible_command (_("Set session start"));
2224 _session->add_command (new MementoCommand<Location>(*loc, &before, &after));
2226 commit_reversible_command ();
2229 _session->set_end_is_free (false);
2234 Editor::toggle_location_at_playhead_cursor ()
2236 if (!do_remove_location_at_playhead_cursor())
2238 add_location_from_playhead_cursor();
2243 Editor::add_location_from_playhead_cursor ()
2245 add_location_mark (_session->audible_frame());
2249 Editor::do_remove_location_at_playhead_cursor ()
2251 bool removed = false;
2254 XMLNode &before = _session->locations()->get_state();
2256 //find location(s) at this time
2257 Locations::LocationList locs;
2258 _session->locations()->find_all_between (_session->audible_frame(), _session->audible_frame()+1, locs, Location::Flags(0));
2259 for (Locations::LocationList::iterator i = locs.begin(); i != locs.end(); ++i) {
2260 if ((*i)->is_mark()) {
2261 _session->locations()->remove (*i);
2268 begin_reversible_command (_("remove marker"));
2269 XMLNode &after = _session->locations()->get_state();
2270 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2271 commit_reversible_command ();
2278 Editor::remove_location_at_playhead_cursor ()
2280 do_remove_location_at_playhead_cursor ();
2283 /** Add a range marker around each selected region */
2285 Editor::add_locations_from_region ()
2287 RegionSelection rs = get_regions_from_selection_and_entered ();
2292 bool commit = false;
2294 XMLNode &before = _session->locations()->get_state();
2296 for (RegionSelection::iterator i = rs.begin (); i != rs.end (); ++i) {
2298 boost::shared_ptr<Region> region = (*i)->region ();
2300 Location *location = new Location (*_session, region->position(), region->last_frame(), region->name(), Location::IsRangeMarker);
2302 _session->locations()->add (location, true);
2307 begin_reversible_command (selection->regions.size () > 1 ? _("add markers") : _("add marker"));
2308 XMLNode &after = _session->locations()->get_state();
2309 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2310 commit_reversible_command ();
2314 /** Add a single range marker around all selected regions */
2316 Editor::add_location_from_region ()
2318 RegionSelection rs = get_regions_from_selection_and_entered ();
2324 XMLNode &before = _session->locations()->get_state();
2328 if (rs.size() > 1) {
2329 _session->locations()->next_available_name(markername, "regions");
2331 RegionView* rv = *(rs.begin());
2332 boost::shared_ptr<Region> region = rv->region();
2333 markername = region->name();
2336 if (!choose_new_marker_name(markername)) {
2340 // single range spanning all selected
2341 Location *location = new Location (*_session, selection->regions.start(), selection->regions.end_frame(), markername, Location::IsRangeMarker);
2342 _session->locations()->add (location, true);
2344 begin_reversible_command (_("add marker"));
2345 XMLNode &after = _session->locations()->get_state();
2346 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2347 commit_reversible_command ();
2353 Editor::jump_forward_to_mark ()
2359 framepos_t pos = _session->locations()->first_mark_after (playhead_cursor->current_frame());
2365 _session->request_locate (pos, _session->transport_rolling());
2369 Editor::jump_backward_to_mark ()
2375 framepos_t pos = _session->locations()->first_mark_before (playhead_cursor->current_frame());
2381 _session->request_locate (pos, _session->transport_rolling());
2387 framepos_t const pos = _session->audible_frame ();
2390 _session->locations()->next_available_name (markername, "mark");
2392 if (!choose_new_marker_name (markername)) {
2396 _session->locations()->add (new Location (*_session, pos, 0, markername, Location::IsMark), true);
2400 Editor::clear_markers ()
2403 begin_reversible_command (_("clear markers"));
2405 XMLNode &before = _session->locations()->get_state();
2406 _session->locations()->clear_markers ();
2407 XMLNode &after = _session->locations()->get_state();
2408 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2410 commit_reversible_command ();
2415 Editor::clear_ranges ()
2418 begin_reversible_command (_("clear ranges"));
2420 XMLNode &before = _session->locations()->get_state();
2422 _session->locations()->clear_ranges ();
2424 XMLNode &after = _session->locations()->get_state();
2425 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2427 commit_reversible_command ();
2432 Editor::clear_locations ()
2434 begin_reversible_command (_("clear locations"));
2436 XMLNode &before = _session->locations()->get_state();
2437 _session->locations()->clear ();
2438 XMLNode &after = _session->locations()->get_state();
2439 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2441 commit_reversible_command ();
2445 Editor::unhide_markers ()
2447 for (LocationMarkerMap::iterator i = location_markers.begin(); i != location_markers.end(); ++i) {
2448 Location *l = (*i).first;
2449 if (l->is_hidden() && l->is_mark()) {
2450 l->set_hidden(false, this);
2456 Editor::unhide_ranges ()
2458 for (LocationMarkerMap::iterator i = location_markers.begin(); i != location_markers.end(); ++i) {
2459 Location *l = (*i).first;
2460 if (l->is_hidden() && l->is_range_marker()) {
2461 l->set_hidden(false, this);
2466 /* INSERT/REPLACE */
2469 Editor::insert_region_list_selection (float times)
2471 RouteTimeAxisView *tv = 0;
2472 boost::shared_ptr<Playlist> playlist;
2474 if (clicked_routeview != 0) {
2475 tv = clicked_routeview;
2476 } else if (!selection->tracks.empty()) {
2477 if ((tv = dynamic_cast<RouteTimeAxisView*>(selection->tracks.front())) == 0) {
2480 } else if (entered_track != 0) {
2481 if ((tv = dynamic_cast<RouteTimeAxisView*>(entered_track)) == 0) {
2488 if ((playlist = tv->playlist()) == 0) {
2492 boost::shared_ptr<Region> region = _regions->get_single_selection ();
2497 begin_reversible_command (_("insert region"));
2498 playlist->clear_changes ();
2499 playlist->add_region ((RegionFactory::create (region, true)), get_preferred_edit_position(), times);
2500 if (Config->get_edit_mode() == Ripple)
2501 playlist->ripple (get_preferred_edit_position(), region->length() * times, boost::shared_ptr<Region>());
2503 _session->add_command(new StatefulDiffCommand (playlist));
2504 commit_reversible_command ();
2507 /* BUILT-IN EFFECTS */
2510 Editor::reverse_selection ()
2515 /* GAIN ENVELOPE EDITING */
2518 Editor::edit_envelope ()
2525 Editor::transition_to_rolling (bool fwd)
2531 if (_session->config.get_external_sync()) {
2532 switch (Config->get_sync_source()) {
2536 /* transport controlled by the master */
2541 if (_session->is_auditioning()) {
2542 _session->cancel_audition ();
2546 _session->request_transport_speed (fwd ? 1.0f : -1.0f);
2550 Editor::play_from_start ()
2552 _session->request_locate (_session->current_start_frame(), true);
2556 Editor::play_from_edit_point ()
2558 _session->request_locate (get_preferred_edit_position(), true);
2562 Editor::play_from_edit_point_and_return ()
2564 framepos_t start_frame;
2565 framepos_t return_frame;
2567 start_frame = get_preferred_edit_position ( EDIT_IGNORE_PHEAD );
2569 if (_session->transport_rolling()) {
2570 _session->request_locate (start_frame, false);
2574 /* don't reset the return frame if its already set */
2576 if ((return_frame = _session->requested_return_frame()) < 0) {
2577 return_frame = _session->audible_frame();
2580 if (start_frame >= 0) {
2581 _session->request_roll_at_and_return (start_frame, return_frame);
2586 Editor::play_selection ()
2588 framepos_t start, end;
2589 if (!get_selection_extents ( start, end))
2592 AudioRange ar (start, end, 0);
2593 list<AudioRange> lar;
2596 _session->request_play_range (&lar, true);
2600 Editor::get_preroll ()
2602 return Config->get_preroll_seconds() * _session->frame_rate();
2607 Editor::maybe_locate_with_edit_preroll ( framepos_t location )
2609 if ( _session->transport_rolling() || !UIConfiguration::instance().get_follow_edits() || _session->config.get_external_sync() )
2612 location -= get_preroll();
2614 //don't try to locate before the beginning of time
2618 //if follow_playhead is on, keep the playhead on the screen
2619 if ( _follow_playhead )
2620 if ( location < leftmost_frame )
2621 location = leftmost_frame;
2623 _session->request_locate( location );
2627 Editor::play_with_preroll ()
2630 framepos_t preroll = get_preroll();
2632 framepos_t start, end;
2633 if (!get_selection_extents ( start, end))
2636 if (start > preroll)
2637 start = start - preroll;
2639 end = end + preroll; //"post-roll"
2641 AudioRange ar (start, end, 0);
2642 list<AudioRange> lar;
2645 _session->request_play_range (&lar, true);
2650 Editor::play_location (Location& location)
2652 if (location.start() <= location.end()) {
2656 _session->request_bounded_roll (location.start(), location.end());
2660 Editor::loop_location (Location& location)
2662 if (location.start() <= location.end()) {
2668 if ((tll = transport_loop_location()) != 0) {
2669 tll->set (location.start(), location.end());
2671 // enable looping, reposition and start rolling
2672 _session->request_locate (tll->start(), true);
2673 _session->request_play_loop (true);
2678 Editor::do_layer_operation (LayerOperation op)
2680 if (selection->regions.empty ()) {
2684 bool const multiple = selection->regions.size() > 1;
2688 begin_reversible_command (_("raise regions"));
2690 begin_reversible_command (_("raise region"));
2696 begin_reversible_command (_("raise regions to top"));
2698 begin_reversible_command (_("raise region to top"));
2704 begin_reversible_command (_("lower regions"));
2706 begin_reversible_command (_("lower region"));
2712 begin_reversible_command (_("lower regions to bottom"));
2714 begin_reversible_command (_("lower region"));
2719 set<boost::shared_ptr<Playlist> > playlists = selection->regions.playlists ();
2720 for (set<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
2721 (*i)->clear_owned_changes ();
2724 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
2725 boost::shared_ptr<Region> r = (*i)->region ();
2737 r->lower_to_bottom ();
2741 for (set<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
2742 vector<Command*> cmds;
2744 _session->add_commands (cmds);
2747 commit_reversible_command ();
2751 Editor::raise_region ()
2753 do_layer_operation (Raise);
2757 Editor::raise_region_to_top ()
2759 do_layer_operation (RaiseToTop);
2763 Editor::lower_region ()
2765 do_layer_operation (Lower);
2769 Editor::lower_region_to_bottom ()
2771 do_layer_operation (LowerToBottom);
2774 /** Show the region editor for the selected regions */
2776 Editor::show_region_properties ()
2778 selection->foreach_regionview (&RegionView::show_region_editor);
2781 /** Show the midi list editor for the selected MIDI regions */
2783 Editor::show_midi_list_editor ()
2785 selection->foreach_midi_regionview (&MidiRegionView::show_list_editor);
2789 Editor::rename_region ()
2791 RegionSelection rs = get_regions_from_selection_and_entered ();
2797 ArdourDialog d (_("Rename Region"), true, false);
2799 Label label (_("New name:"));
2802 hbox.set_spacing (6);
2803 hbox.pack_start (label, false, false);
2804 hbox.pack_start (entry, true, true);
2806 d.get_vbox()->set_border_width (12);
2807 d.get_vbox()->pack_start (hbox, false, false);
2809 d.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
2810 d.add_button(Gtk::Stock::OK, Gtk::RESPONSE_OK);
2812 d.set_size_request (300, -1);
2814 entry.set_text (rs.front()->region()->name());
2815 entry.select_region (0, -1);
2817 entry.signal_activate().connect (sigc::bind (sigc::mem_fun (d, &Dialog::response), RESPONSE_OK));
2823 int const ret = d.run();
2827 if (ret != RESPONSE_OK) {
2831 std::string str = entry.get_text();
2832 strip_whitespace_edges (str);
2834 rs.front()->region()->set_name (str);
2835 _regions->redisplay ();
2839 /** Start an audition of the first selected region */
2841 Editor::play_edit_range ()
2843 framepos_t start, end;
2845 if (get_edit_op_range (start, end)) {
2846 _session->request_bounded_roll (start, end);
2851 Editor::play_selected_region ()
2853 framepos_t start = max_framepos;
2856 RegionSelection rs = get_regions_from_selection_and_entered ();
2862 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
2863 if ((*i)->region()->position() < start) {
2864 start = (*i)->region()->position();
2866 if ((*i)->region()->last_frame() + 1 > end) {
2867 end = (*i)->region()->last_frame() + 1;
2871 _session->request_bounded_roll (start, end);
2875 Editor::audition_playlist_region_standalone (boost::shared_ptr<Region> region)
2877 _session->audition_region (region);
2881 Editor::region_from_selection ()
2883 if (clicked_axisview == 0) {
2887 if (selection->time.empty()) {
2891 framepos_t start = selection->time[clicked_selection].start;
2892 framepos_t end = selection->time[clicked_selection].end;
2894 TrackViewList tracks = get_tracks_for_range_action ();
2896 framepos_t selection_cnt = end - start + 1;
2898 for (TrackSelection::iterator i = tracks.begin(); i != tracks.end(); ++i) {
2899 boost::shared_ptr<Region> current;
2900 boost::shared_ptr<Playlist> pl;
2901 framepos_t internal_start;
2904 if ((pl = (*i)->playlist()) == 0) {
2908 if ((current = pl->top_region_at (start)) == 0) {
2912 internal_start = start - current->position();
2913 RegionFactory::region_name (new_name, current->name(), true);
2917 plist.add (ARDOUR::Properties::start, current->start() + internal_start);
2918 plist.add (ARDOUR::Properties::length, selection_cnt);
2919 plist.add (ARDOUR::Properties::name, new_name);
2920 plist.add (ARDOUR::Properties::layer, 0);
2922 boost::shared_ptr<Region> region (RegionFactory::create (current, plist));
2927 Editor::create_region_from_selection (vector<boost::shared_ptr<Region> >& new_regions)
2929 if (selection->time.empty() || selection->tracks.empty()) {
2933 framepos_t start, end;
2934 if (clicked_selection) {
2935 start = selection->time[clicked_selection].start;
2936 end = selection->time[clicked_selection].end;
2938 start = selection->time.start();
2939 end = selection->time.end_frame();
2942 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
2943 sort_track_selection (ts);
2945 for (TrackSelection::iterator i = ts.begin(); i != ts.end(); ++i) {
2946 boost::shared_ptr<Region> current;
2947 boost::shared_ptr<Playlist> playlist;
2948 framepos_t internal_start;
2951 if ((playlist = (*i)->playlist()) == 0) {
2955 if ((current = playlist->top_region_at(start)) == 0) {
2959 internal_start = start - current->position();
2960 RegionFactory::region_name (new_name, current->name(), true);
2964 plist.add (ARDOUR::Properties::start, current->start() + internal_start);
2965 plist.add (ARDOUR::Properties::length, end - start + 1);
2966 plist.add (ARDOUR::Properties::name, new_name);
2968 new_regions.push_back (RegionFactory::create (current, plist));
2973 Editor::split_multichannel_region ()
2975 RegionSelection rs = get_regions_from_selection_and_entered ();
2981 vector< boost::shared_ptr<Region> > v;
2983 for (list<RegionView*>::iterator x = rs.begin(); x != rs.end(); ++x) {
2984 (*x)->region()->separate_by_channel (*_session, v);
2989 Editor::new_region_from_selection ()
2991 region_from_selection ();
2992 cancel_selection ();
2996 add_if_covered (RegionView* rv, const AudioRange* ar, RegionSelection* rs)
2998 switch (rv->region()->coverage (ar->start, ar->end - 1)) {
2999 // n.b. -1 because AudioRange::end is one past the end, but coverage expects inclusive ranges
3000 case Evoral::OverlapNone:
3008 * - selected tracks, or if there are none...
3009 * - tracks containing selected regions, or if there are none...
3014 Editor::get_tracks_for_range_action () const
3018 if (selection->tracks.empty()) {
3020 /* use tracks with selected regions */
3022 RegionSelection rs = selection->regions;
3024 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3025 TimeAxisView* tv = &(*i)->get_time_axis_view();
3027 if (!t.contains (tv)) {
3033 /* no regions and no tracks: use all tracks */
3039 t = selection->tracks;
3042 return t.filter_to_unique_playlists();
3046 Editor::separate_regions_between (const TimeSelection& ts)
3048 bool in_command = false;
3049 boost::shared_ptr<Playlist> playlist;
3050 RegionSelection new_selection;
3052 TrackViewList tmptracks = get_tracks_for_range_action ();
3053 sort_track_selection (tmptracks);
3055 for (TrackSelection::iterator i = tmptracks.begin(); i != tmptracks.end(); ++i) {
3057 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> ((*i));
3063 if (!rtv->is_track()) {
3067 /* no edits to destructive tracks */
3069 if (rtv->track()->destructive()) {
3073 if ((playlist = rtv->playlist()) != 0) {
3075 playlist->clear_changes ();
3077 /* XXX need to consider musical time selections here at some point */
3079 double speed = rtv->track()->speed();
3081 for (list<AudioRange>::const_iterator t = ts.begin(); t != ts.end(); ++t) {
3083 sigc::connection c = rtv->view()->RegionViewAdded.connect (
3084 sigc::mem_fun(*this, &Editor::collect_new_region_view));
3086 latest_regionviews.clear ();
3088 playlist->partition ((framepos_t)((*t).start * speed),
3089 (framepos_t)((*t).end * speed), false);
3093 if (!latest_regionviews.empty()) {
3095 rtv->view()->foreach_regionview (sigc::bind (
3096 sigc::ptr_fun (add_if_covered),
3097 &(*t), &new_selection));
3100 begin_reversible_command (_("separate"));
3104 /* pick up changes to existing regions */
3106 vector<Command*> cmds;
3107 playlist->rdiff (cmds);
3108 _session->add_commands (cmds);
3110 /* pick up changes to the playlist itself (adds/removes)
3113 _session->add_command(new StatefulDiffCommand (playlist));
3120 // selection->set (new_selection);
3122 commit_reversible_command ();
3126 struct PlaylistState {
3127 boost::shared_ptr<Playlist> playlist;
3131 /** Take tracks from get_tracks_for_range_action and cut any regions
3132 * on those tracks so that the tracks are empty over the time
3136 Editor::separate_region_from_selection ()
3138 /* preferentially use *all* ranges in the time selection if we're in range mode
3139 to allow discontiguous operation, since get_edit_op_range() currently
3140 returns a single range.
3143 if (!selection->time.empty()) {
3145 separate_regions_between (selection->time);
3152 if (get_edit_op_range (start, end)) {
3154 AudioRange ar (start, end, 1);
3158 separate_regions_between (ts);
3164 Editor::separate_region_from_punch ()
3166 Location* loc = _session->locations()->auto_punch_location();
3168 separate_regions_using_location (*loc);
3173 Editor::separate_region_from_loop ()
3175 Location* loc = _session->locations()->auto_loop_location();
3177 separate_regions_using_location (*loc);
3182 Editor::separate_regions_using_location (Location& loc)
3184 if (loc.is_mark()) {
3188 AudioRange ar (loc.start(), loc.end(), 1);
3193 separate_regions_between (ts);
3196 /** Separate regions under the selected region */
3198 Editor::separate_under_selected_regions ()
3200 vector<PlaylistState> playlists;
3204 rs = get_regions_from_selection_and_entered();
3206 if (!_session || rs.empty()) {
3210 begin_reversible_command (_("separate region under"));
3212 list<boost::shared_ptr<Region> > regions_to_remove;
3214 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3215 // we can't just remove the region(s) in this loop because
3216 // this removes them from the RegionSelection, and they thus
3217 // disappear from underneath the iterator, and the ++i above
3218 // SEGVs in a puzzling fashion.
3220 // so, first iterate over the regions to be removed from rs and
3221 // add them to the regions_to_remove list, and then
3222 // iterate over the list to actually remove them.
3224 regions_to_remove.push_back ((*i)->region());
3227 for (list<boost::shared_ptr<Region> >::iterator rl = regions_to_remove.begin(); rl != regions_to_remove.end(); ++rl) {
3229 boost::shared_ptr<Playlist> playlist = (*rl)->playlist();
3232 // is this check necessary?
3236 vector<PlaylistState>::iterator i;
3238 //only take state if this is a new playlist.
3239 for (i = playlists.begin(); i != playlists.end(); ++i) {
3240 if ((*i).playlist == playlist) {
3245 if (i == playlists.end()) {
3247 PlaylistState before;
3248 before.playlist = playlist;
3249 before.before = &playlist->get_state();
3251 playlist->freeze ();
3252 playlists.push_back(before);
3255 //Partition on the region bounds
3256 playlist->partition ((*rl)->first_frame() - 1, (*rl)->last_frame() + 1, true);
3258 //Re-add region that was just removed due to the partition operation
3259 playlist->add_region( (*rl), (*rl)->first_frame() );
3262 vector<PlaylistState>::iterator pl;
3264 for (pl = playlists.begin(); pl != playlists.end(); ++pl) {
3265 (*pl).playlist->thaw ();
3266 _session->add_command(new MementoCommand<Playlist>(*(*pl).playlist, (*pl).before, &(*pl).playlist->get_state()));
3269 commit_reversible_command ();
3273 Editor::crop_region_to_selection ()
3275 if (!selection->time.empty()) {
3277 crop_region_to (selection->time.start(), selection->time.end_frame());
3284 if (get_edit_op_range (start, end)) {
3285 crop_region_to (start, end);
3292 Editor::crop_region_to (framepos_t start, framepos_t end)
3294 vector<boost::shared_ptr<Playlist> > playlists;
3295 boost::shared_ptr<Playlist> playlist;
3298 if (selection->tracks.empty()) {
3299 ts = track_views.filter_to_unique_playlists();
3301 ts = selection->tracks.filter_to_unique_playlists ();
3304 sort_track_selection (ts);
3306 for (TrackSelection::iterator i = ts.begin(); i != ts.end(); ++i) {
3308 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> ((*i));
3314 boost::shared_ptr<Track> t = rtv->track();
3316 if (t != 0 && ! t->destructive()) {
3318 if ((playlist = rtv->playlist()) != 0) {
3319 playlists.push_back (playlist);
3324 if (playlists.empty()) {
3329 framepos_t new_start;
3331 framecnt_t new_length;
3332 bool in_command = false;
3334 for (vector<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
3336 /* Only the top regions at start and end have to be cropped */
3337 boost::shared_ptr<Region> region_at_start = (*i)->top_region_at(start);
3338 boost::shared_ptr<Region> region_at_end = (*i)->top_region_at(end);
3340 vector<boost::shared_ptr<Region> > regions;
3342 if (region_at_start != 0) {
3343 regions.push_back (region_at_start);
3345 if (region_at_end != 0) {
3346 regions.push_back (region_at_end);
3349 /* now adjust lengths */
3350 for (vector<boost::shared_ptr<Region> >::iterator i = regions.begin(); i != regions.end(); ++i) {
3352 pos = (*i)->position();
3353 new_start = max (start, pos);
3354 if (max_framepos - pos > (*i)->length()) {
3355 new_end = pos + (*i)->length() - 1;
3357 new_end = max_framepos;
3359 new_end = min (end, new_end);
3360 new_length = new_end - new_start + 1;
3363 begin_reversible_command (_("trim to selection"));
3366 (*i)->clear_changes ();
3367 (*i)->trim_to (new_start, new_length);
3368 _session->add_command (new StatefulDiffCommand (*i));
3373 commit_reversible_command ();
3378 Editor::region_fill_track ()
3380 boost::shared_ptr<Playlist> playlist;
3381 RegionSelection regions = get_regions_from_selection_and_entered ();
3382 RegionSelection foo;
3384 framepos_t const end = _session->current_end_frame ();
3386 if (regions.empty () || regions.end_frame () + 1 >= end) {
3390 framepos_t const start_frame = regions.start ();
3391 framepos_t const end_frame = regions.end_frame ();
3392 framecnt_t const gap = end_frame - start_frame + 1;
3394 begin_reversible_command (Operations::region_fill);
3396 selection->clear_regions ();
3398 for (RegionSelection::iterator i = regions.begin(); i != regions.end(); ++i) {
3400 boost::shared_ptr<Region> r ((*i)->region());
3402 TimeAxisView& tv = (*i)->get_time_axis_view();
3403 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (&tv);
3404 latest_regionviews.clear ();
3405 sigc::connection c = rtv->view()->RegionViewAdded.connect (sigc::mem_fun(*this, &Editor::collect_new_region_view));
3407 framepos_t const position = end_frame + (r->first_frame() - start_frame + 1);
3408 playlist = (*i)->region()->playlist();
3409 playlist->clear_changes ();
3410 playlist->duplicate_until (r, position, gap, end);
3411 _session->add_command(new StatefulDiffCommand (playlist));
3415 foo.insert (foo.end(), latest_regionviews.begin(), latest_regionviews.end());
3419 selection->set (foo);
3422 commit_reversible_command ();
3426 Editor::set_region_sync_position ()
3428 set_sync_point (get_preferred_edit_position (), get_regions_from_selection_and_edit_point ());
3432 Editor::set_sync_point (framepos_t where, const RegionSelection& rs)
3434 bool in_command = false;
3436 for (RegionSelection::const_iterator r = rs.begin(); r != rs.end(); ++r) {
3438 if (!(*r)->region()->covers (where)) {
3442 boost::shared_ptr<Region> region ((*r)->region());
3445 begin_reversible_command (_("set sync point"));
3449 region->clear_changes ();
3450 region->set_sync_position (where);
3451 _session->add_command(new StatefulDiffCommand (region));
3455 commit_reversible_command ();
3459 /** Remove the sync positions of the selection */
3461 Editor::remove_region_sync ()
3463 RegionSelection rs = get_regions_from_selection_and_entered ();
3469 begin_reversible_command (_("remove region sync"));
3471 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3473 (*i)->region()->clear_changes ();
3474 (*i)->region()->clear_sync_position ();
3475 _session->add_command(new StatefulDiffCommand ((*i)->region()));
3478 commit_reversible_command ();
3482 Editor::naturalize_region ()
3484 RegionSelection rs = get_regions_from_selection_and_entered ();
3490 if (rs.size() > 1) {
3491 begin_reversible_command (_("move regions to original position"));
3493 begin_reversible_command (_("move region to original position"));
3496 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3497 (*i)->region()->clear_changes ();
3498 (*i)->region()->move_to_natural_position ();
3499 _session->add_command (new StatefulDiffCommand ((*i)->region()));
3502 commit_reversible_command ();
3506 Editor::align_regions (RegionPoint what)
3508 RegionSelection const rs = get_regions_from_selection_and_edit_point ();
3514 begin_reversible_command (_("align selection"));
3516 framepos_t const position = get_preferred_edit_position ();
3518 for (RegionSelection::const_iterator i = rs.begin(); i != rs.end(); ++i) {
3519 align_region_internal ((*i)->region(), what, position);
3522 commit_reversible_command ();
3525 struct RegionSortByTime {
3526 bool operator() (const RegionView* a, const RegionView* b) {
3527 return a->region()->position() < b->region()->position();
3532 Editor::align_regions_relative (RegionPoint point)
3534 RegionSelection const rs = get_regions_from_selection_and_edit_point ();
3540 framepos_t const position = get_preferred_edit_position ();
3542 framepos_t distance = 0;
3546 list<RegionView*> sorted;
3547 rs.by_position (sorted);
3549 boost::shared_ptr<Region> r ((*sorted.begin())->region());
3554 if (position > r->position()) {
3555 distance = position - r->position();
3557 distance = r->position() - position;
3563 if (position > r->last_frame()) {
3564 distance = position - r->last_frame();
3565 pos = r->position() + distance;
3567 distance = r->last_frame() - position;
3568 pos = r->position() - distance;
3574 pos = r->adjust_to_sync (position);
3575 if (pos > r->position()) {
3576 distance = pos - r->position();
3578 distance = r->position() - pos;
3584 if (pos == r->position()) {
3588 begin_reversible_command (_("align selection (relative)"));
3590 /* move first one specially */
3592 r->clear_changes ();
3593 r->set_position (pos);
3594 _session->add_command(new StatefulDiffCommand (r));
3596 /* move rest by the same amount */
3600 for (list<RegionView*>::iterator i = sorted.begin(); i != sorted.end(); ++i) {
3602 boost::shared_ptr<Region> region ((*i)->region());
3604 region->clear_changes ();
3607 region->set_position (region->position() + distance);
3609 region->set_position (region->position() - distance);
3612 _session->add_command(new StatefulDiffCommand (region));
3616 commit_reversible_command ();
3620 Editor::align_region (boost::shared_ptr<Region> region, RegionPoint point, framepos_t position)
3622 begin_reversible_command (_("align region"));
3623 align_region_internal (region, point, position);
3624 commit_reversible_command ();
3628 Editor::align_region_internal (boost::shared_ptr<Region> region, RegionPoint point, framepos_t position)
3630 region->clear_changes ();
3634 region->set_position (region->adjust_to_sync (position));
3638 if (position > region->length()) {
3639 region->set_position (position - region->length());
3644 region->set_position (position);
3648 _session->add_command(new StatefulDiffCommand (region));
3652 Editor::trim_region_front ()
3658 Editor::trim_region_back ()
3660 trim_region (false);
3664 Editor::trim_region (bool front)
3666 framepos_t where = get_preferred_edit_position();
3667 RegionSelection rs = get_regions_from_selection_and_edit_point ();
3673 begin_reversible_command (front ? _("trim front") : _("trim back"));
3675 for (list<RegionView*>::const_iterator i = rs.by_layer().begin(); i != rs.by_layer().end(); ++i) {
3676 if (!(*i)->region()->locked()) {
3678 (*i)->region()->clear_changes ();
3681 (*i)->region()->trim_front (where);
3683 (*i)->region()->trim_end (where);
3686 _session->add_command (new StatefulDiffCommand ((*i)->region()));
3690 commit_reversible_command ();
3693 /** Trim the end of the selected regions to the position of the edit cursor */
3695 Editor::trim_region_to_loop ()
3697 Location* loc = _session->locations()->auto_loop_location();
3701 trim_region_to_location (*loc, _("trim to loop"));
3705 Editor::trim_region_to_punch ()
3707 Location* loc = _session->locations()->auto_punch_location();
3711 trim_region_to_location (*loc, _("trim to punch"));
3715 Editor::trim_region_to_location (const Location& loc, const char* str)
3717 RegionSelection rs = get_regions_from_selection_and_entered ();
3718 bool in_command = false;
3720 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
3721 RegionView* rv = (*x);
3723 /* require region to span proposed trim */
3724 switch (rv->region()->coverage (loc.start(), loc.end())) {
3725 case Evoral::OverlapInternal:
3731 RouteTimeAxisView* tav = dynamic_cast<RouteTimeAxisView*> (&rv->get_time_axis_view());
3740 if (tav->track() != 0) {
3741 speed = tav->track()->speed();
3744 start = session_frame_to_track_frame (loc.start(), speed);
3745 end = session_frame_to_track_frame (loc.end(), speed);
3747 rv->region()->clear_changes ();
3748 rv->region()->trim_to (start, (end - start));
3751 begin_reversible_command (str);
3754 _session->add_command(new StatefulDiffCommand (rv->region()));
3758 commit_reversible_command ();
3763 Editor::trim_region_to_previous_region_end ()
3765 return trim_to_region(false);
3769 Editor::trim_region_to_next_region_start ()
3771 return trim_to_region(true);
3775 Editor::trim_to_region(bool forward)
3777 RegionSelection rs = get_regions_from_selection_and_entered ();
3778 bool in_command = false;
3780 boost::shared_ptr<Region> next_region;
3782 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
3784 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*x);
3790 AudioTimeAxisView* atav = dynamic_cast<AudioTimeAxisView*> (&arv->get_time_axis_view());
3798 if (atav->track() != 0) {
3799 speed = atav->track()->speed();
3803 boost::shared_ptr<Region> region = arv->region();
3804 boost::shared_ptr<Playlist> playlist (region->playlist());
3806 region->clear_changes ();
3810 next_region = playlist->find_next_region (region->first_frame(), Start, 1);
3816 region->trim_end((framepos_t) ( (next_region->first_frame() - 1) * speed));
3817 arv->region_changed (PropertyChange (ARDOUR::Properties::length));
3821 next_region = playlist->find_next_region (region->first_frame(), Start, 0);
3827 region->trim_front((framepos_t) ((next_region->last_frame() + 1) * speed));
3829 arv->region_changed (ARDOUR::bounds_change);
3833 begin_reversible_command (_("trim to region"));
3836 _session->add_command(new StatefulDiffCommand (region));
3840 commit_reversible_command ();
3845 Editor::unfreeze_route ()
3847 if (clicked_routeview == 0 || !clicked_routeview->is_track()) {
3851 clicked_routeview->track()->unfreeze ();
3855 Editor::_freeze_thread (void* arg)
3857 return static_cast<Editor*>(arg)->freeze_thread ();
3861 Editor::freeze_thread ()
3863 /* create event pool because we may need to talk to the session */
3864 SessionEvent::create_per_thread_pool ("freeze events", 64);
3865 /* create per-thread buffers for process() tree to use */
3866 clicked_routeview->audio_track()->freeze_me (*current_interthread_info);
3867 current_interthread_info->done = true;
3872 Editor::freeze_route ()
3878 /* stop transport before we start. this is important */
3880 _session->request_transport_speed (0.0);
3882 /* wait for just a little while, because the above call is asynchronous */
3884 Glib::usleep (250000);
3886 if (clicked_routeview == 0 || !clicked_routeview->is_audio_track()) {
3890 if (!clicked_routeview->track()->bounceable (clicked_routeview->track()->main_outs(), true)) {
3892 _("This track/bus cannot be frozen because the signal adds or loses channels before reaching the outputs.\n"
3893 "This is typically caused by plugins that generate stereo output from mono input or vice versa.")
3895 d.set_title (_("Cannot freeze"));
3900 if (clicked_routeview->track()->has_external_redirects()) {
3901 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"
3902 "Freezing will only process the signal as far as the first send/insert/return."),
3903 clicked_routeview->track()->name()), true, MESSAGE_INFO, BUTTONS_NONE, true);
3905 d.add_button (_("Freeze anyway"), Gtk::RESPONSE_OK);
3906 d.add_button (_("Don't freeze"), Gtk::RESPONSE_CANCEL);
3907 d.set_title (_("Freeze Limits"));
3909 int response = d.run ();
3912 case Gtk::RESPONSE_CANCEL:
3919 InterThreadInfo itt;
3920 current_interthread_info = &itt;
3922 InterthreadProgressWindow ipw (current_interthread_info, _("Freeze"), _("Cancel Freeze"));
3924 pthread_create_and_store (X_("freezer"), &itt.thread, _freeze_thread, this);
3926 CursorContext::Handle cursor_ctx = CursorContext::create(*this, _cursors->wait);
3928 while (!itt.done && !itt.cancel) {
3929 gtk_main_iteration ();
3932 pthread_join (itt.thread, 0);
3933 current_interthread_info = 0;
3937 Editor::bounce_range_selection (bool replace, bool enable_processing)
3939 if (selection->time.empty()) {
3943 TrackSelection views = selection->tracks;
3945 for (TrackViewList::iterator i = views.begin(); i != views.end(); ++i) {
3947 if (enable_processing) {
3949 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*i);
3951 if (rtv && rtv->track() && replace && enable_processing && !rtv->track()->bounceable (rtv->track()->main_outs(), false)) {
3953 _("You can't perform this operation because the processing of the signal "
3954 "will cause one or more of the tracks to end up with a region with more channels than this track has inputs.\n\n"
3955 "You can do this without processing, which is a different operation.")
3957 d.set_title (_("Cannot bounce"));
3964 framepos_t start = selection->time[clicked_selection].start;
3965 framepos_t end = selection->time[clicked_selection].end;
3966 framepos_t cnt = end - start + 1;
3967 bool in_command = false;
3969 for (TrackViewList::iterator i = views.begin(); i != views.end(); ++i) {
3971 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*i);
3977 boost::shared_ptr<Playlist> playlist;
3979 if ((playlist = rtv->playlist()) == 0) {
3983 InterThreadInfo itt;
3985 playlist->clear_changes ();
3986 playlist->clear_owned_changes ();
3988 boost::shared_ptr<Region> r;
3990 if (enable_processing) {
3991 r = rtv->track()->bounce_range (start, start+cnt, itt, rtv->track()->main_outs(), false);
3993 r = rtv->track()->bounce_range (start, start+cnt, itt, boost::shared_ptr<Processor>(), false);
4001 list<AudioRange> ranges;
4002 ranges.push_back (AudioRange (start, start+cnt, 0));
4003 playlist->cut (ranges); // discard result
4004 playlist->add_region (r, start);
4008 begin_reversible_command (_("bounce range"));
4011 vector<Command*> cmds;
4012 playlist->rdiff (cmds);
4013 _session->add_commands (cmds);
4015 _session->add_command (new StatefulDiffCommand (playlist));
4019 commit_reversible_command ();
4023 /** Delete selected regions, automation points or a time range */
4027 //special case: if the user is pointing in the editor/mixer strip, they may be trying to delete a plugin.
4028 //we need this because the editor-mixer strip is in the editor window, so it doesn't get the bindings from the mix window
4029 bool deleted = false;
4030 if ( current_mixer_strip && current_mixer_strip == MixerStrip::entered_mixer_strip() )
4031 deleted = current_mixer_strip->delete_processors ();
4037 /** Cut selected regions, automation points or a time range */
4044 /** Copy selected regions, automation points or a time range */
4052 /** @return true if a Cut, Copy or Clear is possible */
4054 Editor::can_cut_copy () const
4056 if (!selection->time.empty() || !selection->regions.empty() || !selection->points.empty())
4063 /** Cut, copy or clear selected regions, automation points or a time range.
4064 * @param op Operation (Delete, Cut, Copy or Clear)
4067 Editor::cut_copy (CutCopyOp op)
4069 /* only cancel selection if cut/copy is successful.*/
4075 opname = _("delete");
4084 opname = _("clear");
4088 /* if we're deleting something, and the mouse is still pressed,
4089 the thing we started a drag for will be gone when we release
4090 the mouse button(s). avoid this. see part 2 at the end of
4094 if (op == Delete || op == Cut || op == Clear) {
4095 if (_drags->active ()) {
4100 if ( op != Delete ) //"Delete" doesn't change copy/paste buf
4101 cut_buffer->clear ();
4103 if (entered_marker) {
4105 /* cut/delete op while pointing at a marker */
4108 Location* loc = find_location_from_marker (entered_marker, ignored);
4110 if (_session && loc) {
4111 entered_marker = NULL;
4112 Glib::signal_idle().connect (sigc::bind (sigc::mem_fun(*this, &Editor::really_remove_marker), loc));
4119 switch (mouse_mode) {
4122 begin_reversible_command (opname + ' ' + X_("MIDI"));
4124 commit_reversible_command ();
4130 bool did_edit = false;
4132 if (!selection->regions.empty() || !selection->points.empty()) {
4133 begin_reversible_command (opname + ' ' + _("objects"));
4136 if (!selection->regions.empty()) {
4137 cut_copy_regions (op, selection->regions);
4139 if (op == Cut || op == Delete) {
4140 selection->clear_regions ();
4144 if (!selection->points.empty()) {
4145 cut_copy_points (op);
4147 if (op == Cut || op == Delete) {
4148 selection->clear_points ();
4151 } else if (selection->time.empty()) {
4152 framepos_t start, end;
4153 /* no time selection, see if we can get an edit range
4156 if (get_edit_op_range (start, end)) {
4157 selection->set (start, end);
4159 } else if (!selection->time.empty()) {
4160 begin_reversible_command (opname + ' ' + _("range"));
4163 cut_copy_ranges (op);
4165 if (op == Cut || op == Delete) {
4166 selection->clear_time ();
4171 /* reset repeated paste state */
4174 commit_reversible_command ();
4177 if (op == Delete || op == Cut || op == Clear) {
4183 struct AutomationRecord {
4184 AutomationRecord () : state (0) , line(NULL) {}
4185 AutomationRecord (XMLNode* s, const AutomationLine* l) : state (s) , line (l) {}
4187 XMLNode* state; ///< state before any operation
4188 const AutomationLine* line; ///< line this came from
4189 boost::shared_ptr<Evoral::ControlList> copy; ///< copied events for the cut buffer
4191 struct PointsSelectionPositionSorter {
4192 bool operator() (ControlPoint* a, ControlPoint* b) {
4193 return (*(a->model()))->when < (*(b->model()))->when;
4196 /** Cut, copy or clear selected automation points.
4197 * @param op Operation (Cut, Copy or Clear)
4200 Editor::cut_copy_points (Editing::CutCopyOp op, Evoral::Beats earliest, bool midi)
4202 if (selection->points.empty ()) {
4206 /* XXX: not ideal, as there may be more than one track involved in the point selection */
4207 _last_cut_copy_source_track = &selection->points.front()->line().trackview;
4209 /* Keep a record of the AutomationLists that we end up using in this operation */
4210 typedef std::map<boost::shared_ptr<AutomationList>, AutomationRecord> Lists;
4213 /* user could select points in any order */
4214 selection->points.sort(PointsSelectionPositionSorter ());
4216 /* Go through all selected points, making an AutomationRecord for each distinct AutomationList */
4217 for (PointSelection::iterator sel_point = selection->points.begin(); sel_point != selection->points.end(); ++sel_point) {
4218 const AutomationLine& line = (*sel_point)->line();
4219 const boost::shared_ptr<AutomationList> al = line.the_list();
4220 if (lists.find (al) == lists.end ()) {
4221 /* We haven't seen this list yet, so make a record for it. This includes
4222 taking a copy of its current state, in case this is needed for undo later.
4224 lists[al] = AutomationRecord (&al->get_state (), &line);
4228 if (op == Cut || op == Copy) {
4229 /* This operation will involve putting things in the cut buffer, so create an empty
4230 ControlList for each of our source lists to put the cut buffer data in.
4232 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
4233 i->second.copy = i->first->create (i->first->parameter (), i->first->descriptor());
4236 /* Add all selected points to the relevant copy ControlLists */
4237 framepos_t start = std::numeric_limits<framepos_t>::max();
4238 for (PointSelection::iterator sel_point = selection->points.begin(); sel_point != selection->points.end(); ++sel_point) {
4239 boost::shared_ptr<AutomationList> al = (*sel_point)->line().the_list();
4240 AutomationList::const_iterator ctrl_evt = (*sel_point)->model ();
4242 lists[al].copy->fast_simple_add ((*ctrl_evt)->when, (*ctrl_evt)->value);
4244 /* Update earliest MIDI start time in beats */
4245 earliest = std::min(earliest, Evoral::Beats((*ctrl_evt)->when));
4247 /* Update earliest session start time in frames */
4248 start = std::min(start, (*sel_point)->line().session_position(ctrl_evt));
4252 /* Snap start time backwards, so copy/paste is snap aligned. */
4254 if (earliest == Evoral::Beats::max()) {
4255 earliest = Evoral::Beats(); // Weird... don't offset
4257 earliest.round_down_to_beat();
4259 if (start == std::numeric_limits<double>::max()) {
4260 start = 0; // Weird... don't offset
4262 snap_to(start, RoundDownMaybe);
4265 const double line_offset = midi ? earliest.to_double() : start;
4266 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
4267 /* Correct this copy list so that it is relative to the earliest
4268 start time, so relative ordering between points is preserved
4269 when copying from several lists and the paste starts at the
4270 earliest copied piece of data. */
4271 boost::shared_ptr<Evoral::ControlList> &al_cpy = i->second.copy;
4272 for (AutomationList::iterator ctrl_evt = al_cpy->begin(); ctrl_evt != al_cpy->end(); ++ctrl_evt) {
4273 (*ctrl_evt)->when -= line_offset;
4276 /* And add it to the cut buffer */
4277 cut_buffer->add (al_cpy);
4281 if (op == Delete || op == Cut) {
4282 /* This operation needs to remove things from the main AutomationList, so do that now */
4284 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
4285 i->first->freeze ();
4288 /* Remove each selected point from its AutomationList */
4289 for (PointSelection::iterator sel_point = selection->points.begin(); sel_point != selection->points.end(); ++sel_point) {
4290 AutomationLine& line = (*sel_point)->line ();
4291 boost::shared_ptr<AutomationList> al = line.the_list();
4295 if (dynamic_cast<AudioRegionGainLine*> (&line)) {
4296 /* removing of first and last gain point in region gain lines is prohibited*/
4297 if (line.is_last_point (*(*sel_point)) || line.is_first_point (*(*sel_point))) {
4303 al->erase ((*sel_point)->model ());
4307 /* Thaw the lists and add undo records for them */
4308 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
4309 boost::shared_ptr<AutomationList> al = i->first;
4311 _session->add_command (new MementoCommand<AutomationList> (*al.get(), i->second.state, &(al->get_state ())));
4316 /** Cut, copy or clear selected automation points.
4317 * @param op Operation (Cut, Copy or Clear)
4320 Editor::cut_copy_midi (CutCopyOp op)
4322 Evoral::Beats earliest = Evoral::Beats::max();
4323 for (MidiRegionSelection::iterator i = selection->midi_regions.begin(); i != selection->midi_regions.end(); ++i) {
4324 MidiRegionView* mrv = dynamic_cast<MidiRegionView*>(*i);
4326 if (!mrv->selection().empty()) {
4327 earliest = std::min(earliest, (*mrv->selection().begin())->note()->time());
4329 mrv->cut_copy_clear (op);
4331 /* XXX: not ideal, as there may be more than one track involved in the selection */
4332 _last_cut_copy_source_track = &mrv->get_time_axis_view();
4336 if (!selection->points.empty()) {
4337 cut_copy_points (op, earliest, true);
4338 if (op == Cut || op == Delete) {
4339 selection->clear_points ();
4344 struct lt_playlist {
4345 bool operator () (const PlaylistState& a, const PlaylistState& b) {
4346 return a.playlist < b.playlist;
4350 struct PlaylistMapping {
4352 boost::shared_ptr<Playlist> pl;
4354 PlaylistMapping (TimeAxisView* tvp) : tv (tvp) {}
4357 /** Remove `clicked_regionview' */
4359 Editor::remove_clicked_region ()
4361 if (clicked_routeview == 0 || clicked_regionview == 0) {
4365 begin_reversible_command (_("remove region"));
4367 boost::shared_ptr<Playlist> playlist = clicked_routeview->playlist();
4369 playlist->clear_changes ();
4370 playlist->clear_owned_changes ();
4371 playlist->remove_region (clicked_regionview->region());
4372 if (Config->get_edit_mode() == Ripple)
4373 playlist->ripple (clicked_regionview->region()->position(), -clicked_regionview->region()->length(), boost::shared_ptr<Region>());
4375 /* We might have removed regions, which alters other regions' layering_index,
4376 so we need to do a recursive diff here.
4378 vector<Command*> cmds;
4379 playlist->rdiff (cmds);
4380 _session->add_commands (cmds);
4382 _session->add_command(new StatefulDiffCommand (playlist));
4383 commit_reversible_command ();
4387 /** Remove the selected regions */
4389 Editor::remove_selected_regions ()
4391 RegionSelection rs = get_regions_from_selection_and_entered ();
4393 if (!_session || rs.empty()) {
4397 list<boost::shared_ptr<Region> > regions_to_remove;
4399 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
4400 // we can't just remove the region(s) in this loop because
4401 // this removes them from the RegionSelection, and they thus
4402 // disappear from underneath the iterator, and the ++i above
4403 // SEGVs in a puzzling fashion.
4405 // so, first iterate over the regions to be removed from rs and
4406 // add them to the regions_to_remove list, and then
4407 // iterate over the list to actually remove them.
4409 regions_to_remove.push_back ((*i)->region());
4412 vector<boost::shared_ptr<Playlist> > playlists;
4414 for (list<boost::shared_ptr<Region> >::iterator rl = regions_to_remove.begin(); rl != regions_to_remove.end(); ++rl) {
4416 boost::shared_ptr<Playlist> playlist = (*rl)->playlist();
4419 // is this check necessary?
4423 /* get_regions_from_selection_and_entered() guarantees that
4424 the playlists involved are unique, so there is no need
4428 playlists.push_back (playlist);
4430 playlist->clear_changes ();
4431 playlist->clear_owned_changes ();
4432 playlist->freeze ();
4433 playlist->remove_region (*rl);
4434 if (Config->get_edit_mode() == Ripple)
4435 playlist->ripple ((*rl)->position(), -(*rl)->length(), boost::shared_ptr<Region>());
4439 vector<boost::shared_ptr<Playlist> >::iterator pl;
4440 bool in_command = false;
4442 for (pl = playlists.begin(); pl != playlists.end(); ++pl) {
4445 /* We might have removed regions, which alters other regions' layering_index,
4446 so we need to do a recursive diff here.
4450 begin_reversible_command (_("remove region"));
4453 vector<Command*> cmds;
4454 (*pl)->rdiff (cmds);
4455 _session->add_commands (cmds);
4457 _session->add_command(new StatefulDiffCommand (*pl));
4461 commit_reversible_command ();
4465 /** Cut, copy or clear selected regions.
4466 * @param op Operation (Cut, Copy or Clear)
4469 Editor::cut_copy_regions (CutCopyOp op, RegionSelection& rs)
4471 /* we can't use a std::map here because the ordering is important, and we can't trivially sort
4472 a map when we want ordered access to both elements. i think.
4475 vector<PlaylistMapping> pmap;
4477 framepos_t first_position = max_framepos;
4479 typedef set<boost::shared_ptr<Playlist> > FreezeList;
4480 FreezeList freezelist;
4482 /* get ordering correct before we cut/copy */
4484 rs.sort_by_position_and_track ();
4486 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
4488 first_position = min ((framepos_t) (*x)->region()->position(), first_position);
4490 if (op == Cut || op == Clear || op == Delete) {
4491 boost::shared_ptr<Playlist> pl = (*x)->region()->playlist();
4494 FreezeList::iterator fl;
4496 // only take state if this is a new playlist.
4497 for (fl = freezelist.begin(); fl != freezelist.end(); ++fl) {
4503 if (fl == freezelist.end()) {
4504 pl->clear_changes();
4505 pl->clear_owned_changes ();
4507 freezelist.insert (pl);
4512 TimeAxisView* tv = &(*x)->get_time_axis_view();
4513 vector<PlaylistMapping>::iterator z;
4515 for (z = pmap.begin(); z != pmap.end(); ++z) {
4516 if ((*z).tv == tv) {
4521 if (z == pmap.end()) {
4522 pmap.push_back (PlaylistMapping (tv));
4526 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ) {
4528 boost::shared_ptr<Playlist> pl = (*x)->region()->playlist();
4531 /* region not yet associated with a playlist (e.g. unfinished
4538 TimeAxisView& tv = (*x)->get_time_axis_view();
4539 boost::shared_ptr<Playlist> npl;
4540 RegionSelection::iterator tmp;
4547 vector<PlaylistMapping>::iterator z;
4549 for (z = pmap.begin(); z != pmap.end(); ++z) {
4550 if ((*z).tv == &tv) {
4555 assert (z != pmap.end());
4558 npl = PlaylistFactory::create (pl->data_type(), *_session, "cutlist", true);
4566 boost::shared_ptr<Region> r = (*x)->region();
4567 boost::shared_ptr<Region> _xx;
4573 pl->remove_region (r);
4574 if (Config->get_edit_mode() == Ripple)
4575 pl->ripple (r->position(), -r->length(), boost::shared_ptr<Region>());
4579 _xx = RegionFactory::create (r);
4580 npl->add_region (_xx, r->position() - first_position);
4581 pl->remove_region (r);
4582 if (Config->get_edit_mode() == Ripple)
4583 pl->ripple (r->position(), -r->length(), boost::shared_ptr<Region>());
4587 /* copy region before adding, so we're not putting same object into two different playlists */
4588 npl->add_region (RegionFactory::create (r), r->position() - first_position);
4592 pl->remove_region (r);
4593 if (Config->get_edit_mode() == Ripple)
4594 pl->ripple (r->position(), -r->length(), boost::shared_ptr<Region>());
4603 list<boost::shared_ptr<Playlist> > foo;
4605 /* the pmap is in the same order as the tracks in which selected regions occurred */
4607 for (vector<PlaylistMapping>::iterator i = pmap.begin(); i != pmap.end(); ++i) {
4610 foo.push_back ((*i).pl);
4615 cut_buffer->set (foo);
4619 _last_cut_copy_source_track = 0;
4621 _last_cut_copy_source_track = pmap.front().tv;
4625 for (FreezeList::iterator pl = freezelist.begin(); pl != freezelist.end(); ++pl) {
4628 /* We might have removed regions, which alters other regions' layering_index,
4629 so we need to do a recursive diff here.
4631 vector<Command*> cmds;
4632 (*pl)->rdiff (cmds);
4633 _session->add_commands (cmds);
4635 _session->add_command (new StatefulDiffCommand (*pl));
4640 Editor::cut_copy_ranges (CutCopyOp op)
4642 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4644 /* Sort the track selection now, so that it if is used, the playlists
4645 selected by the calls below to cut_copy_clear are in the order that
4646 their tracks appear in the editor. This makes things like paste
4647 of ranges work properly.
4650 sort_track_selection (ts);
4653 if (!entered_track) {
4656 ts.push_back (entered_track);
4659 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4660 (*i)->cut_copy_clear (*selection, op);
4665 Editor::paste (float times, bool from_context)
4667 DEBUG_TRACE (DEBUG::CutNPaste, "paste to preferred edit pos\n");
4669 paste_internal (get_preferred_edit_position (EDIT_IGNORE_NONE, from_context), times, get_grid_music_divisions (0));
4673 Editor::mouse_paste ()
4678 if (!mouse_frame (where, ignored)) {
4683 paste_internal (where, 1, get_grid_music_divisions (0));
4687 Editor::paste_internal (framepos_t position, float times, const int32_t sub_num)
4689 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("apparent paste position is %1\n", position));
4691 if (cut_buffer->empty(internal_editing())) {
4695 if (position == max_framepos) {
4696 position = get_preferred_edit_position();
4697 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("preferred edit position is %1\n", position));
4700 if (position == last_paste_pos) {
4701 /* repeated paste in the same position */
4704 /* paste in new location, reset repeated paste state */
4706 last_paste_pos = position;
4709 /* get everything in the correct order */
4712 if (!selection->tracks.empty()) {
4713 /* If there is a track selection, paste into exactly those tracks and
4714 only those tracks. This allows the user to be explicit and override
4715 the below "do the reasonable thing" logic. */
4716 ts = selection->tracks.filter_to_unique_playlists ();
4717 sort_track_selection (ts);
4719 /* Figure out which track to base the paste at. */
4720 TimeAxisView* base_track = NULL;
4721 if (_edit_point == Editing::EditAtMouse && entered_track) {
4722 /* With the mouse edit point, paste onto the track under the mouse. */
4723 base_track = entered_track;
4724 } else if (_edit_point == Editing::EditAtMouse && entered_regionview) {
4725 /* With the mouse edit point, paste onto the track of the region under the mouse. */
4726 base_track = &entered_regionview->get_time_axis_view();
4727 } else if (_last_cut_copy_source_track) {
4728 /* Paste to the track that the cut/copy came from (see mantis #333). */
4729 base_track = _last_cut_copy_source_track;
4731 /* This is "impossible" since we've copied... well, do nothing. */
4735 /* Walk up to parent if necessary, so base track is a route. */
4736 while (base_track->get_parent()) {
4737 base_track = base_track->get_parent();
4740 /* Add base track and all tracks below it. The paste logic will select
4741 the appropriate object types from the cut buffer in relative order. */
4742 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4743 if ((*i)->order() >= base_track->order()) {
4748 /* Sort tracks so the nth track of type T will pick the nth object of type T. */
4749 sort_track_selection (ts);
4751 /* Add automation children of each track in order, for pasting several lines. */
4752 for (TrackViewList::iterator i = ts.begin(); i != ts.end();) {
4753 /* Add any automation children for pasting several lines */
4754 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*i++);
4759 typedef RouteTimeAxisView::AutomationTracks ATracks;
4760 const ATracks& atracks = rtv->automation_tracks();
4761 for (ATracks::const_iterator a = atracks.begin(); a != atracks.end(); ++a) {
4762 i = ts.insert(i, a->second.get());
4767 /* We now have a list of trackviews starting at base_track, including
4768 automation children, in the order shown in the editor, e.g. R1,
4769 R1.A1, R1.A2, R2, R2.A1, ... */
4772 begin_reversible_command (Operations::paste);
4774 if (ts.size() == 1 && cut_buffer->lines.size() == 1 &&
4775 dynamic_cast<AutomationTimeAxisView*>(ts.front())) {
4776 /* Only one line copied, and one automation track selected. Do a
4777 "greedy" paste from one automation type to another. */
4779 PasteContext ctx(paste_count, times, ItemCounts(), true);
4780 ts.front()->paste (position, *cut_buffer, ctx, sub_num);
4784 /* Paste into tracks */
4786 PasteContext ctx(paste_count, times, ItemCounts(), false);
4787 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4788 (*i)->paste (position, *cut_buffer, ctx, sub_num);
4792 commit_reversible_command ();
4796 Editor::duplicate_regions (float times)
4798 RegionSelection rs (get_regions_from_selection_and_entered());
4799 duplicate_some_regions (rs, times);
4803 Editor::duplicate_some_regions (RegionSelection& regions, float times)
4805 if (regions.empty ()) {
4809 boost::shared_ptr<Playlist> playlist;
4810 RegionSelection sel = regions; // clear (below) may clear the argument list if its the current region selection
4811 RegionSelection foo;
4813 framepos_t const start_frame = regions.start ();
4814 framepos_t const end_frame = regions.end_frame ();
4815 framecnt_t const gap = end_frame - start_frame + 1;
4817 begin_reversible_command (Operations::duplicate_region);
4819 selection->clear_regions ();
4821 for (RegionSelection::iterator i = sel.begin(); i != sel.end(); ++i) {
4823 boost::shared_ptr<Region> r ((*i)->region());
4825 TimeAxisView& tv = (*i)->get_time_axis_view();
4826 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (&tv);
4827 latest_regionviews.clear ();
4828 sigc::connection c = rtv->view()->RegionViewAdded.connect (sigc::mem_fun(*this, &Editor::collect_new_region_view));
4830 framepos_t const position = end_frame + (r->first_frame() - start_frame + 1);
4831 playlist = (*i)->region()->playlist();
4832 playlist->clear_changes ();
4833 playlist->duplicate (r, position, gap, times);
4834 _session->add_command(new StatefulDiffCommand (playlist));
4838 foo.insert (foo.end(), latest_regionviews.begin(), latest_regionviews.end());
4842 selection->set (foo);
4845 commit_reversible_command ();
4849 Editor::duplicate_selection (float times)
4851 if (selection->time.empty() || selection->tracks.empty()) {
4855 boost::shared_ptr<Playlist> playlist;
4857 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4859 bool in_command = false;
4861 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4862 if ((playlist = (*i)->playlist()) == 0) {
4865 playlist->clear_changes ();
4867 if (clicked_selection) {
4868 playlist->duplicate_range (selection->time[clicked_selection], times);
4870 playlist->duplicate_ranges (selection->time, times);
4874 begin_reversible_command (_("duplicate range selection"));
4877 _session->add_command (new StatefulDiffCommand (playlist));
4882 if (times == 1.0f) {
4883 // now "move" range selection to after the current range selection
4884 framecnt_t distance = 0;
4886 if (clicked_selection) {
4888 selection->time[clicked_selection].end - selection->time[clicked_selection].start;
4890 distance = selection->time.end_frame () - selection->time.start ();
4893 selection->move_time (distance);
4895 commit_reversible_command ();
4899 /** Reset all selected points to the relevant default value */
4901 Editor::reset_point_selection ()
4903 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
4904 ARDOUR::AutomationList::iterator j = (*i)->model ();
4905 (*j)->value = (*i)->line().the_list()->default_value ();
4910 Editor::center_playhead ()
4912 float const page = _visible_canvas_width * samples_per_pixel;
4913 center_screen_internal (playhead_cursor->current_frame (), page);
4917 Editor::center_edit_point ()
4919 float const page = _visible_canvas_width * samples_per_pixel;
4920 center_screen_internal (get_preferred_edit_position(), page);
4923 /** Caller must begin and commit a reversible command */
4925 Editor::clear_playlist (boost::shared_ptr<Playlist> playlist)
4927 playlist->clear_changes ();
4929 _session->add_command (new StatefulDiffCommand (playlist));
4933 Editor::nudge_track (bool use_edit, bool forwards)
4935 boost::shared_ptr<Playlist> playlist;
4936 framepos_t distance;
4937 framepos_t next_distance;
4941 start = get_preferred_edit_position();
4946 if ((distance = get_nudge_distance (start, next_distance)) == 0) {
4950 if (selection->tracks.empty()) {
4954 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4955 bool in_command = false;
4957 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4959 if ((playlist = (*i)->playlist()) == 0) {
4963 playlist->clear_changes ();
4964 playlist->clear_owned_changes ();
4966 playlist->nudge_after (start, distance, forwards);
4969 begin_reversible_command (_("nudge track"));
4972 vector<Command*> cmds;
4974 playlist->rdiff (cmds);
4975 _session->add_commands (cmds);
4977 _session->add_command (new StatefulDiffCommand (playlist));
4981 commit_reversible_command ();
4986 Editor::remove_last_capture ()
4988 vector<string> choices;
4995 if (Config->get_verify_remove_last_capture()) {
4996 prompt = _("Do you really want to destroy the last capture?"
4997 "\n(This is destructive and cannot be undone)");
4999 choices.push_back (_("No, do nothing."));
5000 choices.push_back (_("Yes, destroy it."));
5002 Gtkmm2ext::Choice prompter (_("Destroy last capture"), prompt, choices);
5004 if (prompter.run () == 1) {
5005 _session->remove_last_capture ();
5006 _regions->redisplay ();
5010 _session->remove_last_capture();
5011 _regions->redisplay ();
5016 Editor::normalize_region ()
5022 RegionSelection rs = get_regions_from_selection_and_entered ();
5028 NormalizeDialog dialog (rs.size() > 1);
5030 if (dialog.run () != RESPONSE_ACCEPT) {
5034 CursorContext::Handle cursor_ctx = CursorContext::create(*this, _cursors->wait);
5037 /* XXX: should really only count audio regions here */
5038 int const regions = rs.size ();
5040 /* Make a list of the selected audio regions' maximum amplitudes, and also
5041 obtain the maximum amplitude of them all.
5043 list<double> max_amps;
5044 list<double> rms_vals;
5047 bool use_rms = dialog.constrain_rms ();
5049 for (RegionSelection::const_iterator i = rs.begin(); i != rs.end(); ++i) {
5050 AudioRegionView const * arv = dynamic_cast<AudioRegionView const *> (*i);
5054 dialog.descend (1.0 / regions);
5055 double const a = arv->audio_region()->maximum_amplitude (&dialog);
5057 double r = arv->audio_region()->rms (&dialog);
5058 max_rms = max (max_rms, r);
5059 rms_vals.push_back (r);
5063 /* the user cancelled the operation */
5067 max_amps.push_back (a);
5068 max_amp = max (max_amp, a);
5072 list<double>::const_iterator a = max_amps.begin ();
5073 list<double>::const_iterator l = rms_vals.begin ();
5074 bool in_command = false;
5076 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
5077 AudioRegionView* const arv = dynamic_cast<AudioRegionView*> (*r);
5082 arv->region()->clear_changes ();
5084 double amp = dialog.normalize_individually() ? *a : max_amp;
5085 double target = dialog.target_peak (); // dB
5088 double const amp_rms = dialog.normalize_individually() ? *l : max_rms;
5089 const double t_rms = dialog.target_rms ();
5090 const gain_t c_peak = dB_to_coefficient (target);
5091 const gain_t c_rms = dB_to_coefficient (t_rms);
5092 if ((amp_rms / c_rms) > (amp / c_peak)) {
5098 arv->audio_region()->normalize (amp, target);
5101 begin_reversible_command (_("normalize"));
5104 _session->add_command (new StatefulDiffCommand (arv->region()));
5111 commit_reversible_command ();
5117 Editor::reset_region_scale_amplitude ()
5123 RegionSelection rs = get_regions_from_selection_and_entered ();
5129 bool in_command = false;
5131 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
5132 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
5135 arv->region()->clear_changes ();
5136 arv->audio_region()->set_scale_amplitude (1.0f);
5139 begin_reversible_command ("reset gain");
5142 _session->add_command (new StatefulDiffCommand (arv->region()));
5146 commit_reversible_command ();
5151 Editor::adjust_region_gain (bool up)
5153 RegionSelection rs = get_regions_from_selection_and_entered ();
5155 if (!_session || rs.empty()) {
5159 bool in_command = false;
5161 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
5162 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
5167 arv->region()->clear_changes ();
5169 double dB = accurate_coefficient_to_dB (arv->audio_region()->scale_amplitude ());
5177 arv->audio_region()->set_scale_amplitude (dB_to_coefficient (dB));
5180 begin_reversible_command ("adjust region gain");
5183 _session->add_command (new StatefulDiffCommand (arv->region()));
5187 commit_reversible_command ();
5193 Editor::reverse_region ()
5199 Reverse rev (*_session);
5200 apply_filter (rev, _("reverse regions"));
5204 Editor::strip_region_silence ()
5210 RegionSelection rs = get_regions_from_selection_and_entered ();
5216 std::list<RegionView*> audio_only;
5218 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5219 AudioRegionView* const arv = dynamic_cast<AudioRegionView*> (*i);
5221 audio_only.push_back (arv);
5225 assert (!audio_only.empty());
5227 StripSilenceDialog d (_session, audio_only);
5228 int const r = d.run ();
5232 if (r == Gtk::RESPONSE_OK) {
5233 ARDOUR::AudioIntervalMap silences;
5234 d.silences (silences);
5235 StripSilence s (*_session, silences, d.fade_length());
5237 apply_filter (s, _("strip silence"), &d);
5242 Editor::apply_midi_note_edit_op_to_region (MidiOperator& op, MidiRegionView& mrv)
5244 Evoral::Sequence<Evoral::Beats>::Notes selected;
5245 mrv.selection_as_notelist (selected, true);
5247 vector<Evoral::Sequence<Evoral::Beats>::Notes> v;
5248 v.push_back (selected);
5250 Evoral::Beats pos_beats = Evoral::Beats (mrv.midi_region()->beat()) - mrv.midi_region()->start_beats();
5252 return op (mrv.midi_region()->model(), pos_beats, v);
5256 Editor::apply_midi_note_edit_op (MidiOperator& op, const RegionSelection& rs)
5262 bool in_command = false;
5264 for (RegionSelection::const_iterator r = rs.begin(); r != rs.end(); ) {
5265 RegionSelection::const_iterator tmp = r;
5268 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*r);
5271 Command* cmd = apply_midi_note_edit_op_to_region (op, *mrv);
5274 begin_reversible_command (op.name ());
5278 _session->add_command (cmd);
5286 commit_reversible_command ();
5291 Editor::fork_region ()
5293 RegionSelection rs = get_regions_from_selection_and_entered ();
5299 CursorContext::Handle cursor_ctx = CursorContext::create(*this, _cursors->wait);
5300 bool in_command = false;
5304 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
5305 RegionSelection::iterator tmp = r;
5308 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*>(*r);
5312 boost::shared_ptr<Playlist> playlist = mrv->region()->playlist();
5313 boost::shared_ptr<MidiSource> new_source = _session->create_midi_source_by_stealing_name (mrv->midi_view()->track());
5314 boost::shared_ptr<MidiRegion> newregion = mrv->midi_region()->clone (new_source);
5317 begin_reversible_command (_("Fork Region(s)"));
5320 playlist->clear_changes ();
5321 playlist->replace_region (mrv->region(), newregion, mrv->region()->position());
5322 _session->add_command(new StatefulDiffCommand (playlist));
5324 error << string_compose (_("Could not unlink %1"), mrv->region()->name()) << endmsg;
5332 commit_reversible_command ();
5337 Editor::quantize_region ()
5340 quantize_regions(get_regions_from_selection_and_entered ());
5345 Editor::quantize_regions (const RegionSelection& rs)
5347 if (rs.n_midi_regions() == 0) {
5351 if (!quantize_dialog) {
5352 quantize_dialog = new QuantizeDialog (*this);
5355 if (quantize_dialog->is_mapped()) {
5356 /* in progress already */
5360 quantize_dialog->present ();
5361 const int r = quantize_dialog->run ();
5362 quantize_dialog->hide ();
5364 if (r == Gtk::RESPONSE_OK) {
5365 Quantize quant (quantize_dialog->snap_start(),
5366 quantize_dialog->snap_end(),
5367 quantize_dialog->start_grid_size(),
5368 quantize_dialog->end_grid_size(),
5369 quantize_dialog->strength(),
5370 quantize_dialog->swing(),
5371 quantize_dialog->threshold());
5373 apply_midi_note_edit_op (quant, rs);
5378 Editor::legatize_region (bool shrink_only)
5381 legatize_regions(get_regions_from_selection_and_entered (), shrink_only);
5386 Editor::legatize_regions (const RegionSelection& rs, bool shrink_only)
5388 if (rs.n_midi_regions() == 0) {
5392 Legatize legatize(shrink_only);
5393 apply_midi_note_edit_op (legatize, rs);
5397 Editor::transform_region ()
5400 transform_regions(get_regions_from_selection_and_entered ());
5405 Editor::transform_regions (const RegionSelection& rs)
5407 if (rs.n_midi_regions() == 0) {
5414 const int r = td.run();
5417 if (r == Gtk::RESPONSE_OK) {
5418 Transform transform(td.get());
5419 apply_midi_note_edit_op(transform, rs);
5424 Editor::transpose_region ()
5427 transpose_regions(get_regions_from_selection_and_entered ());
5432 Editor::transpose_regions (const RegionSelection& rs)
5434 if (rs.n_midi_regions() == 0) {
5439 int const r = d.run ();
5441 if (r == RESPONSE_ACCEPT) {
5442 Transpose transpose(d.semitones ());
5443 apply_midi_note_edit_op (transpose, rs);
5448 Editor::insert_patch_change (bool from_context)
5450 RegionSelection rs = get_regions_from_selection_and_entered ();
5456 const framepos_t p = get_preferred_edit_position (EDIT_IGNORE_NONE, from_context);
5458 /* XXX: bit of a hack; use the MIDNAM from the first selected region;
5459 there may be more than one, but the PatchChangeDialog can only offer
5460 one set of patch menus.
5462 MidiRegionView* first = dynamic_cast<MidiRegionView*> (rs.front ());
5464 Evoral::PatchChange<Evoral::Beats> empty (Evoral::Beats(), 0, 0, 0);
5465 PatchChangeDialog d (0, _session, empty, first->instrument_info(), Gtk::Stock::ADD);
5467 if (d.run() == RESPONSE_CANCEL) {
5471 for (RegionSelection::iterator i = rs.begin (); i != rs.end(); ++i) {
5472 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*i);
5474 if (p >= mrv->region()->first_frame() && p <= mrv->region()->last_frame()) {
5475 mrv->add_patch_change (p - mrv->region()->position(), d.patch ());
5482 Editor::apply_filter (Filter& filter, string command, ProgressReporter* progress)
5484 RegionSelection rs = get_regions_from_selection_and_entered ();
5490 CursorContext::Handle cursor_ctx = CursorContext::create(*this, _cursors->wait);
5491 bool in_command = false;
5496 int const N = rs.size ();
5498 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
5499 RegionSelection::iterator tmp = r;
5502 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
5504 boost::shared_ptr<Playlist> playlist = arv->region()->playlist();
5507 progress->descend (1.0 / N);
5510 if (arv->audio_region()->apply (filter, progress) == 0) {
5512 playlist->clear_changes ();
5513 playlist->clear_owned_changes ();
5516 begin_reversible_command (command);
5520 if (filter.results.empty ()) {
5522 /* no regions returned; remove the old one */
5523 playlist->remove_region (arv->region ());
5527 std::vector<boost::shared_ptr<Region> >::iterator res = filter.results.begin ();
5529 /* first region replaces the old one */
5530 playlist->replace_region (arv->region(), *res, (*res)->position());
5534 while (res != filter.results.end()) {
5535 playlist->add_region (*res, (*res)->position());
5541 /* We might have removed regions, which alters other regions' layering_index,
5542 so we need to do a recursive diff here.
5544 vector<Command*> cmds;
5545 playlist->rdiff (cmds);
5546 _session->add_commands (cmds);
5548 _session->add_command(new StatefulDiffCommand (playlist));
5552 progress->ascend ();
5561 commit_reversible_command ();
5566 Editor::external_edit_region ()
5572 Editor::reset_region_gain_envelopes ()
5574 RegionSelection rs = get_regions_from_selection_and_entered ();
5576 if (!_session || rs.empty()) {
5580 bool in_command = false;
5582 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5583 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
5585 boost::shared_ptr<AutomationList> alist (arv->audio_region()->envelope());
5586 XMLNode& before (alist->get_state());
5588 arv->audio_region()->set_default_envelope ();
5591 begin_reversible_command (_("reset region gain"));
5594 _session->add_command (new MementoCommand<AutomationList>(*arv->audio_region()->envelope().get(), &before, &alist->get_state()));
5599 commit_reversible_command ();
5604 Editor::set_region_gain_visibility (RegionView* rv)
5606 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (rv);
5608 arv->update_envelope_visibility();
5613 Editor::set_gain_envelope_visibility ()
5619 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5620 AudioTimeAxisView* v = dynamic_cast<AudioTimeAxisView*>(*i);
5622 v->audio_view()->foreach_regionview (sigc::mem_fun (this, &Editor::set_region_gain_visibility));
5628 Editor::toggle_gain_envelope_active ()
5630 if (_ignore_region_action) {
5634 RegionSelection rs = get_regions_from_selection_and_entered ();
5636 if (!_session || rs.empty()) {
5640 bool in_command = false;
5642 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5643 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
5645 arv->region()->clear_changes ();
5646 arv->audio_region()->set_envelope_active (!arv->audio_region()->envelope_active());
5649 begin_reversible_command (_("region gain envelope active"));
5652 _session->add_command (new StatefulDiffCommand (arv->region()));
5657 commit_reversible_command ();
5662 Editor::toggle_region_lock ()
5664 if (_ignore_region_action) {
5668 RegionSelection rs = get_regions_from_selection_and_entered ();
5670 if (!_session || rs.empty()) {
5674 begin_reversible_command (_("toggle region lock"));
5676 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5677 (*i)->region()->clear_changes ();
5678 (*i)->region()->set_locked (!(*i)->region()->locked());
5679 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5682 commit_reversible_command ();
5686 Editor::toggle_region_video_lock ()
5688 if (_ignore_region_action) {
5692 RegionSelection rs = get_regions_from_selection_and_entered ();
5694 if (!_session || rs.empty()) {
5698 begin_reversible_command (_("Toggle Video Lock"));
5700 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5701 (*i)->region()->clear_changes ();
5702 (*i)->region()->set_video_locked (!(*i)->region()->video_locked());
5703 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5706 commit_reversible_command ();
5710 Editor::toggle_region_lock_style ()
5712 if (_ignore_region_action) {
5716 RegionSelection rs = get_regions_from_selection_and_entered ();
5718 if (!_session || rs.empty()) {
5722 begin_reversible_command (_("region lock style"));
5724 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5725 (*i)->region()->clear_changes ();
5726 PositionLockStyle const ns = (*i)->region()->position_lock_style() == AudioTime ? MusicTime : AudioTime;
5727 (*i)->region()->set_position_lock_style (ns);
5728 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5731 commit_reversible_command ();
5735 Editor::toggle_opaque_region ()
5737 if (_ignore_region_action) {
5741 RegionSelection rs = get_regions_from_selection_and_entered ();
5743 if (!_session || rs.empty()) {
5747 begin_reversible_command (_("change region opacity"));
5749 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5750 (*i)->region()->clear_changes ();
5751 (*i)->region()->set_opaque (!(*i)->region()->opaque());
5752 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5755 commit_reversible_command ();
5759 Editor::toggle_record_enable ()
5761 bool new_state = false;
5763 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5764 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5767 if (!rtav->is_track())
5771 new_state = !rtav->track()->rec_enable_control()->get_value();
5775 rtav->track()->rec_enable_control()->set_value (new_state, Controllable::UseGroup);
5780 Editor::toggle_solo ()
5782 bool new_state = false;
5784 boost::shared_ptr<ControlList> cl (new ControlList);
5786 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5787 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5794 new_state = !rtav->route()->soloed ();
5798 cl->push_back (rtav->route()->solo_control());
5801 _session->set_controls (cl, new_state ? 1.0 : 0.0, Controllable::UseGroup);
5805 Editor::toggle_mute ()
5807 bool new_state = false;
5809 boost::shared_ptr<RouteList> rl (new RouteList);
5811 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5812 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5819 new_state = !rtav->route()->muted();
5823 rl->push_back (rtav->route());
5826 _session->set_controls (route_list_to_control_list (rl, &Stripable::mute_control), new_state, Controllable::UseGroup);
5830 Editor::toggle_solo_isolate ()
5836 Editor::fade_range ()
5838 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
5840 begin_reversible_command (_("fade range"));
5842 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
5843 (*i)->fade_range (selection->time);
5846 commit_reversible_command ();
5851 Editor::set_fade_length (bool in)
5853 RegionSelection rs = get_regions_from_selection_and_entered ();
5859 /* we need a region to measure the offset from the start */
5861 RegionView* rv = rs.front ();
5863 framepos_t pos = get_preferred_edit_position();
5867 if (pos > rv->region()->last_frame() || pos < rv->region()->first_frame()) {
5868 /* edit point is outside the relevant region */
5873 if (pos <= rv->region()->position()) {
5877 len = pos - rv->region()->position();
5878 cmd = _("set fade in length");
5880 if (pos >= rv->region()->last_frame()) {
5884 len = rv->region()->last_frame() - pos;
5885 cmd = _("set fade out length");
5888 bool in_command = false;
5890 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5891 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5897 boost::shared_ptr<AutomationList> alist;
5899 alist = tmp->audio_region()->fade_in();
5901 alist = tmp->audio_region()->fade_out();
5904 XMLNode &before = alist->get_state();
5907 tmp->audio_region()->set_fade_in_length (len);
5908 tmp->audio_region()->set_fade_in_active (true);
5910 tmp->audio_region()->set_fade_out_length (len);
5911 tmp->audio_region()->set_fade_out_active (true);
5915 begin_reversible_command (cmd);
5918 XMLNode &after = alist->get_state();
5919 _session->add_command(new MementoCommand<AutomationList>(*alist, &before, &after));
5923 commit_reversible_command ();
5928 Editor::set_fade_in_shape (FadeShape shape)
5930 RegionSelection rs = get_regions_from_selection_and_entered ();
5935 bool in_command = false;
5937 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5938 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5944 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_in();
5945 XMLNode &before = alist->get_state();
5947 tmp->audio_region()->set_fade_in_shape (shape);
5950 begin_reversible_command (_("set fade in shape"));
5953 XMLNode &after = alist->get_state();
5954 _session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
5958 commit_reversible_command ();
5963 Editor::set_fade_out_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_out();
5980 XMLNode &before = alist->get_state();
5982 tmp->audio_region()->set_fade_out_shape (shape);
5985 begin_reversible_command (_("set fade out 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_in_active (bool yn)
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);
6015 boost::shared_ptr<AudioRegion> ar (tmp->audio_region());
6017 ar->clear_changes ();
6018 ar->set_fade_in_active (yn);
6021 begin_reversible_command (_("set fade in active"));
6024 _session->add_command (new StatefulDiffCommand (ar));
6028 commit_reversible_command ();
6033 Editor::set_fade_out_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);
6049 boost::shared_ptr<AudioRegion> ar (tmp->audio_region());
6051 ar->clear_changes ();
6052 ar->set_fade_out_active (yn);
6055 begin_reversible_command (_("set fade out active"));
6058 _session->add_command(new StatefulDiffCommand (ar));
6062 commit_reversible_command ();
6067 Editor::toggle_region_fades (int dir)
6069 if (_ignore_region_action) {
6073 boost::shared_ptr<AudioRegion> ar;
6076 RegionSelection rs = get_regions_from_selection_and_entered ();
6082 RegionSelection::iterator i;
6083 for (i = rs.begin(); i != rs.end(); ++i) {
6084 if ((ar = boost::dynamic_pointer_cast<AudioRegion>((*i)->region())) != 0) {
6086 yn = ar->fade_out_active ();
6088 yn = ar->fade_in_active ();
6094 if (i == rs.end()) {
6098 /* XXX should this undo-able? */
6099 bool in_command = false;
6101 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
6102 if ((ar = boost::dynamic_pointer_cast<AudioRegion>((*i)->region())) == 0) {
6105 ar->clear_changes ();
6107 if (dir == 1 || dir == 0) {
6108 ar->set_fade_in_active (!yn);
6111 if (dir == -1 || dir == 0) {
6112 ar->set_fade_out_active (!yn);
6115 begin_reversible_command (_("toggle fade active"));
6118 _session->add_command(new StatefulDiffCommand (ar));
6122 commit_reversible_command ();
6127 /** Update region fade visibility after its configuration has been changed */
6129 Editor::update_region_fade_visibility ()
6131 bool _fade_visibility = _session->config.get_show_region_fades ();
6133 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
6134 AudioTimeAxisView* v = dynamic_cast<AudioTimeAxisView*>(*i);
6136 if (_fade_visibility) {
6137 v->audio_view()->show_all_fades ();
6139 v->audio_view()->hide_all_fades ();
6146 Editor::set_edit_point ()
6151 if (!mouse_frame (where, ignored)) {
6157 if (selection->markers.empty()) {
6159 mouse_add_new_marker (where);
6164 Location* loc = find_location_from_marker (selection->markers.front(), ignored);
6167 loc->move_to (where);
6173 Editor::set_playhead_cursor ()
6175 if (entered_marker) {
6176 _session->request_locate (entered_marker->position(), _session->transport_rolling());
6181 if (!mouse_frame (where, ignored)) {
6188 _session->request_locate (where, _session->transport_rolling());
6192 //not sure what this was for; remove it for now.
6193 // if (UIConfiguration::instance().get_follow_edits() && (!_session || !_session->config.get_external_sync())) {
6194 // cancel_time_selection();
6200 Editor::split_region ()
6202 if (_drags->active ()) {
6206 //if a range is selected, separate it
6207 if ( !selection->time.empty()) {
6208 separate_regions_between (selection->time);
6212 //if no range was selected, try to find some regions to split
6213 if (current_mouse_mode() == MouseObject) { //don't try this for Internal Edit, Stretch, Draw, etc.
6215 RegionSelection rs = get_regions_from_selection_and_edit_point ();
6217 framepos_t where = get_preferred_edit_position ();
6223 if (snap_musical()) {
6224 split_regions_at (where, rs, get_grid_music_divisions (0));
6226 split_regions_at (where, rs, 0);
6232 Editor::select_next_route()
6234 if (selection->tracks.empty()) {
6235 selection->set (track_views.front());
6239 TimeAxisView* current = selection->tracks.front();
6243 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
6245 if (*i == current) {
6247 if (i != track_views.end()) {
6250 current = (*(track_views.begin()));
6251 //selection->set (*(track_views.begin()));
6257 rui = dynamic_cast<RouteUI *>(current);
6259 } while (current->hidden() || (rui == NULL) || !rui->route()->active());
6261 selection->set (current);
6263 ensure_time_axis_view_is_visible (*current, false);
6267 Editor::select_prev_route()
6269 if (selection->tracks.empty()) {
6270 selection->set (track_views.front());
6274 TimeAxisView* current = selection->tracks.front();
6278 for (TrackViewList::reverse_iterator i = track_views.rbegin(); i != track_views.rend(); ++i) {
6280 if (*i == current) {
6282 if (i != track_views.rend()) {
6285 current = *(track_views.rbegin());
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::set_loop_from_selection (bool play)
6302 if (_session == 0) {
6306 framepos_t start, end;
6307 if (!get_selection_extents ( start, end))
6310 set_loop_range (start, end, _("set loop range from selection"));
6313 _session->request_play_loop (true, true);
6318 Editor::set_loop_from_region (bool play)
6320 framepos_t start, end;
6321 if (!get_selection_extents ( start, end))
6324 set_loop_range (start, end, _("set loop range from region"));
6327 _session->request_locate (start, true);
6328 _session->request_play_loop (true);
6333 Editor::set_punch_from_selection ()
6335 if (_session == 0) {
6339 framepos_t start, end;
6340 if (!get_selection_extents ( start, end))
6343 set_punch_range (start, end, _("set punch range from selection"));
6347 Editor::set_auto_punch_range ()
6349 // auto punch in/out button from a single button
6350 // If Punch In is unset, set punch range from playhead to end, enable punch in
6351 // If Punch In is set, the next punch sets Punch Out, unless the playhead has been
6352 // rewound beyond the Punch In marker, in which case that marker will be moved back
6353 // to the current playhead position.
6354 // If punch out is set, it clears the punch range and Punch In/Out buttons
6356 if (_session == 0) {
6360 Location* tpl = transport_punch_location();
6361 framepos_t now = playhead_cursor->current_frame();
6362 framepos_t begin = now;
6363 framepos_t end = _session->current_end_frame();
6365 if (!_session->config.get_punch_in()) {
6366 // First Press - set punch in and create range from here to eternity
6367 set_punch_range (begin, end, _("Auto Punch In"));
6368 _session->config.set_punch_in(true);
6369 } else if (tpl && !_session->config.get_punch_out()) {
6370 // Second press - update end range marker and set punch_out
6371 if (now < tpl->start()) {
6372 // playhead has been rewound - move start back and pretend nothing happened
6374 set_punch_range (begin, end, _("Auto Punch In/Out"));
6376 // normal case for 2nd press - set the punch out
6377 end = playhead_cursor->current_frame ();
6378 set_punch_range (tpl->start(), now, _("Auto Punch In/Out"));
6379 _session->config.set_punch_out(true);
6382 if (_session->config.get_punch_out()) {
6383 _session->config.set_punch_out(false);
6386 if (_session->config.get_punch_in()) {
6387 _session->config.set_punch_in(false);
6392 // third press - unset punch in/out and remove range
6393 _session->locations()->remove(tpl);
6400 Editor::set_session_extents_from_selection ()
6402 if (_session == 0) {
6406 framepos_t start, end;
6407 if (!get_selection_extents ( start, end))
6411 if ((loc = _session->locations()->session_range_location()) == 0) {
6412 _session->set_session_extents (start, end); // this will create a new session range; no need for UNDO
6414 XMLNode &before = loc->get_state();
6416 _session->set_session_extents (start, end);
6418 XMLNode &after = loc->get_state();
6420 begin_reversible_command (_("set session start/end from selection"));
6422 _session->add_command (new MementoCommand<Location>(*loc, &before, &after));
6424 commit_reversible_command ();
6427 _session->set_end_is_free (false);
6431 Editor::set_punch_start_from_edit_point ()
6435 framepos_t start = 0;
6436 framepos_t end = max_framepos;
6438 //use the existing punch end, if any
6439 Location* tpl = transport_punch_location();
6444 if ((_edit_point == EditAtPlayhead) && _session->transport_rolling()) {
6445 start = _session->audible_frame();
6447 start = get_preferred_edit_position();
6450 //snap the selection start/end
6453 //if there's not already a sensible selection endpoint, go "forever"
6454 if ( start > end ) {
6458 set_punch_range (start, end, _("set punch start from EP"));
6464 Editor::set_punch_end_from_edit_point ()
6468 framepos_t start = 0;
6469 framepos_t end = max_framepos;
6471 //use the existing punch start, if any
6472 Location* tpl = transport_punch_location();
6474 start = tpl->start();
6477 if ((_edit_point == EditAtPlayhead) && _session->transport_rolling()) {
6478 end = _session->audible_frame();
6480 end = get_preferred_edit_position();
6483 //snap the selection start/end
6486 set_punch_range (start, end, _("set punch end from EP"));
6492 Editor::set_loop_start_from_edit_point ()
6496 framepos_t start = 0;
6497 framepos_t end = max_framepos;
6499 //use the existing loop end, if any
6500 Location* tpl = transport_loop_location();
6505 if ((_edit_point == EditAtPlayhead) && _session->transport_rolling()) {
6506 start = _session->audible_frame();
6508 start = get_preferred_edit_position();
6511 //snap the selection start/end
6514 //if there's not already a sensible selection endpoint, go "forever"
6515 if ( start > end ) {
6519 set_loop_range (start, end, _("set loop start from EP"));
6525 Editor::set_loop_end_from_edit_point ()
6529 framepos_t start = 0;
6530 framepos_t end = max_framepos;
6532 //use the existing loop start, if any
6533 Location* tpl = transport_loop_location();
6535 start = tpl->start();
6538 if ((_edit_point == EditAtPlayhead) && _session->transport_rolling()) {
6539 end = _session->audible_frame();
6541 end = get_preferred_edit_position();
6544 //snap the selection start/end
6547 set_loop_range (start, end, _("set loop end from EP"));
6552 Editor::set_punch_from_region ()
6554 framepos_t start, end;
6555 if (!get_selection_extents ( start, end))
6558 set_punch_range (start, end, _("set punch range from region"));
6562 Editor::pitch_shift_region ()
6564 RegionSelection rs = get_regions_from_selection_and_entered ();
6566 RegionSelection audio_rs;
6567 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
6568 if (dynamic_cast<AudioRegionView*> (*i)) {
6569 audio_rs.push_back (*i);
6573 if (audio_rs.empty()) {
6577 pitch_shift (audio_rs, 1.2);
6581 Editor::set_tempo_from_region ()
6583 RegionSelection rs = get_regions_from_selection_and_entered ();
6585 if (!_session || rs.empty()) {
6589 RegionView* rv = rs.front();
6591 define_one_bar (rv->region()->position(), rv->region()->last_frame() + 1);
6595 Editor::use_range_as_bar ()
6597 framepos_t start, end;
6598 if (get_edit_op_range (start, end)) {
6599 define_one_bar (start, end);
6604 Editor::define_one_bar (framepos_t start, framepos_t end)
6606 framepos_t length = end - start;
6608 const Meter& m (_session->tempo_map().meter_at_frame (start));
6610 /* length = 1 bar */
6612 /* We're going to deliver a constant tempo here,
6613 so we can use frames per beat to determine length.
6614 now we want frames per beat.
6615 we have frames per bar, and beats per bar, so ...
6618 /* XXXX METER MATH */
6620 double frames_per_beat = length / m.divisions_per_bar();
6622 /* beats per minute = */
6624 double beats_per_minute = (_session->frame_rate() * 60.0) / frames_per_beat;
6626 /* now decide whether to:
6628 (a) set global tempo
6629 (b) add a new tempo marker
6633 const TempoSection& t (_session->tempo_map().tempo_section_at_frame (start));
6635 bool do_global = false;
6637 if ((_session->tempo_map().n_tempos() == 1) && (_session->tempo_map().n_meters() == 1)) {
6639 /* only 1 tempo & 1 meter: ask if the user wants to set the tempo
6640 at the start, or create a new marker
6643 vector<string> options;
6644 options.push_back (_("Cancel"));
6645 options.push_back (_("Add new marker"));
6646 options.push_back (_("Set global tempo"));
6649 _("Define one bar"),
6650 _("Do you want to set the global tempo or add a new tempo marker?"),
6654 c.set_default_response (2);
6670 /* more than 1 tempo and/or meter section already, go ahead do the "usual":
6671 if the marker is at the region starter, change it, otherwise add
6676 begin_reversible_command (_("set tempo from region"));
6677 XMLNode& before (_session->tempo_map().get_state());
6680 _session->tempo_map().change_initial_tempo (beats_per_minute, t.note_type());
6681 } else if (t.frame() == start) {
6682 _session->tempo_map().change_existing_tempo_at (start, beats_per_minute, t.note_type());
6684 const Tempo tempo (beats_per_minute, t.note_type());
6685 _session->tempo_map().add_tempo (tempo, 0.0, start, TempoSection::Constant, AudioTime);
6688 XMLNode& after (_session->tempo_map().get_state());
6690 _session->add_command (new MementoCommand<TempoMap>(_session->tempo_map(), &before, &after));
6691 commit_reversible_command ();
6695 Editor::split_region_at_transients ()
6697 AnalysisFeatureList positions;
6699 RegionSelection rs = get_regions_from_selection_and_entered ();
6701 if (!_session || rs.empty()) {
6705 begin_reversible_command (_("split regions"));
6707 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ) {
6709 RegionSelection::iterator tmp;
6714 boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion> ((*i)->region());
6717 ar->transients (positions);
6718 split_region_at_points ((*i)->region(), positions, true);
6725 commit_reversible_command ();
6730 Editor::split_region_at_points (boost::shared_ptr<Region> r, AnalysisFeatureList& positions, bool can_ferret, bool select_new)
6732 bool use_rhythmic_rodent = false;
6734 boost::shared_ptr<Playlist> pl = r->playlist();
6736 list<boost::shared_ptr<Region> > new_regions;
6742 if (positions.empty()) {
6746 if (positions.size() > 20 && can_ferret) {
6747 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);
6748 MessageDialog msg (msgstr,
6751 Gtk::BUTTONS_OK_CANCEL);
6754 msg.add_button (_("Call for the Ferret!"), RESPONSE_APPLY);
6755 msg.set_secondary_text (_("Press OK to continue with this split operation\nor ask the Ferret dialog to tune the analysis"));
6757 msg.set_secondary_text (_("Press OK to continue with this split operation"));
6760 msg.set_title (_("Excessive split?"));
6763 int response = msg.run();
6769 case RESPONSE_APPLY:
6770 use_rhythmic_rodent = true;
6777 if (use_rhythmic_rodent) {
6778 show_rhythm_ferret ();
6782 AnalysisFeatureList::const_iterator x;
6784 pl->clear_changes ();
6785 pl->clear_owned_changes ();
6787 x = positions.begin();
6789 if (x == positions.end()) {
6794 pl->remove_region (r);
6798 framepos_t rstart = r->first_frame ();
6799 framepos_t rend = r->last_frame ();
6801 while (x != positions.end()) {
6803 /* deal with positons that are out of scope of present region bounds */
6804 if (*x <= rstart || *x > rend) {
6809 /* file start = original start + how far we from the initial position ? */
6811 framepos_t file_start = r->start() + pos;
6813 /* length = next position - current position */
6815 framepos_t len = (*x) - pos - rstart;
6817 /* XXX we do we really want to allow even single-sample regions?
6818 * shouldn't we have some kind of lower limit on region size?
6827 if (RegionFactory::region_name (new_name, r->name())) {
6831 /* do NOT announce new regions 1 by one, just wait till they are all done */
6835 plist.add (ARDOUR::Properties::start, file_start);
6836 plist.add (ARDOUR::Properties::length, len);
6837 plist.add (ARDOUR::Properties::name, new_name);
6838 plist.add (ARDOUR::Properties::layer, 0);
6839 // TODO set transients_offset
6841 boost::shared_ptr<Region> nr = RegionFactory::create (r->sources(), plist, false);
6842 /* because we set annouce to false, manually add the new region to the
6845 RegionFactory::map_add (nr);
6847 pl->add_region (nr, rstart + pos);
6850 new_regions.push_front(nr);
6859 RegionFactory::region_name (new_name, r->name());
6861 /* Add the final region */
6864 plist.add (ARDOUR::Properties::start, r->start() + pos);
6865 plist.add (ARDOUR::Properties::length, r->last_frame() - (r->position() + pos) + 1);
6866 plist.add (ARDOUR::Properties::name, new_name);
6867 plist.add (ARDOUR::Properties::layer, 0);
6869 boost::shared_ptr<Region> nr = RegionFactory::create (r->sources(), plist, false);
6870 /* because we set annouce to false, manually add the new region to the
6873 RegionFactory::map_add (nr);
6874 pl->add_region (nr, r->position() + pos);
6877 new_regions.push_front(nr);
6882 /* We might have removed regions, which alters other regions' layering_index,
6883 so we need to do a recursive diff here.
6885 vector<Command*> cmds;
6887 _session->add_commands (cmds);
6889 _session->add_command (new StatefulDiffCommand (pl));
6893 for (list<boost::shared_ptr<Region> >::iterator i = new_regions.begin(); i != new_regions.end(); ++i){
6894 set_selected_regionview_from_region_list ((*i), Selection::Add);
6900 Editor::place_transient()
6906 RegionSelection rs = get_regions_from_selection_and_edit_point ();
6912 framepos_t where = get_preferred_edit_position();
6914 begin_reversible_command (_("place transient"));
6916 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6917 (*r)->region()->add_transient(where);
6920 commit_reversible_command ();
6924 Editor::remove_transient(ArdourCanvas::Item* item)
6930 ArdourCanvas::Line* _line = reinterpret_cast<ArdourCanvas::Line*> (item);
6933 AudioRegionView* _arv = reinterpret_cast<AudioRegionView*> (item->get_data ("regionview"));
6934 _arv->remove_transient (*(float*) _line->get_data ("position"));
6938 Editor::snap_regions_to_grid ()
6940 list <boost::shared_ptr<Playlist > > used_playlists;
6942 RegionSelection rs = get_regions_from_selection_and_entered ();
6944 if (!_session || rs.empty()) {
6948 begin_reversible_command (_("snap regions to grid"));
6950 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6952 boost::shared_ptr<Playlist> pl = (*r)->region()->playlist();
6954 if (!pl->frozen()) {
6955 /* we haven't seen this playlist before */
6957 /* remember used playlists so we can thaw them later */
6958 used_playlists.push_back(pl);
6962 framepos_t start_frame = (*r)->region()->first_frame ();
6963 snap_to (start_frame);
6964 (*r)->region()->set_position (start_frame);
6967 while (used_playlists.size() > 0) {
6968 list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
6970 used_playlists.pop_front();
6973 commit_reversible_command ();
6977 Editor::close_region_gaps ()
6979 list <boost::shared_ptr<Playlist > > used_playlists;
6981 RegionSelection rs = get_regions_from_selection_and_entered ();
6983 if (!_session || rs.empty()) {
6987 Dialog dialog (_("Close Region Gaps"));
6990 table.set_spacings (12);
6991 table.set_border_width (12);
6992 Label* l = manage (left_aligned_label (_("Crossfade length")));
6993 table.attach (*l, 0, 1, 0, 1);
6995 SpinButton spin_crossfade (1, 0);
6996 spin_crossfade.set_range (0, 15);
6997 spin_crossfade.set_increments (1, 1);
6998 spin_crossfade.set_value (5);
6999 table.attach (spin_crossfade, 1, 2, 0, 1);
7001 table.attach (*manage (new Label (_("ms"))), 2, 3, 0, 1);
7003 l = manage (left_aligned_label (_("Pull-back length")));
7004 table.attach (*l, 0, 1, 1, 2);
7006 SpinButton spin_pullback (1, 0);
7007 spin_pullback.set_range (0, 100);
7008 spin_pullback.set_increments (1, 1);
7009 spin_pullback.set_value(30);
7010 table.attach (spin_pullback, 1, 2, 1, 2);
7012 table.attach (*manage (new Label (_("ms"))), 2, 3, 1, 2);
7014 dialog.get_vbox()->pack_start (table);
7015 dialog.add_button (Stock::CANCEL, RESPONSE_CANCEL);
7016 dialog.add_button (_("Ok"), RESPONSE_ACCEPT);
7019 if (dialog.run () == RESPONSE_CANCEL) {
7023 framepos_t crossfade_len = spin_crossfade.get_value();
7024 framepos_t pull_back_frames = spin_pullback.get_value();
7026 crossfade_len = lrintf (crossfade_len * _session->frame_rate()/1000);
7027 pull_back_frames = lrintf (pull_back_frames * _session->frame_rate()/1000);
7029 /* Iterate over the region list and make adjacent regions overlap by crossfade_len_ms */
7031 begin_reversible_command (_("close region gaps"));
7034 boost::shared_ptr<Region> last_region;
7036 rs.sort_by_position_and_track();
7038 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
7040 boost::shared_ptr<Playlist> pl = (*r)->region()->playlist();
7042 if (!pl->frozen()) {
7043 /* we haven't seen this playlist before */
7045 /* remember used playlists so we can thaw them later */
7046 used_playlists.push_back(pl);
7050 framepos_t position = (*r)->region()->position();
7052 if (idx == 0 || position < last_region->position()){
7053 last_region = (*r)->region();
7058 (*r)->region()->trim_front( (position - pull_back_frames));
7059 last_region->trim_end( (position - pull_back_frames + crossfade_len));
7061 last_region = (*r)->region();
7066 while (used_playlists.size() > 0) {
7067 list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
7069 used_playlists.pop_front();
7072 commit_reversible_command ();
7076 Editor::tab_to_transient (bool forward)
7078 AnalysisFeatureList positions;
7080 RegionSelection rs = get_regions_from_selection_and_entered ();
7086 framepos_t pos = _session->audible_frame ();
7088 if (!selection->tracks.empty()) {
7090 /* don't waste time searching for transients in duplicate playlists.
7093 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
7095 for (TrackViewList::iterator t = ts.begin(); t != ts.end(); ++t) {
7097 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*t);
7100 boost::shared_ptr<Track> tr = rtv->track();
7102 boost::shared_ptr<Playlist> pl = tr->playlist ();
7104 framepos_t result = pl->find_next_transient (pos, forward ? 1 : -1);
7107 positions.push_back (result);
7120 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
7121 (*r)->region()->get_transients (positions);
7125 TransientDetector::cleanup_transients (positions, _session->frame_rate(), 3.0);
7128 AnalysisFeatureList::iterator x;
7130 for (x = positions.begin(); x != positions.end(); ++x) {
7136 if (x != positions.end ()) {
7137 _session->request_locate (*x);
7141 AnalysisFeatureList::reverse_iterator x;
7143 for (x = positions.rbegin(); x != positions.rend(); ++x) {
7149 if (x != positions.rend ()) {
7150 _session->request_locate (*x);
7156 Editor::playhead_forward_to_grid ()
7162 framepos_t pos = playhead_cursor->current_frame ();
7163 if (pos < max_framepos - 1) {
7165 snap_to_internal (pos, RoundUpAlways, false);
7166 _session->request_locate (pos);
7172 Editor::playhead_backward_to_grid ()
7178 framepos_t pos = playhead_cursor->current_frame ();
7181 snap_to_internal (pos, RoundDownAlways, false);
7182 _session->request_locate (pos);
7187 Editor::set_track_height (Height h)
7189 TrackSelection& ts (selection->tracks);
7191 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
7192 (*x)->set_height_enum (h);
7197 Editor::toggle_tracks_active ()
7199 TrackSelection& ts (selection->tracks);
7201 bool target = false;
7207 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
7208 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*x);
7212 target = !rtv->_route->active();
7215 rtv->_route->set_active (target, this);
7221 Editor::remove_tracks ()
7223 /* this will delete GUI objects that may be the subject of an event
7224 handler in which this method is called. Defer actual deletion to the
7225 next idle callback, when all event handling is finished.
7227 Glib::signal_idle().connect (sigc::mem_fun (*this, &Editor::idle_remove_tracks));
7231 Editor::idle_remove_tracks ()
7233 Session::StateProtector sp (_session);
7235 return false; /* do not call again */
7239 Editor::_remove_tracks ()
7241 TrackSelection& ts (selection->tracks);
7247 vector<string> choices;
7251 const char* trackstr;
7253 vector<boost::shared_ptr<Route> > routes;
7254 bool special_bus = false;
7256 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
7257 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*x);
7261 if (rtv->is_track()) {
7266 routes.push_back (rtv->_route);
7268 if (rtv->route()->is_master() || rtv->route()->is_monitor()) {
7273 if (special_bus && !Config->get_allow_special_bus_removal()) {
7274 MessageDialog msg (_("That would be bad news ...."),
7278 msg.set_secondary_text (string_compose (_(
7279 "Removing the master or monitor bus is such a bad idea\n\
7280 that %1 is not going to allow it.\n\
7282 If you really want to do this sort of thing\n\
7283 edit your ardour.rc file to set the\n\
7284 \"allow-special-bus-removal\" option to be \"yes\""), PROGRAM_NAME));
7291 if (ntracks + nbusses == 0) {
7295 trackstr = P_("track", "tracks", ntracks);
7296 busstr = P_("bus", "busses", nbusses);
7300 prompt = string_compose (_("Do you really want to remove %1 %2 and %3 %4?\n"
7301 "(You may also lose the playlists associated with the %2)\n\n"
7302 "This action cannot be undone, and the session file will be overwritten!"),
7303 ntracks, trackstr, nbusses, busstr);
7305 prompt = string_compose (_("Do you really want to remove %1 %2?\n"
7306 "(You may also lose the playlists associated with the %2)\n\n"
7307 "This action cannot be undone, and the session file will be overwritten!"),
7310 } else if (nbusses) {
7311 prompt = string_compose (_("Do you really want to remove %1 %2?\n\n"
7312 "This action cannot be undone, and the session file will be overwritten"),
7316 choices.push_back (_("No, do nothing."));
7317 if (ntracks + nbusses > 1) {
7318 choices.push_back (_("Yes, remove them."));
7320 choices.push_back (_("Yes, remove it."));
7325 title = string_compose (_("Remove %1"), trackstr);
7327 title = string_compose (_("Remove %1"), busstr);
7330 Choice prompter (title, prompt, choices);
7332 if (prompter.run () != 1) {
7336 if (current_mixer_strip && routes.size () > 1 && std::find (routes.begin(), routes.end(), current_mixer_strip->route()) != routes.end ()) {
7337 /* Route deletion calls Editor::timeaxisview_deleted() iteratively (for each deleted
7338 * route). If the deleted route is currently displayed in the Editor-Mixer (highly
7339 * likely because deletion requires selection) this will call
7340 * Editor::set_selected_mixer_strip () which is expensive ( MixerStrip::set_route() ).
7341 * It's likewise likely that the route that has just been displayed in the
7342 * Editor-Mixer will be next in line for deletion.
7344 * So simply switch to the master-bus (if present)
7346 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
7347 if ((*i)->stripable ()->is_master ()) {
7348 set_selected_mixer_strip (*(*i));
7354 Mixer_UI::instance()->selection().block_routes_changed (true);
7355 selection->block_tracks_changed (true);
7357 DisplaySuspender ds;
7358 boost::shared_ptr<RouteList> rl (new RouteList);
7359 for (vector<boost::shared_ptr<Route> >::iterator x = routes.begin(); x != routes.end(); ++x) {
7362 _session->remove_routes (rl);
7364 /* TrackSelection and RouteList leave scope,
7365 * destructors are called,
7366 * diskstream drops references, save_state is called (again for every track)
7368 selection->block_tracks_changed (false);
7369 Mixer_UI::instance()->selection().block_routes_changed (false);
7370 selection->TracksChanged (); /* EMIT SIGNAL */
7374 Editor::do_insert_time ()
7376 if (selection->tracks.empty()) {
7380 InsertRemoveTimeDialog d (*this);
7381 int response = d.run ();
7383 if (response != RESPONSE_OK) {
7387 if (d.distance() == 0) {
7394 d.intersected_region_action (),
7398 d.move_glued_markers(),
7399 d.move_locked_markers(),
7405 Editor::insert_time (
7406 framepos_t pos, framecnt_t frames, InsertTimeOption opt,
7407 bool all_playlists, bool ignore_music_glue, bool markers_too, bool glued_markers_too, bool locked_markers_too, bool tempo_too
7411 if (Config->get_edit_mode() == Lock) {
7414 bool in_command = false;
7416 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
7418 for (TrackViewList::iterator x = ts.begin(); x != ts.end(); ++x) {
7422 /* don't operate on any playlist more than once, which could
7423 * happen if "all playlists" is enabled, but there is more
7424 * than 1 track using playlists "from" a given track.
7427 set<boost::shared_ptr<Playlist> > pl;
7429 if (all_playlists) {
7430 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*x);
7431 if (rtav && rtav->track ()) {
7432 vector<boost::shared_ptr<Playlist> > all = _session->playlists->playlists_for_track (rtav->track ());
7433 for (vector<boost::shared_ptr<Playlist> >::iterator p = all.begin(); p != all.end(); ++p) {
7438 if ((*x)->playlist ()) {
7439 pl.insert ((*x)->playlist ());
7443 for (set<boost::shared_ptr<Playlist> >::iterator i = pl.begin(); i != pl.end(); ++i) {
7445 (*i)->clear_changes ();
7446 (*i)->clear_owned_changes ();
7448 if (opt == SplitIntersected) {
7449 /* non musical split */
7450 (*i)->split (pos, 0);
7453 (*i)->shift (pos, frames, (opt == MoveIntersected), ignore_music_glue);
7456 begin_reversible_command (_("insert time"));
7459 vector<Command*> cmds;
7461 _session->add_commands (cmds);
7463 _session->add_command (new StatefulDiffCommand (*i));
7467 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*x);
7470 begin_reversible_command (_("insert time"));
7473 rtav->route ()->shift (pos, frames);
7480 XMLNode& before (_session->locations()->get_state());
7481 Locations::LocationList copy (_session->locations()->list());
7483 for (Locations::LocationList::iterator i = copy.begin(); i != copy.end(); ++i) {
7485 Locations::LocationList::const_iterator tmp;
7487 if ((*i)->position_lock_style() == AudioTime || glued_markers_too) {
7488 bool const was_locked = (*i)->locked ();
7489 if (locked_markers_too) {
7493 if ((*i)->start() >= pos) {
7494 // move end first, in case we're moving by more than the length of the range
7495 if (!(*i)->is_mark()) {
7496 (*i)->set_end ((*i)->end() + frames);
7498 (*i)->set_start ((*i)->start() + frames);
7510 begin_reversible_command (_("insert time"));
7513 XMLNode& after (_session->locations()->get_state());
7514 _session->add_command (new MementoCommand<Locations>(*_session->locations(), &before, &after));
7520 begin_reversible_command (_("insert time"));
7523 XMLNode& before (_session->tempo_map().get_state());
7524 _session->tempo_map().insert_time (pos, frames);
7525 XMLNode& after (_session->tempo_map().get_state());
7526 _session->add_command (new MementoCommand<TempoMap>(_session->tempo_map(), &before, &after));
7530 commit_reversible_command ();
7535 Editor::do_remove_time ()
7537 if (selection->tracks.empty()) {
7541 InsertRemoveTimeDialog d (*this, true);
7543 int response = d.run ();
7545 if (response != RESPONSE_OK) {
7549 framecnt_t distance = d.distance();
7551 if (distance == 0) {
7561 d.move_glued_markers(),
7562 d.move_locked_markers(),
7568 Editor::remove_time (framepos_t pos, framecnt_t frames, InsertTimeOption opt,
7569 bool ignore_music_glue, bool markers_too, bool glued_markers_too, bool locked_markers_too, bool tempo_too)
7571 if (Config->get_edit_mode() == Lock) {
7572 error << (_("Cannot insert or delete time when in Lock edit.")) << endmsg;
7575 bool in_command = false;
7577 for (TrackSelection::iterator x = selection->tracks.begin(); x != selection->tracks.end(); ++x) {
7579 boost::shared_ptr<Playlist> pl = (*x)->playlist();
7583 XMLNode &before = pl->get_state();
7585 std::list<AudioRange> rl;
7586 AudioRange ar(pos, pos+frames, 0);
7589 pl->shift (pos, -frames, true, ignore_music_glue);
7592 begin_reversible_command (_("remove time"));
7595 XMLNode &after = pl->get_state();
7597 _session->add_command (new MementoCommand<Playlist> (*pl, &before, &after));
7601 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*x);
7604 begin_reversible_command (_("remove time"));
7607 rtav->route ()->shift (pos, -frames);
7611 std::list<Location*> loc_kill_list;
7616 XMLNode& before (_session->locations()->get_state());
7617 Locations::LocationList copy (_session->locations()->list());
7619 for (Locations::LocationList::iterator i = copy.begin(); i != copy.end(); ++i) {
7620 if ((*i)->position_lock_style() == AudioTime || glued_markers_too) {
7622 bool const was_locked = (*i)->locked ();
7623 if (locked_markers_too) {
7627 if (!(*i)->is_mark()) { // it's a range; have to handle both start and end
7628 if ((*i)->end() >= pos
7629 && (*i)->end() < pos+frames
7630 && (*i)->start() >= pos
7631 && (*i)->end() < pos+frames) { // range is completely enclosed; kill it
7633 loc_kill_list.push_back(*i);
7634 } else { // only start or end is included, try to do the right thing
7635 // move start before moving end, to avoid trying to move the end to before the start
7636 // if we're removing more time than the length of the range
7637 if ((*i)->start() >= pos && (*i)->start() < pos+frames) {
7638 // start is within cut
7639 (*i)->set_start (pos); // bring the start marker to the beginning of the cut
7641 } else if ((*i)->start() >= pos+frames) {
7642 // start (and thus entire range) lies beyond end of cut
7643 (*i)->set_start ((*i)->start() - frames); // slip the start marker back
7646 if ((*i)->end() >= pos && (*i)->end() < pos+frames) {
7647 // end is inside cut
7648 (*i)->set_end (pos); // bring the end to the cut
7650 } else if ((*i)->end() >= pos+frames) {
7651 // end is beyond end of cut
7652 (*i)->set_end ((*i)->end() - frames); // slip the end marker back
7657 } else if ((*i)->start() >= pos && (*i)->start() < pos+frames ) {
7658 loc_kill_list.push_back(*i);
7660 } else if ((*i)->start() >= pos) {
7661 (*i)->set_start ((*i)->start() -frames);
7671 for (list<Location*>::iterator i = loc_kill_list.begin(); i != loc_kill_list.end(); ++i) {
7672 _session->locations()->remove( *i );
7677 begin_reversible_command (_("remove time"));
7680 XMLNode& after (_session->locations()->get_state());
7681 _session->add_command (new MementoCommand<Locations>(*_session->locations(), &before, &after));
7686 XMLNode& before (_session->tempo_map().get_state());
7688 if (_session->tempo_map().remove_time (pos, frames) ) {
7690 begin_reversible_command (_("remove time"));
7693 XMLNode& after (_session->tempo_map().get_state());
7694 _session->add_command (new MementoCommand<TempoMap>(_session->tempo_map(), &before, &after));
7699 commit_reversible_command ();
7704 Editor::fit_selection ()
7706 if (!selection->tracks.empty()) {
7707 fit_tracks (selection->tracks);
7711 /* no selected tracks - use tracks with selected regions */
7713 if (!selection->regions.empty()) {
7714 for (RegionSelection::iterator r = selection->regions.begin(); r != selection->regions.end(); ++r) {
7715 tvl.push_back (&(*r)->get_time_axis_view ());
7721 } else if (internal_editing()) {
7722 /* no selected tracks, or regions, but in internal edit mode, so follow the mouse and use
7725 if (entered_track) {
7726 tvl.push_back (entered_track);
7735 Editor::fit_tracks (TrackViewList & tracks)
7737 if (tracks.empty()) {
7741 uint32_t child_heights = 0;
7742 int visible_tracks = 0;
7744 for (TrackSelection::iterator t = tracks.begin(); t != tracks.end(); ++t) {
7746 if (!(*t)->marked_for_display()) {
7750 child_heights += (*t)->effective_height() - (*t)->current_height();
7754 /* compute the per-track height from:
7756 total canvas visible height -
7757 height that will be taken by visible children of selected
7758 tracks - height of the ruler/hscroll area
7760 uint32_t h = (uint32_t) floor ((trackviews_height() - child_heights) / visible_tracks);
7761 double first_y_pos = DBL_MAX;
7763 if (h < TimeAxisView::preset_height (HeightSmall)) {
7764 MessageDialog msg (_("There are too many tracks to fit in the current window"));
7765 /* too small to be displayed */
7769 undo_visual_stack.push_back (current_visual_state (true));
7770 PBD::Unwinder<bool> nsv (no_save_visual, true);
7772 /* build a list of all tracks, including children */
7775 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
7777 TimeAxisView::Children c = (*i)->get_child_list ();
7778 for (TimeAxisView::Children::iterator j = c.begin(); j != c.end(); ++j) {
7779 all.push_back (j->get());
7784 // find selection range.
7785 // if someone knows how to user TrackViewList::iterator for this
7787 int selected_top = -1;
7788 int selected_bottom = -1;
7790 for (TrackViewList::iterator t = all.begin(); t != all.end(); ++t, ++i) {
7791 if ((*t)->marked_for_display ()) {
7792 if (tracks.contains(*t)) {
7793 if (selected_top == -1) {
7796 selected_bottom = i;
7802 for (TrackViewList::iterator t = all.begin(); t != all.end(); ++t, ++i) {
7803 if ((*t)->marked_for_display ()) {
7804 if (tracks.contains(*t)) {
7805 (*t)->set_height (h);
7806 first_y_pos = std::min ((*t)->y_position (), first_y_pos);
7808 if (i > selected_top && i < selected_bottom) {
7809 hide_track_in_display (*t);
7816 set the controls_layout height now, because waiting for its size
7817 request signal handler will cause the vertical adjustment setting to fail
7820 controls_layout.property_height () = _full_canvas_height;
7821 vertical_adjustment.set_value (first_y_pos);
7823 redo_visual_stack.push_back (current_visual_state (true));
7825 visible_tracks_selector.set_text (_("Sel"));
7829 Editor::save_visual_state (uint32_t n)
7831 while (visual_states.size() <= n) {
7832 visual_states.push_back (0);
7835 if (visual_states[n] != 0) {
7836 delete visual_states[n];
7839 visual_states[n] = current_visual_state (true);
7844 Editor::goto_visual_state (uint32_t n)
7846 if (visual_states.size() <= n) {
7850 if (visual_states[n] == 0) {
7854 use_visual_state (*visual_states[n]);
7858 Editor::start_visual_state_op (uint32_t n)
7860 save_visual_state (n);
7862 PopUp* pup = new PopUp (WIN_POS_MOUSE, 1000, true);
7864 snprintf (buf, sizeof (buf), _("Saved view %u"), n+1);
7865 pup->set_text (buf);
7870 Editor::cancel_visual_state_op (uint32_t n)
7872 goto_visual_state (n);
7876 Editor::toggle_region_mute ()
7878 if (_ignore_region_action) {
7882 RegionSelection rs = get_regions_from_selection_and_entered ();
7888 if (rs.size() > 1) {
7889 begin_reversible_command (_("mute regions"));
7891 begin_reversible_command (_("mute region"));
7894 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
7896 (*i)->region()->playlist()->clear_changes ();
7897 (*i)->region()->set_muted (!(*i)->region()->muted ());
7898 _session->add_command (new StatefulDiffCommand ((*i)->region()));
7902 commit_reversible_command ();
7906 Editor::combine_regions ()
7908 /* foreach track with selected regions, take all selected regions
7909 and join them into a new region containing the subregions (as a
7913 typedef set<RouteTimeAxisView*> RTVS;
7916 if (selection->regions.empty()) {
7920 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
7921 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(&(*i)->get_time_axis_view());
7924 tracks.insert (rtv);
7928 begin_reversible_command (_("combine regions"));
7930 vector<RegionView*> new_selection;
7932 for (RTVS::iterator i = tracks.begin(); i != tracks.end(); ++i) {
7935 if ((rv = (*i)->combine_regions ()) != 0) {
7936 new_selection.push_back (rv);
7940 selection->clear_regions ();
7941 for (vector<RegionView*>::iterator i = new_selection.begin(); i != new_selection.end(); ++i) {
7942 selection->add (*i);
7945 commit_reversible_command ();
7949 Editor::uncombine_regions ()
7951 typedef set<RouteTimeAxisView*> RTVS;
7954 if (selection->regions.empty()) {
7958 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
7959 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(&(*i)->get_time_axis_view());
7962 tracks.insert (rtv);
7966 begin_reversible_command (_("uncombine regions"));
7968 for (RTVS::iterator i = tracks.begin(); i != tracks.end(); ++i) {
7969 (*i)->uncombine_regions ();
7972 commit_reversible_command ();
7976 Editor::toggle_midi_input_active (bool flip_others)
7979 boost::shared_ptr<RouteList> rl (new RouteList);
7981 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
7982 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
7988 boost::shared_ptr<MidiTrack> mt = rtav->midi_track();
7991 rl->push_back (rtav->route());
7992 onoff = !mt->input_active();
7996 _session->set_exclusive_input_active (rl, onoff, flip_others);
7999 static bool ok_fine (GdkEventAny*) { return true; }
8005 lock_dialog = new Gtk::Dialog (string_compose (_("%1: Locked"), PROGRAM_NAME), true);
8007 Gtk::Image* padlock = manage (new Gtk::Image (ARDOUR_UI_UTILS::get_icon ("padlock_closed")));
8008 lock_dialog->get_vbox()->pack_start (*padlock);
8009 lock_dialog->signal_delete_event ().connect (sigc::ptr_fun (ok_fine));
8011 ArdourButton* b = manage (new ArdourButton);
8012 b->set_name ("lock button");
8013 b->set_text (_("Click to unlock"));
8014 b->signal_clicked.connect (sigc::mem_fun (*this, &Editor::unlock));
8015 lock_dialog->get_vbox()->pack_start (*b);
8017 lock_dialog->get_vbox()->show_all ();
8018 lock_dialog->set_size_request (200, 200);
8021 delete _main_menu_disabler;
8022 _main_menu_disabler = new MainMenuDisabler;
8024 lock_dialog->present ();
8026 lock_dialog->get_window()->set_decorations (Gdk::WMDecoration (0));
8032 lock_dialog->hide ();
8034 delete _main_menu_disabler;
8035 _main_menu_disabler = 0;
8037 if (UIConfiguration::instance().get_lock_gui_after_seconds()) {
8038 start_lock_event_timing ();
8043 Editor::bring_in_callback (Gtk::Label* label, uint32_t n, uint32_t total, string name)
8045 Gtkmm2ext::UI::instance()->call_slot (invalidator (*this), boost::bind (&Editor::update_bring_in_message, this, label, n, total, name));
8049 Editor::update_bring_in_message (Gtk::Label* label, uint32_t n, uint32_t total, string name)
8051 Timers::TimerSuspender t;
8052 label->set_text (string_compose ("Copying %1, %2 of %3", name, n, total));
8053 Gtkmm2ext::UI::instance()->flush_pending (1);
8057 Editor::bring_all_sources_into_session ()
8064 ArdourDialog w (_("Moving embedded files into session folder"));
8065 w.get_vbox()->pack_start (msg);
8068 /* flush all pending GUI events because we're about to start copying
8072 Timers::TimerSuspender t;
8073 Gtkmm2ext::UI::instance()->flush_pending (3);
8077 _session->bring_all_sources_into_session (boost::bind (&Editor::bring_in_callback, this, &msg, _1, _2, _3));