2 Copyright (C) 2000-2004 Paul Davis
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 /* Note: public Editor methods are documented in public_editor.h */
31 #include "pbd/error.h"
32 #include "pbd/basename.h"
33 #include "pbd/pthread_utils.h"
34 #include "pbd/memento_command.h"
35 #include "pbd/unwind.h"
36 #include "pbd/whitespace.h"
37 #include "pbd/stateful_diff_command.h"
39 #include <gtkmm2ext/utils.h>
40 #include <gtkmm2ext/choice.h>
41 #include <gtkmm2ext/popup.h>
43 #include "ardour/audio_track.h"
44 #include "ardour/audioregion.h"
45 #include "ardour/boost_debug.h"
46 #include "ardour/dB.h"
47 #include "ardour/location.h"
48 #include "ardour/midi_region.h"
49 #include "ardour/midi_track.h"
50 #include "ardour/operations.h"
51 #include "ardour/playlist_factory.h"
52 #include "ardour/profile.h"
53 #include "ardour/quantize.h"
54 #include "ardour/legatize.h"
55 #include "ardour/region_factory.h"
56 #include "ardour/reverse.h"
57 #include "ardour/session.h"
58 #include "ardour/session_playlists.h"
59 #include "ardour/strip_silence.h"
60 #include "ardour/transient_detector.h"
61 #include "ardour/transpose.h"
63 #include "canvas/canvas.h"
66 #include "audio_region_view.h"
67 #include "audio_streamview.h"
68 #include "audio_time_axis.h"
69 #include "automation_region_view.h"
70 #include "automation_time_axis.h"
71 #include "control_point.h"
75 #include "editor_cursors.h"
76 #include "editor_drag.h"
77 #include "editor_regions.h"
78 #include "editor_routes.h"
79 #include "gui_thread.h"
80 #include "insert_remove_time_dialog.h"
81 #include "interthread_progress_window.h"
82 #include "item_counts.h"
84 #include "midi_region_view.h"
86 #include "mixer_strip.h"
87 #include "mouse_cursors.h"
88 #include "normalize_dialog.h"
90 #include "paste_context.h"
91 #include "patch_change_dialog.h"
92 #include "quantize_dialog.h"
93 #include "region_gain_line.h"
94 #include "rgb_macros.h"
95 #include "route_time_axis.h"
96 #include "selection.h"
97 #include "selection_templates.h"
98 #include "streamview.h"
99 #include "strip_silence_dialog.h"
100 #include "time_axis_view.h"
102 #include "transpose_dialog.h"
103 #include "transform_dialog.h"
104 #include "ui_config.h"
106 #include "pbd/i18n.h"
109 using namespace ARDOUR;
112 using namespace Gtkmm2ext;
113 using namespace Editing;
114 using Gtkmm2ext::Keyboard;
116 /***********************************************************************
118 ***********************************************************************/
121 Editor::undo (uint32_t n)
123 if (_session && _session->actively_recording()) {
124 /* no undo allowed while recording. Session will check also,
125 but we don't even want to get to that.
130 if (_drags->active ()) {
136 if (_session->undo_depth() == 0) {
137 undo_action->set_sensitive(false);
139 redo_action->set_sensitive(true);
140 begin_selection_op_history ();
145 Editor::redo (uint32_t n)
147 if (_session && _session->actively_recording()) {
148 /* no redo allowed while recording. Session will check also,
149 but we don't even want to get to that.
154 if (_drags->active ()) {
160 if (_session->redo_depth() == 0) {
161 redo_action->set_sensitive(false);
163 undo_action->set_sensitive(true);
164 begin_selection_op_history ();
169 Editor::split_regions_at (MusicFrame where, RegionSelection& regions, bool snap_frame)
173 RegionSelection pre_selected_regions = selection->regions;
174 bool working_on_selection = !pre_selected_regions.empty();
176 list<boost::shared_ptr<Playlist> > used_playlists;
177 list<RouteTimeAxisView*> used_trackviews;
179 if (regions.empty()) {
183 begin_reversible_command (_("split"));
185 // if splitting a single region, and snap-to is using
186 // region boundaries, don't pay attention to them
188 if (regions.size() == 1) {
189 switch (_snap_type) {
190 case SnapToRegionStart:
191 case SnapToRegionSync:
192 case SnapToRegionEnd:
205 EditorFreeze(); /* Emit Signal */
208 for (RegionSelection::iterator a = regions.begin(); a != regions.end(); ) {
210 RegionSelection::iterator tmp;
212 /* XXX this test needs to be more complicated, to make sure we really
213 have something to split.
216 if (!(*a)->region()->covers (where.frame)) {
224 boost::shared_ptr<Playlist> pl = (*a)->region()->playlist();
232 /* we haven't seen this playlist before */
234 /* remember used playlists so we can thaw them later */
235 used_playlists.push_back(pl);
237 TimeAxisView& tv = (*a)->get_time_axis_view();
238 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (&tv);
240 used_trackviews.push_back (rtv);
247 pl->clear_changes ();
248 pl->split_region ((*a)->region(), where);
249 _session->add_command (new StatefulDiffCommand (pl));
255 latest_regionviews.clear ();
257 vector<sigc::connection> region_added_connections;
259 for (list<RouteTimeAxisView*>::iterator i = used_trackviews.begin(); i != used_trackviews.end(); ++i) {
260 region_added_connections.push_back ((*i)->view()->RegionViewAdded.connect (sigc::mem_fun(*this, &Editor::collect_new_region_view)));
263 while (used_playlists.size() > 0) {
264 list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
266 used_playlists.pop_front();
269 for (vector<sigc::connection>::iterator c = region_added_connections.begin(); c != region_added_connections.end(); ++c) {
274 EditorThaw(); /* Emit Signal */
277 if (working_on_selection) {
278 // IFF we were working on selected regions, try to reinstate the other region selections that existed before the freeze/thaw.
280 RegionSelectionAfterSplit rsas = Config->get_region_selection_after_split();
281 /* There are three classes of regions that we might want selected after
282 splitting selected regions:
283 - regions selected before the split operation, and unaffected by it
284 - newly-created regions before the split
285 - newly-created regions after the split
288 if (rsas & Existing) {
289 // region selections that existed before the split.
290 selection->add ( pre_selected_regions );
293 for (RegionSelection::iterator ri = latest_regionviews.begin(); ri != latest_regionviews.end(); ri++) {
294 if ((*ri)->region()->position() < where.frame) {
295 // new regions created before the split
296 if (rsas & NewlyCreatedLeft) {
297 selection->add (*ri);
300 // new regions created after the split
301 if (rsas & NewlyCreatedRight) {
302 selection->add (*ri);
307 if( working_on_selection ) {
308 selection->add (latest_regionviews); //these are the new regions created after the split
312 commit_reversible_command ();
315 /** Move one extreme of the current range selection. If more than one range is selected,
316 * the start of the earliest range or the end of the latest range is moved.
318 * @param move_end true to move the end of the current range selection, false to move
320 * @param next true to move the extreme to the next region boundary, false to move to
324 Editor::move_range_selection_start_or_end_to_region_boundary (bool move_end, bool next)
326 if (selection->time.start() == selection->time.end_frame()) {
330 framepos_t start = selection->time.start ();
331 framepos_t end = selection->time.end_frame ();
333 /* the position of the thing we may move */
334 framepos_t pos = move_end ? end : start;
335 int dir = next ? 1 : -1;
337 /* so we don't find the current region again */
338 if (dir > 0 || pos > 0) {
342 framepos_t const target = get_region_boundary (pos, dir, true, false);
357 begin_reversible_selection_op (_("alter selection"));
358 selection->set_preserving_all_ranges (start, end);
359 commit_reversible_selection_op ();
363 Editor::nudge_forward_release (GdkEventButton* ev)
365 if (ev->state & Keyboard::PrimaryModifier) {
366 nudge_forward (false, true);
368 nudge_forward (false, false);
374 Editor::nudge_backward_release (GdkEventButton* ev)
376 if (ev->state & Keyboard::PrimaryModifier) {
377 nudge_backward (false, true);
379 nudge_backward (false, false);
386 Editor::nudge_forward (bool next, bool force_playhead)
389 framepos_t next_distance;
395 RegionSelection rs = get_regions_from_selection_and_entered ();
397 if (!force_playhead && !rs.empty()) {
399 begin_reversible_command (_("nudge regions forward"));
401 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
402 boost::shared_ptr<Region> r ((*i)->region());
404 distance = get_nudge_distance (r->position(), next_distance);
407 distance = next_distance;
411 r->set_position (r->position() + distance);
412 _session->add_command (new StatefulDiffCommand (r));
415 commit_reversible_command ();
418 } else if (!force_playhead && !selection->markers.empty()) {
421 bool in_command = false;
422 const int32_t divisions = get_grid_music_divisions (0);
424 for (MarkerSelection::iterator i = selection->markers.begin(); i != selection->markers.end(); ++i) {
426 Location* loc = find_location_from_marker ((*i), is_start);
430 XMLNode& before (loc->get_state());
433 distance = get_nudge_distance (loc->start(), next_distance);
435 distance = next_distance;
437 if (max_framepos - distance > loc->start() + loc->length()) {
438 loc->set_start (loc->start() + distance, false, true, divisions);
440 loc->set_start (max_framepos - loc->length(), false, true, divisions);
443 distance = get_nudge_distance (loc->end(), next_distance);
445 distance = next_distance;
447 if (max_framepos - distance > loc->end()) {
448 loc->set_end (loc->end() + distance, false, true, divisions);
450 loc->set_end (max_framepos, false, true, divisions);
452 if (loc->is_session_range()) {
453 _session->set_end_is_free (false);
457 begin_reversible_command (_("nudge location forward"));
460 XMLNode& after (loc->get_state());
461 _session->add_command (new MementoCommand<Location>(*loc, &before, &after));
466 commit_reversible_command ();
469 distance = get_nudge_distance (playhead_cursor->current_frame (), next_distance);
470 _session->request_locate (playhead_cursor->current_frame () + distance);
475 Editor::nudge_backward (bool next, bool force_playhead)
478 framepos_t next_distance;
484 RegionSelection rs = get_regions_from_selection_and_entered ();
486 if (!force_playhead && !rs.empty()) {
488 begin_reversible_command (_("nudge regions backward"));
490 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
491 boost::shared_ptr<Region> r ((*i)->region());
493 distance = get_nudge_distance (r->position(), next_distance);
496 distance = next_distance;
501 if (r->position() > distance) {
502 r->set_position (r->position() - distance);
506 _session->add_command (new StatefulDiffCommand (r));
509 commit_reversible_command ();
511 } else if (!force_playhead && !selection->markers.empty()) {
514 bool in_command = false;
516 for (MarkerSelection::iterator i = selection->markers.begin(); i != selection->markers.end(); ++i) {
518 Location* loc = find_location_from_marker ((*i), is_start);
522 XMLNode& before (loc->get_state());
525 distance = get_nudge_distance (loc->start(), next_distance);
527 distance = next_distance;
529 if (distance < loc->start()) {
530 loc->set_start (loc->start() - distance, false, true, get_grid_music_divisions(0));
532 loc->set_start (0, false, true, get_grid_music_divisions(0));
535 distance = get_nudge_distance (loc->end(), next_distance);
538 distance = next_distance;
541 if (distance < loc->end() - loc->length()) {
542 loc->set_end (loc->end() - distance, false, true, get_grid_music_divisions(0));
544 loc->set_end (loc->length(), false, true, get_grid_music_divisions(0));
546 if (loc->is_session_range()) {
547 _session->set_end_is_free (false);
551 begin_reversible_command (_("nudge location forward"));
554 XMLNode& after (loc->get_state());
555 _session->add_command (new MementoCommand<Location>(*loc, &before, &after));
559 commit_reversible_command ();
564 distance = get_nudge_distance (playhead_cursor->current_frame (), next_distance);
566 if (playhead_cursor->current_frame () > distance) {
567 _session->request_locate (playhead_cursor->current_frame () - distance);
569 _session->goto_start();
575 Editor::nudge_forward_capture_offset ()
577 RegionSelection rs = get_regions_from_selection_and_entered ();
579 if (!_session || rs.empty()) {
583 begin_reversible_command (_("nudge forward"));
585 framepos_t const distance = _session->worst_output_latency();
587 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
588 boost::shared_ptr<Region> r ((*i)->region());
591 r->set_position (r->position() + distance);
592 _session->add_command(new StatefulDiffCommand (r));
595 commit_reversible_command ();
599 Editor::nudge_backward_capture_offset ()
601 RegionSelection rs = get_regions_from_selection_and_entered ();
603 if (!_session || rs.empty()) {
607 begin_reversible_command (_("nudge backward"));
609 framepos_t const distance = _session->worst_output_latency();
611 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
612 boost::shared_ptr<Region> r ((*i)->region());
616 if (r->position() > distance) {
617 r->set_position (r->position() - distance);
621 _session->add_command(new StatefulDiffCommand (r));
624 commit_reversible_command ();
627 struct RegionSelectionPositionSorter {
628 bool operator() (RegionView* a, RegionView* b) {
629 return a->region()->position() < b->region()->position();
634 Editor::sequence_regions ()
637 framepos_t r_end_prev;
645 RegionSelection rs = get_regions_from_selection_and_entered ();
646 rs.sort(RegionSelectionPositionSorter());
650 bool in_command = false;
652 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
653 boost::shared_ptr<Region> r ((*i)->region());
661 if(r->position_locked())
668 r->set_position(r_end_prev);
672 begin_reversible_command (_("sequence regions"));
675 _session->add_command (new StatefulDiffCommand (r));
677 r_end=r->position() + r->length();
683 commit_reversible_command ();
692 Editor::move_to_start ()
694 _session->goto_start ();
698 Editor::move_to_end ()
701 _session->request_locate (_session->current_end_frame());
705 Editor::build_region_boundary_cache ()
708 vector<RegionPoint> interesting_points;
709 boost::shared_ptr<Region> r;
710 TrackViewList tracks;
713 region_boundary_cache.clear ();
719 switch (_snap_type) {
720 case SnapToRegionStart:
721 interesting_points.push_back (Start);
723 case SnapToRegionEnd:
724 interesting_points.push_back (End);
726 case SnapToRegionSync:
727 interesting_points.push_back (SyncPoint);
729 case SnapToRegionBoundary:
730 interesting_points.push_back (Start);
731 interesting_points.push_back (End);
734 fatal << string_compose (_("build_region_boundary_cache called with snap_type = %1"), _snap_type) << endmsg;
735 abort(); /*NOTREACHED*/
739 TimeAxisView *ontrack = 0;
742 if (!selection->tracks.empty()) {
743 tlist = selection->tracks.filter_to_unique_playlists ();
745 tlist = track_views.filter_to_unique_playlists ();
748 while (pos < _session->current_end_frame() && !at_end) {
751 framepos_t lpos = max_framepos;
753 for (vector<RegionPoint>::iterator p = interesting_points.begin(); p != interesting_points.end(); ++p) {
755 if ((r = find_next_region (pos, *p, 1, tlist, &ontrack)) == 0) {
756 if (*p == interesting_points.back()) {
759 /* move to next point type */
765 rpos = r->first_frame();
769 rpos = r->last_frame();
773 rpos = r->sync_position ();
781 RouteTimeAxisView *rtav;
783 if (ontrack != 0 && (rtav = dynamic_cast<RouteTimeAxisView*>(ontrack)) != 0 ) {
784 if (rtav->track() != 0) {
785 speed = rtav->track()->speed();
789 rpos = track_frame_to_session_frame (rpos, speed);
795 /* prevent duplicates, but we don't use set<> because we want to be able
799 vector<framepos_t>::iterator ri;
801 for (ri = region_boundary_cache.begin(); ri != region_boundary_cache.end(); ++ri) {
807 if (ri == region_boundary_cache.end()) {
808 region_boundary_cache.push_back (rpos);
815 /* finally sort to be sure that the order is correct */
817 sort (region_boundary_cache.begin(), region_boundary_cache.end());
820 boost::shared_ptr<Region>
821 Editor::find_next_region (framepos_t frame, RegionPoint point, int32_t dir, TrackViewList& tracks, TimeAxisView **ontrack)
823 TrackViewList::iterator i;
824 framepos_t closest = max_framepos;
825 boost::shared_ptr<Region> ret;
829 framepos_t track_frame;
830 RouteTimeAxisView *rtav;
832 for (i = tracks.begin(); i != tracks.end(); ++i) {
835 boost::shared_ptr<Region> r;
838 if ( (rtav = dynamic_cast<RouteTimeAxisView*>(*i)) != 0 ) {
839 if (rtav->track()!=0)
840 track_speed = rtav->track()->speed();
843 track_frame = session_frame_to_track_frame(frame, track_speed);
845 if ((r = (*i)->find_next_region (track_frame, point, dir)) == 0) {
851 rpos = r->first_frame ();
855 rpos = r->last_frame ();
859 rpos = r->sync_position ();
863 // rpos is a "track frame", converting it to "_session frame"
864 rpos = track_frame_to_session_frame(rpos, track_speed);
867 distance = rpos - frame;
869 distance = frame - rpos;
872 if (distance < closest) {
884 Editor::find_next_region_boundary (framepos_t pos, int32_t dir, const TrackViewList& tracks)
886 framecnt_t distance = max_framepos;
887 framepos_t current_nearest = -1;
889 for (TrackViewList::const_iterator i = tracks.begin(); i != tracks.end(); ++i) {
890 framepos_t contender;
893 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*i);
899 if ((contender = rtv->find_next_region_boundary (pos, dir)) < 0) {
903 d = ::llabs (pos - contender);
906 current_nearest = contender;
911 return current_nearest;
915 Editor::get_region_boundary (framepos_t pos, int32_t dir, bool with_selection, bool only_onscreen)
920 if (with_selection && Config->get_region_boundaries_from_selected_tracks()) {
922 if (!selection->tracks.empty()) {
924 target = find_next_region_boundary (pos, dir, selection->tracks);
928 if (only_onscreen || Config->get_region_boundaries_from_onscreen_tracks()) {
929 get_onscreen_tracks (tvl);
930 target = find_next_region_boundary (pos, dir, tvl);
932 target = find_next_region_boundary (pos, dir, track_views);
938 if (only_onscreen || Config->get_region_boundaries_from_onscreen_tracks()) {
939 get_onscreen_tracks (tvl);
940 target = find_next_region_boundary (pos, dir, tvl);
942 target = find_next_region_boundary (pos, dir, track_views);
950 Editor::cursor_to_region_boundary (bool with_selection, int32_t dir)
952 framepos_t pos = playhead_cursor->current_frame ();
959 // so we don't find the current region again..
960 if (dir > 0 || pos > 0) {
964 if ((target = get_region_boundary (pos, dir, with_selection, false)) < 0) {
968 _session->request_locate (target);
972 Editor::cursor_to_next_region_boundary (bool with_selection)
974 cursor_to_region_boundary (with_selection, 1);
978 Editor::cursor_to_previous_region_boundary (bool with_selection)
980 cursor_to_region_boundary (with_selection, -1);
984 Editor::cursor_to_region_point (EditorCursor* cursor, RegionPoint point, int32_t dir)
986 boost::shared_ptr<Region> r;
987 framepos_t pos = cursor->current_frame ();
993 TimeAxisView *ontrack = 0;
995 // so we don't find the current region again..
999 if (!selection->tracks.empty()) {
1001 r = find_next_region (pos, point, dir, selection->tracks, &ontrack);
1003 } else if (clicked_axisview) {
1006 t.push_back (clicked_axisview);
1008 r = find_next_region (pos, point, dir, t, &ontrack);
1012 r = find_next_region (pos, point, dir, track_views, &ontrack);
1021 pos = r->first_frame ();
1025 pos = r->last_frame ();
1029 pos = r->sync_position ();
1034 RouteTimeAxisView *rtav;
1036 if ( ontrack != 0 && (rtav = dynamic_cast<RouteTimeAxisView*>(ontrack)) != 0 ) {
1037 if (rtav->track() != 0) {
1038 speed = rtav->track()->speed();
1042 pos = track_frame_to_session_frame(pos, speed);
1044 if (cursor == playhead_cursor) {
1045 _session->request_locate (pos);
1047 cursor->set_position (pos);
1052 Editor::cursor_to_next_region_point (EditorCursor* cursor, RegionPoint point)
1054 cursor_to_region_point (cursor, point, 1);
1058 Editor::cursor_to_previous_region_point (EditorCursor* cursor, RegionPoint point)
1060 cursor_to_region_point (cursor, point, -1);
1064 Editor::cursor_to_selection_start (EditorCursor *cursor)
1068 switch (mouse_mode) {
1070 if (!selection->regions.empty()) {
1071 pos = selection->regions.start();
1076 if (!selection->time.empty()) {
1077 pos = selection->time.start ();
1085 if (cursor == playhead_cursor) {
1086 _session->request_locate (pos);
1088 cursor->set_position (pos);
1093 Editor::cursor_to_selection_end (EditorCursor *cursor)
1097 switch (mouse_mode) {
1099 if (!selection->regions.empty()) {
1100 pos = selection->regions.end_frame();
1105 if (!selection->time.empty()) {
1106 pos = selection->time.end_frame ();
1114 if (cursor == playhead_cursor) {
1115 _session->request_locate (pos);
1117 cursor->set_position (pos);
1122 Editor::selected_marker_to_region_boundary (bool with_selection, int32_t dir)
1132 if (selection->markers.empty()) {
1136 if (!mouse_frame (mouse, ignored)) {
1140 add_location_mark (mouse);
1143 if ((loc = find_location_from_marker (selection->markers.front(), ignored)) == 0) {
1147 framepos_t pos = loc->start();
1149 // so we don't find the current region again..
1150 if (dir > 0 || pos > 0) {
1154 if ((target = get_region_boundary (pos, dir, with_selection, false)) < 0) {
1158 loc->move_to (target, 0);
1162 Editor::selected_marker_to_next_region_boundary (bool with_selection)
1164 selected_marker_to_region_boundary (with_selection, 1);
1168 Editor::selected_marker_to_previous_region_boundary (bool with_selection)
1170 selected_marker_to_region_boundary (with_selection, -1);
1174 Editor::selected_marker_to_region_point (RegionPoint point, int32_t dir)
1176 boost::shared_ptr<Region> r;
1181 if (!_session || selection->markers.empty()) {
1185 if ((loc = find_location_from_marker (selection->markers.front(), ignored)) == 0) {
1189 TimeAxisView *ontrack = 0;
1193 // so we don't find the current region again..
1197 if (!selection->tracks.empty()) {
1199 r = find_next_region (pos, point, dir, selection->tracks, &ontrack);
1203 r = find_next_region (pos, point, dir, track_views, &ontrack);
1212 pos = r->first_frame ();
1216 pos = r->last_frame ();
1220 pos = r->adjust_to_sync (r->first_frame());
1225 RouteTimeAxisView *rtav;
1227 if (ontrack != 0 && (rtav = dynamic_cast<RouteTimeAxisView*>(ontrack)) != 0) {
1228 if (rtav->track() != 0) {
1229 speed = rtav->track()->speed();
1233 pos = track_frame_to_session_frame(pos, speed);
1235 loc->move_to (pos, 0);
1239 Editor::selected_marker_to_next_region_point (RegionPoint point)
1241 selected_marker_to_region_point (point, 1);
1245 Editor::selected_marker_to_previous_region_point (RegionPoint point)
1247 selected_marker_to_region_point (point, -1);
1251 Editor::selected_marker_to_selection_start ()
1257 if (!_session || selection->markers.empty()) {
1261 if ((loc = find_location_from_marker (selection->markers.front(), ignored)) == 0) {
1265 switch (mouse_mode) {
1267 if (!selection->regions.empty()) {
1268 pos = selection->regions.start();
1273 if (!selection->time.empty()) {
1274 pos = selection->time.start ();
1282 loc->move_to (pos, 0);
1286 Editor::selected_marker_to_selection_end ()
1292 if (!_session || selection->markers.empty()) {
1296 if ((loc = find_location_from_marker (selection->markers.front(), ignored)) == 0) {
1300 switch (mouse_mode) {
1302 if (!selection->regions.empty()) {
1303 pos = selection->regions.end_frame();
1308 if (!selection->time.empty()) {
1309 pos = selection->time.end_frame ();
1317 loc->move_to (pos, 0);
1321 Editor::scroll_playhead (bool forward)
1323 framepos_t pos = playhead_cursor->current_frame ();
1324 framecnt_t delta = (framecnt_t) floor (current_page_samples() / 0.8);
1327 if (pos == max_framepos) {
1331 if (pos < max_framepos - delta) {
1350 _session->request_locate (pos);
1354 Editor::cursor_align (bool playhead_to_edit)
1360 if (playhead_to_edit) {
1362 if (selection->markers.empty()) {
1366 _session->request_locate (selection->markers.front()->position(), _session->transport_rolling());
1369 const int32_t divisions = get_grid_music_divisions (0);
1370 /* move selected markers to playhead */
1372 for (MarkerSelection::iterator i = selection->markers.begin(); i != selection->markers.end(); ++i) {
1375 Location* loc = find_location_from_marker (*i, ignored);
1377 if (loc->is_mark()) {
1378 loc->set_start (playhead_cursor->current_frame (), false, true, divisions);
1380 loc->set (playhead_cursor->current_frame (),
1381 playhead_cursor->current_frame () + loc->length(), true, divisions);
1388 Editor::scroll_backward (float pages)
1390 framepos_t const one_page = (framepos_t) rint (_visible_canvas_width * samples_per_pixel);
1391 framepos_t const cnt = (framepos_t) floor (pages * one_page);
1394 if (leftmost_frame < cnt) {
1397 frame = leftmost_frame - cnt;
1400 reset_x_origin (frame);
1404 Editor::scroll_forward (float pages)
1406 framepos_t const one_page = (framepos_t) rint (_visible_canvas_width * samples_per_pixel);
1407 framepos_t const cnt = (framepos_t) floor (pages * one_page);
1410 if (max_framepos - cnt < leftmost_frame) {
1411 frame = max_framepos - cnt;
1413 frame = leftmost_frame + cnt;
1416 reset_x_origin (frame);
1420 Editor::scroll_tracks_down ()
1422 double vert_value = vertical_adjustment.get_value() + vertical_adjustment.get_page_size();
1423 if (vert_value > vertical_adjustment.get_upper() - _visible_canvas_height) {
1424 vert_value = vertical_adjustment.get_upper() - _visible_canvas_height;
1427 vertical_adjustment.set_value (vert_value);
1431 Editor::scroll_tracks_up ()
1433 vertical_adjustment.set_value (vertical_adjustment.get_value() - vertical_adjustment.get_page_size());
1437 Editor::scroll_tracks_down_line ()
1439 double vert_value = vertical_adjustment.get_value() + 60;
1441 if (vert_value > vertical_adjustment.get_upper() - _visible_canvas_height) {
1442 vert_value = vertical_adjustment.get_upper() - _visible_canvas_height;
1445 vertical_adjustment.set_value (vert_value);
1449 Editor::scroll_tracks_up_line ()
1451 reset_y_origin (vertical_adjustment.get_value() - 60);
1455 Editor::scroll_down_one_track (bool skip_child_views)
1457 TrackViewList::reverse_iterator next = track_views.rend();
1458 const double top_of_trackviews = vertical_adjustment.get_value();
1460 for (TrackViewList::reverse_iterator t = track_views.rbegin(); t != track_views.rend(); ++t) {
1461 if ((*t)->hidden()) {
1465 /* If this is the upper-most visible trackview, we want to display
1466 * the one above it (next)
1468 * Note that covers_y_position() is recursive and includes child views
1470 std::pair<TimeAxisView*,double> res = (*t)->covers_y_position (top_of_trackviews);
1473 if (skip_child_views) {
1476 /* automation lane (one level, non-recursive)
1478 * - if no automation lane exists -> move to next tack
1479 * - if the first (here: bottom-most) matches -> move to next tack
1480 * - if no y-axis match is found -> the current track is at the top
1481 * -> move to last (here: top-most) automation lane
1483 TimeAxisView::Children kids = (*t)->get_child_list();
1484 TimeAxisView::Children::reverse_iterator nkid = kids.rend();
1486 for (TimeAxisView::Children::reverse_iterator ci = kids.rbegin(); ci != kids.rend(); ++ci) {
1487 if ((*ci)->hidden()) {
1491 std::pair<TimeAxisView*,double> dev;
1492 dev = (*ci)->covers_y_position (top_of_trackviews);
1494 /* some automation lane is currently at the top */
1495 if (ci == kids.rbegin()) {
1496 /* first (bottom-most) autmation lane is at the top.
1497 * -> move to next track
1506 if (nkid != kids.rend()) {
1507 ensure_time_axis_view_is_visible (**nkid, true);
1515 /* move to the track below the first one that covers the */
1517 if (next != track_views.rend()) {
1518 ensure_time_axis_view_is_visible (**next, true);
1526 Editor::scroll_up_one_track (bool skip_child_views)
1528 TrackViewList::iterator prev = track_views.end();
1529 double top_of_trackviews = vertical_adjustment.get_value ();
1531 for (TrackViewList::iterator t = track_views.begin(); t != track_views.end(); ++t) {
1533 if ((*t)->hidden()) {
1537 /* find the trackview at the top of the trackview group
1539 * Note that covers_y_position() is recursive and includes child views
1541 std::pair<TimeAxisView*,double> res = (*t)->covers_y_position (top_of_trackviews);
1544 if (skip_child_views) {
1547 /* automation lane (one level, non-recursive)
1549 * - if no automation lane exists -> move to prev tack
1550 * - if no y-axis match is found -> the current track is at the top -> move to prev track
1551 * (actually last automation lane of previous track, see below)
1552 * - if first (top-most) lane is at the top -> move to this track
1553 * - else move up one lane
1555 TimeAxisView::Children kids = (*t)->get_child_list();
1556 TimeAxisView::Children::iterator pkid = kids.end();
1558 for (TimeAxisView::Children::iterator ci = kids.begin(); ci != kids.end(); ++ci) {
1559 if ((*ci)->hidden()) {
1563 std::pair<TimeAxisView*,double> dev;
1564 dev = (*ci)->covers_y_position (top_of_trackviews);
1566 /* some automation lane is currently at the top */
1567 if (ci == kids.begin()) {
1568 /* first (top-most) autmation lane is at the top.
1569 * jump directly to this track's top
1571 ensure_time_axis_view_is_visible (**t, true);
1574 else if (pkid != kids.end()) {
1575 /* some other automation lane is at the top.
1576 * move up to prev automation lane.
1578 ensure_time_axis_view_is_visible (**pkid, true);
1581 assert(0); // not reached
1592 if (prev != track_views.end()) {
1593 // move to bottom-most automation-lane of the previous track
1594 TimeAxisView::Children kids = (*prev)->get_child_list();
1595 TimeAxisView::Children::reverse_iterator pkid = kids.rend();
1596 if (!skip_child_views) {
1597 // find the last visible lane
1598 for (TimeAxisView::Children::reverse_iterator ci = kids.rbegin(); ci != kids.rend(); ++ci) {
1599 if (!(*ci)->hidden()) {
1605 if (pkid != kids.rend()) {
1606 ensure_time_axis_view_is_visible (**pkid, true);
1608 ensure_time_axis_view_is_visible (**prev, true);
1617 Editor::scroll_left_step ()
1619 framepos_t xdelta = (current_page_samples() / 8);
1621 if (leftmost_frame > xdelta) {
1622 reset_x_origin (leftmost_frame - xdelta);
1630 Editor::scroll_right_step ()
1632 framepos_t xdelta = (current_page_samples() / 8);
1634 if (max_framepos - xdelta > leftmost_frame) {
1635 reset_x_origin (leftmost_frame + xdelta);
1637 reset_x_origin (max_framepos - current_page_samples());
1642 Editor::scroll_left_half_page ()
1644 framepos_t xdelta = (current_page_samples() / 2);
1645 if (leftmost_frame > xdelta) {
1646 reset_x_origin (leftmost_frame - xdelta);
1653 Editor::scroll_right_half_page ()
1655 framepos_t xdelta = (current_page_samples() / 2);
1656 if (max_framepos - xdelta > leftmost_frame) {
1657 reset_x_origin (leftmost_frame + xdelta);
1659 reset_x_origin (max_framepos - current_page_samples());
1666 Editor::tav_zoom_step (bool coarser)
1668 DisplaySuspender ds;
1672 if (selection->tracks.empty()) {
1675 ts = &selection->tracks;
1678 for (TrackViewList::iterator i = ts->begin(); i != ts->end(); ++i) {
1679 TimeAxisView *tv = (static_cast<TimeAxisView*>(*i));
1680 tv->step_height (coarser);
1685 Editor::tav_zoom_smooth (bool coarser, bool force_all)
1687 DisplaySuspender ds;
1691 if (selection->tracks.empty() || force_all) {
1694 ts = &selection->tracks;
1697 for (TrackViewList::iterator i = ts->begin(); i != ts->end(); ++i) {
1698 TimeAxisView *tv = (static_cast<TimeAxisView*>(*i));
1699 uint32_t h = tv->current_height ();
1704 if (h >= TimeAxisView::preset_height (HeightSmall)) {
1709 tv->set_height (h + 5);
1715 Editor::temporal_zoom_step_mouse_focus_scale (bool zoom_out, double scale)
1717 Editing::ZoomFocus temp_focus = zoom_focus;
1718 zoom_focus = Editing::ZoomFocusMouse;
1719 temporal_zoom_step_scale (zoom_out, scale);
1720 zoom_focus = temp_focus;
1724 Editor::temporal_zoom_step_mouse_focus (bool zoom_out)
1726 temporal_zoom_step_mouse_focus_scale (zoom_out, 2.0);
1730 Editor::temporal_zoom_step (bool zoom_out)
1732 temporal_zoom_step_scale (zoom_out, 2.0);
1736 Editor::temporal_zoom_step_scale (bool zoom_out, double scale)
1738 ENSURE_GUI_THREAD (*this, &Editor::temporal_zoom_step, zoom_out, scale)
1740 framecnt_t nspp = samples_per_pixel;
1744 if (nspp == samples_per_pixel) {
1749 if (nspp == samples_per_pixel) {
1754 temporal_zoom (nspp);
1758 Editor::temporal_zoom (framecnt_t fpp)
1764 framepos_t current_page = current_page_samples();
1765 framepos_t current_leftmost = leftmost_frame;
1766 framepos_t current_rightmost;
1767 framepos_t current_center;
1768 framepos_t new_page_size;
1769 framepos_t half_page_size;
1770 framepos_t leftmost_after_zoom = 0;
1772 bool in_track_canvas;
1773 bool use_mouse_frame = true;
1777 if (fpp == samples_per_pixel) {
1781 // Imposing an arbitrary limit to zoom out as too much zoom out produces
1782 // segfaults for lack of memory. If somebody decides this is not high enough I
1783 // believe it can be raisen to higher values but some limit must be in place.
1785 // This constant represents 1 day @ 48kHz on a 1600 pixel wide display
1786 // all of which is used for the editor track displays. The whole day
1787 // would be 4147200000 samples, so 2592000 samples per pixel.
1789 nfpp = min (fpp, (framecnt_t) 2592000);
1790 nfpp = max ((framecnt_t) 1, nfpp);
1792 new_page_size = (framepos_t) floor (_visible_canvas_width * nfpp);
1793 half_page_size = new_page_size / 2;
1795 switch (zoom_focus) {
1797 leftmost_after_zoom = current_leftmost;
1800 case ZoomFocusRight:
1801 current_rightmost = leftmost_frame + current_page;
1802 if (current_rightmost < new_page_size) {
1803 leftmost_after_zoom = 0;
1805 leftmost_after_zoom = current_rightmost - new_page_size;
1809 case ZoomFocusCenter:
1810 current_center = current_leftmost + (current_page/2);
1811 if (current_center < half_page_size) {
1812 leftmost_after_zoom = 0;
1814 leftmost_after_zoom = current_center - half_page_size;
1818 case ZoomFocusPlayhead:
1819 /* centre playhead */
1820 l = playhead_cursor->current_frame () - (new_page_size * 0.5);
1823 leftmost_after_zoom = 0;
1824 } else if (l > max_framepos) {
1825 leftmost_after_zoom = max_framepos - new_page_size;
1827 leftmost_after_zoom = (framepos_t) l;
1831 case ZoomFocusMouse:
1832 /* try to keep the mouse over the same point in the display */
1834 if (_drags->active()) {
1835 where = _drags->current_pointer_frame ();
1836 } else if (!mouse_frame (where, in_track_canvas)) {
1837 use_mouse_frame = false;
1840 if (use_mouse_frame) {
1841 l = - ((new_page_size * ((where - current_leftmost)/(double)current_page)) - where);
1844 leftmost_after_zoom = 0;
1845 } else if (l > max_framepos) {
1846 leftmost_after_zoom = max_framepos - new_page_size;
1848 leftmost_after_zoom = (framepos_t) l;
1851 /* use playhead instead */
1852 where = playhead_cursor->current_frame ();
1854 if (where < half_page_size) {
1855 leftmost_after_zoom = 0;
1857 leftmost_after_zoom = where - half_page_size;
1863 /* try to keep the edit point in the same place */
1864 where = get_preferred_edit_position ();
1868 double l = - ((new_page_size * ((where - current_leftmost)/(double)current_page)) - where);
1871 leftmost_after_zoom = 0;
1872 } else if (l > max_framepos) {
1873 leftmost_after_zoom = max_framepos - new_page_size;
1875 leftmost_after_zoom = (framepos_t) l;
1879 /* edit point not defined */
1886 // leftmost_after_zoom = min (leftmost_after_zoom, _session->current_end_frame());
1888 reposition_and_zoom (leftmost_after_zoom, nfpp);
1892 Editor::calc_extra_zoom_edges(framepos_t &start, framepos_t &end)
1894 /* this func helps make sure we leave a little space
1895 at each end of the editor so that the zoom doesn't fit the region
1896 precisely to the screen.
1899 GdkScreen* screen = gdk_screen_get_default ();
1900 const gint pixwidth = gdk_screen_get_width (screen);
1901 const gint mmwidth = gdk_screen_get_width_mm (screen);
1902 const double pix_per_mm = (double) pixwidth/ (double) mmwidth;
1903 const double one_centimeter_in_pixels = pix_per_mm * 10.0;
1905 const framepos_t range = end - start;
1906 const framecnt_t new_fpp = (framecnt_t) ceil ((double) range / (double) _visible_canvas_width);
1907 const framepos_t extra_samples = (framepos_t) floor (one_centimeter_in_pixels * new_fpp);
1909 if (start > extra_samples) {
1910 start -= extra_samples;
1915 if (max_framepos - extra_samples > end) {
1916 end += extra_samples;
1923 Editor::get_selection_extents (framepos_t &start, framepos_t &end) const
1925 start = max_framepos;
1929 //ToDo: if notes are selected, set extents to that selection
1931 //ToDo: if control points are selected, set extents to that selection
1933 if ( !selection->regions.empty() ) {
1934 RegionSelection rs = get_regions_from_selection_and_entered ();
1936 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
1938 if ((*i)->region()->position() < start) {
1939 start = (*i)->region()->position();
1942 if ((*i)->region()->last_frame() + 1 > end) {
1943 end = (*i)->region()->last_frame() + 1;
1947 } else if (!selection->time.empty()) {
1948 start = selection->time.start();
1949 end = selection->time.end_frame();
1951 ret = false; //no selection found
1954 if ((start == 0 && end == 0) || end < start) {
1963 Editor::temporal_zoom_selection (Editing::ZoomAxis axes)
1965 if (!selection) return;
1967 //ToDo: if notes are selected, zoom to that
1969 //ToDo: if control points are selected, zoom to that
1971 if (axes == Horizontal || axes == Both) {
1973 framepos_t start, end;
1974 if (get_selection_extents (start, end)) {
1975 calc_extra_zoom_edges (start, end);
1976 temporal_zoom_by_frame (start, end);
1980 if (axes == Vertical || axes == Both) {
1986 Editor::temporal_zoom_session ()
1988 ENSURE_GUI_THREAD (*this, &Editor::temporal_zoom_session)
1991 framecnt_t start = _session->current_start_frame();
1992 framecnt_t end = _session->current_end_frame();
1994 if (_session->actively_recording () ) {
1995 framepos_t cur = playhead_cursor->current_frame ();
1997 /* recording beyond the end marker; zoom out
1998 * by 5 seconds more so that if 'follow
1999 * playhead' is active we don't immediately
2002 end = cur + _session->frame_rate() * 5;
2006 if ((start == 0 && end == 0) || end < start) {
2010 calc_extra_zoom_edges(start, end);
2012 temporal_zoom_by_frame (start, end);
2017 Editor::temporal_zoom_by_frame (framepos_t start, framepos_t end)
2019 if (!_session) return;
2021 if ((start == 0 && end == 0) || end < start) {
2025 framepos_t range = end - start;
2027 const framecnt_t new_fpp = (framecnt_t) ceil ((double) range / (double) _visible_canvas_width);
2029 framepos_t new_page = range;
2030 framepos_t middle = (framepos_t) floor ((double) start + ((double) range / 2.0f));
2031 framepos_t new_leftmost = (framepos_t) floor ((double) middle - ((double) new_page / 2.0f));
2033 if (new_leftmost > middle) {
2037 if (new_leftmost < 0) {
2041 reposition_and_zoom (new_leftmost, new_fpp);
2045 Editor::temporal_zoom_to_frame (bool coarser, framepos_t frame)
2051 framecnt_t range_before = frame - leftmost_frame;
2055 if (samples_per_pixel <= 1) {
2058 new_spp = samples_per_pixel + (samples_per_pixel/2);
2060 range_before += range_before/2;
2062 if (samples_per_pixel >= 1) {
2063 new_spp = samples_per_pixel - (samples_per_pixel/2);
2065 /* could bail out here since we cannot zoom any finer,
2066 but leave that to the equality test below
2068 new_spp = samples_per_pixel;
2071 range_before -= range_before/2;
2074 if (new_spp == samples_per_pixel) {
2078 /* zoom focus is automatically taken as @param frame when this
2082 framepos_t new_leftmost = frame - (framepos_t)range_before;
2084 if (new_leftmost > frame) {
2088 if (new_leftmost < 0) {
2092 reposition_and_zoom (new_leftmost, new_spp);
2097 Editor::choose_new_marker_name(string &name) {
2099 if (!UIConfiguration::instance().get_name_new_markers()) {
2100 /* don't prompt user for a new name */
2104 ArdourPrompter dialog (true);
2106 dialog.set_prompt (_("New Name:"));
2108 dialog.set_title (_("New Location Marker"));
2110 dialog.set_name ("MarkNameWindow");
2111 dialog.set_size_request (250, -1);
2112 dialog.set_position (Gtk::WIN_POS_MOUSE);
2114 dialog.add_button (Stock::OK, RESPONSE_ACCEPT);
2115 dialog.set_initial_text (name);
2119 switch (dialog.run ()) {
2120 case RESPONSE_ACCEPT:
2126 dialog.get_result(name);
2133 Editor::add_location_from_selection ()
2137 if (selection->time.empty()) {
2141 if (_session == 0 || clicked_axisview == 0) {
2145 framepos_t start = selection->time[clicked_selection].start;
2146 framepos_t end = selection->time[clicked_selection].end;
2148 _session->locations()->next_available_name(rangename,"selection");
2149 Location *location = new Location (*_session, start, end, rangename, Location::IsRangeMarker, get_grid_music_divisions(0));
2151 begin_reversible_command (_("add marker"));
2153 XMLNode &before = _session->locations()->get_state();
2154 _session->locations()->add (location, true);
2155 XMLNode &after = _session->locations()->get_state();
2156 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2158 commit_reversible_command ();
2162 Editor::add_location_mark (framepos_t where)
2166 select_new_marker = true;
2168 _session->locations()->next_available_name(markername,"mark");
2169 if (!choose_new_marker_name(markername)) {
2172 Location *location = new Location (*_session, where, where, markername, Location::IsMark, get_grid_music_divisions (0));
2173 begin_reversible_command (_("add marker"));
2175 XMLNode &before = _session->locations()->get_state();
2176 _session->locations()->add (location, true);
2177 XMLNode &after = _session->locations()->get_state();
2178 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2180 commit_reversible_command ();
2184 Editor::set_session_start_from_playhead ()
2190 if ((loc = _session->locations()->session_range_location()) == 0) { //should never happen
2191 _session->set_session_extents ( _session->audible_frame(), _session->audible_frame() );
2193 XMLNode &before = loc->get_state();
2195 _session->set_session_extents ( _session->audible_frame(), loc->end() );
2197 XMLNode &after = loc->get_state();
2199 begin_reversible_command (_("Set session start"));
2201 _session->add_command (new MementoCommand<Location>(*loc, &before, &after));
2203 commit_reversible_command ();
2208 Editor::set_session_end_from_playhead ()
2214 if ((loc = _session->locations()->session_range_location()) == 0) { //should never happen
2215 _session->set_session_extents ( _session->audible_frame(), _session->audible_frame() );
2217 XMLNode &before = loc->get_state();
2219 _session->set_session_extents ( loc->start(), _session->audible_frame() );
2221 XMLNode &after = loc->get_state();
2223 begin_reversible_command (_("Set session start"));
2225 _session->add_command (new MementoCommand<Location>(*loc, &before, &after));
2227 commit_reversible_command ();
2230 _session->set_end_is_free (false);
2235 Editor::toggle_location_at_playhead_cursor ()
2237 if (!do_remove_location_at_playhead_cursor())
2239 add_location_from_playhead_cursor();
2244 Editor::add_location_from_playhead_cursor ()
2246 add_location_mark (_session->audible_frame());
2250 Editor::do_remove_location_at_playhead_cursor ()
2252 bool removed = false;
2255 XMLNode &before = _session->locations()->get_state();
2257 //find location(s) at this time
2258 Locations::LocationList locs;
2259 _session->locations()->find_all_between (_session->audible_frame(), _session->audible_frame()+1, locs, Location::Flags(0));
2260 for (Locations::LocationList::iterator i = locs.begin(); i != locs.end(); ++i) {
2261 if ((*i)->is_mark()) {
2262 _session->locations()->remove (*i);
2269 begin_reversible_command (_("remove marker"));
2270 XMLNode &after = _session->locations()->get_state();
2271 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2272 commit_reversible_command ();
2279 Editor::remove_location_at_playhead_cursor ()
2281 do_remove_location_at_playhead_cursor ();
2284 /** Add a range marker around each selected region */
2286 Editor::add_locations_from_region ()
2288 RegionSelection rs = get_regions_from_selection_and_entered ();
2293 bool commit = false;
2295 XMLNode &before = _session->locations()->get_state();
2297 for (RegionSelection::iterator i = rs.begin (); i != rs.end (); ++i) {
2299 boost::shared_ptr<Region> region = (*i)->region ();
2301 Location *location = new Location (*_session, region->position(), region->last_frame(), region->name(), Location::IsRangeMarker, 0);
2303 _session->locations()->add (location, true);
2308 begin_reversible_command (selection->regions.size () > 1 ? _("add markers") : _("add marker"));
2309 XMLNode &after = _session->locations()->get_state();
2310 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2311 commit_reversible_command ();
2315 /** Add a single range marker around all selected regions */
2317 Editor::add_location_from_region ()
2319 RegionSelection rs = get_regions_from_selection_and_entered ();
2325 XMLNode &before = _session->locations()->get_state();
2329 if (rs.size() > 1) {
2330 _session->locations()->next_available_name(markername, "regions");
2332 RegionView* rv = *(rs.begin());
2333 boost::shared_ptr<Region> region = rv->region();
2334 markername = region->name();
2337 if (!choose_new_marker_name(markername)) {
2341 // single range spanning all selected
2342 Location *location = new Location (*_session, selection->regions.start(), selection->regions.end_frame(), markername, Location::IsRangeMarker, 0);
2343 _session->locations()->add (location, true);
2345 begin_reversible_command (_("add marker"));
2346 XMLNode &after = _session->locations()->get_state();
2347 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2348 commit_reversible_command ();
2354 Editor::jump_forward_to_mark ()
2360 framepos_t pos = _session->locations()->first_mark_after (playhead_cursor->current_frame());
2366 _session->request_locate (pos, _session->transport_rolling());
2370 Editor::jump_backward_to_mark ()
2376 framepos_t pos = _session->locations()->first_mark_before (playhead_cursor->current_frame());
2378 //handle the case where we are rolling, and we're less than one-half second past the mark, we want to go to the prior mark...
2379 if ( _session->transport_rolling() ) {
2380 if ( (playhead_cursor->current_frame() - pos) < _session->frame_rate()/2 ) {
2381 framepos_t prior = _session->locations()->first_mark_before ( pos );
2390 _session->request_locate (pos, _session->transport_rolling());
2396 framepos_t const pos = _session->audible_frame ();
2399 _session->locations()->next_available_name (markername, "mark");
2401 if (!choose_new_marker_name (markername)) {
2405 _session->locations()->add (new Location (*_session, pos, 0, markername, Location::IsMark, 0), true);
2409 Editor::clear_markers ()
2412 begin_reversible_command (_("clear markers"));
2414 XMLNode &before = _session->locations()->get_state();
2415 _session->locations()->clear_markers ();
2416 XMLNode &after = _session->locations()->get_state();
2417 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2419 commit_reversible_command ();
2424 Editor::clear_ranges ()
2427 begin_reversible_command (_("clear ranges"));
2429 XMLNode &before = _session->locations()->get_state();
2431 _session->locations()->clear_ranges ();
2433 XMLNode &after = _session->locations()->get_state();
2434 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2436 commit_reversible_command ();
2441 Editor::clear_locations ()
2443 begin_reversible_command (_("clear locations"));
2445 XMLNode &before = _session->locations()->get_state();
2446 _session->locations()->clear ();
2447 XMLNode &after = _session->locations()->get_state();
2448 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2450 commit_reversible_command ();
2454 Editor::unhide_markers ()
2456 for (LocationMarkerMap::iterator i = location_markers.begin(); i != location_markers.end(); ++i) {
2457 Location *l = (*i).first;
2458 if (l->is_hidden() && l->is_mark()) {
2459 l->set_hidden(false, this);
2465 Editor::unhide_ranges ()
2467 for (LocationMarkerMap::iterator i = location_markers.begin(); i != location_markers.end(); ++i) {
2468 Location *l = (*i).first;
2469 if (l->is_hidden() && l->is_range_marker()) {
2470 l->set_hidden(false, this);
2475 /* INSERT/REPLACE */
2478 Editor::insert_region_list_selection (float times)
2480 RouteTimeAxisView *tv = 0;
2481 boost::shared_ptr<Playlist> playlist;
2483 if (clicked_routeview != 0) {
2484 tv = clicked_routeview;
2485 } else if (!selection->tracks.empty()) {
2486 if ((tv = dynamic_cast<RouteTimeAxisView*>(selection->tracks.front())) == 0) {
2489 } else if (entered_track != 0) {
2490 if ((tv = dynamic_cast<RouteTimeAxisView*>(entered_track)) == 0) {
2497 if ((playlist = tv->playlist()) == 0) {
2501 boost::shared_ptr<Region> region = _regions->get_single_selection ();
2506 begin_reversible_command (_("insert region"));
2507 playlist->clear_changes ();
2508 playlist->add_region ((RegionFactory::create (region, true)), get_preferred_edit_position(), times);
2509 if (Config->get_edit_mode() == Ripple)
2510 playlist->ripple (get_preferred_edit_position(), region->length() * times, boost::shared_ptr<Region>());
2512 _session->add_command(new StatefulDiffCommand (playlist));
2513 commit_reversible_command ();
2516 /* BUILT-IN EFFECTS */
2519 Editor::reverse_selection ()
2524 /* GAIN ENVELOPE EDITING */
2527 Editor::edit_envelope ()
2534 Editor::transition_to_rolling (bool fwd)
2540 if (_session->config.get_external_sync()) {
2541 switch (Config->get_sync_source()) {
2545 /* transport controlled by the master */
2550 if (_session->is_auditioning()) {
2551 _session->cancel_audition ();
2555 _session->request_transport_speed (fwd ? 1.0f : -1.0f);
2559 Editor::play_from_start ()
2561 _session->request_locate (_session->current_start_frame(), true);
2565 Editor::play_from_edit_point ()
2567 _session->request_locate (get_preferred_edit_position(), true);
2571 Editor::play_from_edit_point_and_return ()
2573 framepos_t start_frame;
2574 framepos_t return_frame;
2576 start_frame = get_preferred_edit_position ( EDIT_IGNORE_PHEAD );
2578 if (_session->transport_rolling()) {
2579 _session->request_locate (start_frame, false);
2583 /* don't reset the return frame if its already set */
2585 if ((return_frame = _session->requested_return_frame()) < 0) {
2586 return_frame = _session->audible_frame();
2589 if (start_frame >= 0) {
2590 _session->request_roll_at_and_return (start_frame, return_frame);
2595 Editor::play_selection ()
2597 framepos_t start, end;
2598 if (!get_selection_extents ( start, end))
2601 AudioRange ar (start, end, 0);
2602 list<AudioRange> lar;
2605 _session->request_play_range (&lar, true);
2610 Editor::maybe_locate_with_edit_preroll (framepos_t location)
2612 if ( _session->transport_rolling() || !UIConfiguration::instance().get_follow_edits() || _session->config.get_external_sync() )
2615 location -= _session->preroll_samples (location);
2617 //don't try to locate before the beginning of time
2622 //if follow_playhead is on, keep the playhead on the screen
2623 if ( _follow_playhead )
2624 if ( location < leftmost_frame )
2625 location = leftmost_frame;
2627 _session->request_locate( location );
2631 Editor::play_with_preroll ()
2633 framepos_t start, end;
2634 if ( UIConfiguration::instance().get_follow_edits() && get_selection_extents ( start, end) ) {
2635 const framepos_t preroll = _session->preroll_samples (start);
2637 framepos_t ret = start;
2639 if (start > preroll) {
2640 start = start - preroll;
2643 end = end + preroll; //"post-roll"
2645 AudioRange ar (start, end, 0);
2646 list<AudioRange> lar;
2649 _session->request_play_range (&lar, true);
2650 _session->set_requested_return_frame (ret); //force auto-return to return to range start, without the preroll
2652 framepos_t ph = playhead_cursor->current_frame ();
2653 const framepos_t preroll = _session->preroll_samples (ph);
2656 start = ph - preroll;
2660 _session->request_locate (start, true);
2661 _session->set_requested_return_frame (ph); //force auto-return to return to playhead location, without the preroll
2666 Editor::rec_with_preroll ()
2668 framepos_t ph = playhead_cursor->current_frame ();
2669 framepos_t preroll = _session->preroll_samples (ph);
2670 _session->request_preroll_record_trim (ph, preroll);
2674 Editor::rec_with_count_in ()
2676 _session->request_count_in_record ();
2680 Editor::play_location (Location& location)
2682 if (location.start() <= location.end()) {
2686 _session->request_bounded_roll (location.start(), location.end());
2690 Editor::loop_location (Location& location)
2692 if (location.start() <= location.end()) {
2698 if ((tll = transport_loop_location()) != 0) {
2699 tll->set (location.start(), location.end());
2701 // enable looping, reposition and start rolling
2702 _session->request_locate (tll->start(), true);
2703 _session->request_play_loop (true);
2708 Editor::do_layer_operation (LayerOperation op)
2710 if (selection->regions.empty ()) {
2714 bool const multiple = selection->regions.size() > 1;
2718 begin_reversible_command (_("raise regions"));
2720 begin_reversible_command (_("raise region"));
2726 begin_reversible_command (_("raise regions to top"));
2728 begin_reversible_command (_("raise region to top"));
2734 begin_reversible_command (_("lower regions"));
2736 begin_reversible_command (_("lower region"));
2742 begin_reversible_command (_("lower regions to bottom"));
2744 begin_reversible_command (_("lower region"));
2749 set<boost::shared_ptr<Playlist> > playlists = selection->regions.playlists ();
2750 for (set<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
2751 (*i)->clear_owned_changes ();
2754 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
2755 boost::shared_ptr<Region> r = (*i)->region ();
2767 r->lower_to_bottom ();
2771 for (set<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
2772 vector<Command*> cmds;
2774 _session->add_commands (cmds);
2777 commit_reversible_command ();
2781 Editor::raise_region ()
2783 do_layer_operation (Raise);
2787 Editor::raise_region_to_top ()
2789 do_layer_operation (RaiseToTop);
2793 Editor::lower_region ()
2795 do_layer_operation (Lower);
2799 Editor::lower_region_to_bottom ()
2801 do_layer_operation (LowerToBottom);
2804 /** Show the region editor for the selected regions */
2806 Editor::show_region_properties ()
2808 selection->foreach_regionview (&RegionView::show_region_editor);
2811 /** Show the midi list editor for the selected MIDI regions */
2813 Editor::show_midi_list_editor ()
2815 selection->foreach_midi_regionview (&MidiRegionView::show_list_editor);
2819 Editor::rename_region ()
2821 RegionSelection rs = get_regions_from_selection_and_entered ();
2827 ArdourDialog d (_("Rename Region"), true, false);
2829 Label label (_("New name:"));
2832 hbox.set_spacing (6);
2833 hbox.pack_start (label, false, false);
2834 hbox.pack_start (entry, true, true);
2836 d.get_vbox()->set_border_width (12);
2837 d.get_vbox()->pack_start (hbox, false, false);
2839 d.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
2840 d.add_button(Gtk::Stock::OK, Gtk::RESPONSE_OK);
2842 d.set_size_request (300, -1);
2844 entry.set_text (rs.front()->region()->name());
2845 entry.select_region (0, -1);
2847 entry.signal_activate().connect (sigc::bind (sigc::mem_fun (d, &Dialog::response), RESPONSE_OK));
2853 int const ret = d.run();
2857 if (ret != RESPONSE_OK) {
2861 std::string str = entry.get_text();
2862 strip_whitespace_edges (str);
2864 rs.front()->region()->set_name (str);
2865 _regions->redisplay ();
2869 /** Start an audition of the first selected region */
2871 Editor::play_edit_range ()
2873 framepos_t start, end;
2875 if (get_edit_op_range (start, end)) {
2876 _session->request_bounded_roll (start, end);
2881 Editor::play_selected_region ()
2883 framepos_t start = max_framepos;
2886 RegionSelection rs = get_regions_from_selection_and_entered ();
2892 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
2893 if ((*i)->region()->position() < start) {
2894 start = (*i)->region()->position();
2896 if ((*i)->region()->last_frame() + 1 > end) {
2897 end = (*i)->region()->last_frame() + 1;
2901 _session->request_bounded_roll (start, end);
2905 Editor::audition_playlist_region_standalone (boost::shared_ptr<Region> region)
2907 _session->audition_region (region);
2911 Editor::region_from_selection ()
2913 if (clicked_axisview == 0) {
2917 if (selection->time.empty()) {
2921 framepos_t start = selection->time[clicked_selection].start;
2922 framepos_t end = selection->time[clicked_selection].end;
2924 TrackViewList tracks = get_tracks_for_range_action ();
2926 framepos_t selection_cnt = end - start + 1;
2928 for (TrackSelection::iterator i = tracks.begin(); i != tracks.end(); ++i) {
2929 boost::shared_ptr<Region> current;
2930 boost::shared_ptr<Playlist> pl;
2931 framepos_t internal_start;
2934 if ((pl = (*i)->playlist()) == 0) {
2938 if ((current = pl->top_region_at (start)) == 0) {
2942 internal_start = start - current->position();
2943 RegionFactory::region_name (new_name, current->name(), true);
2947 plist.add (ARDOUR::Properties::start, current->start() + internal_start);
2948 plist.add (ARDOUR::Properties::length, selection_cnt);
2949 plist.add (ARDOUR::Properties::name, new_name);
2950 plist.add (ARDOUR::Properties::layer, 0);
2952 boost::shared_ptr<Region> region (RegionFactory::create (current, plist));
2957 Editor::create_region_from_selection (vector<boost::shared_ptr<Region> >& new_regions)
2959 if (selection->time.empty() || selection->tracks.empty()) {
2963 framepos_t start, end;
2964 if (clicked_selection) {
2965 start = selection->time[clicked_selection].start;
2966 end = selection->time[clicked_selection].end;
2968 start = selection->time.start();
2969 end = selection->time.end_frame();
2972 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
2973 sort_track_selection (ts);
2975 for (TrackSelection::iterator i = ts.begin(); i != ts.end(); ++i) {
2976 boost::shared_ptr<Region> current;
2977 boost::shared_ptr<Playlist> playlist;
2978 framepos_t internal_start;
2981 if ((playlist = (*i)->playlist()) == 0) {
2985 if ((current = playlist->top_region_at(start)) == 0) {
2989 internal_start = start - current->position();
2990 RegionFactory::region_name (new_name, current->name(), true);
2994 plist.add (ARDOUR::Properties::start, current->start() + internal_start);
2995 plist.add (ARDOUR::Properties::length, end - start + 1);
2996 plist.add (ARDOUR::Properties::name, new_name);
2998 new_regions.push_back (RegionFactory::create (current, plist));
3003 Editor::split_multichannel_region ()
3005 RegionSelection rs = get_regions_from_selection_and_entered ();
3011 vector< boost::shared_ptr<Region> > v;
3013 for (list<RegionView*>::iterator x = rs.begin(); x != rs.end(); ++x) {
3014 (*x)->region()->separate_by_channel (*_session, v);
3019 Editor::new_region_from_selection ()
3021 region_from_selection ();
3022 cancel_selection ();
3026 add_if_covered (RegionView* rv, const AudioRange* ar, RegionSelection* rs)
3028 switch (rv->region()->coverage (ar->start, ar->end - 1)) {
3029 // n.b. -1 because AudioRange::end is one past the end, but coverage expects inclusive ranges
3030 case Evoral::OverlapNone:
3038 * - selected tracks, or if there are none...
3039 * - tracks containing selected regions, or if there are none...
3044 Editor::get_tracks_for_range_action () const
3048 if (selection->tracks.empty()) {
3050 /* use tracks with selected regions */
3052 RegionSelection rs = selection->regions;
3054 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3055 TimeAxisView* tv = &(*i)->get_time_axis_view();
3057 if (!t.contains (tv)) {
3063 /* no regions and no tracks: use all tracks */
3069 t = selection->tracks;
3072 return t.filter_to_unique_playlists();
3076 Editor::separate_regions_between (const TimeSelection& ts)
3078 bool in_command = false;
3079 boost::shared_ptr<Playlist> playlist;
3080 RegionSelection new_selection;
3082 TrackViewList tmptracks = get_tracks_for_range_action ();
3083 sort_track_selection (tmptracks);
3085 for (TrackSelection::iterator i = tmptracks.begin(); i != tmptracks.end(); ++i) {
3087 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> ((*i));
3093 if (!rtv->is_track()) {
3097 /* no edits to destructive tracks */
3099 if (rtv->track()->destructive()) {
3103 if ((playlist = rtv->playlist()) != 0) {
3105 playlist->clear_changes ();
3107 /* XXX need to consider musical time selections here at some point */
3109 double speed = rtv->track()->speed();
3111 for (list<AudioRange>::const_iterator t = ts.begin(); t != ts.end(); ++t) {
3113 sigc::connection c = rtv->view()->RegionViewAdded.connect (
3114 sigc::mem_fun(*this, &Editor::collect_new_region_view));
3116 latest_regionviews.clear ();
3118 playlist->partition ((framepos_t)((*t).start * speed),
3119 (framepos_t)((*t).end * speed), false);
3123 if (!latest_regionviews.empty()) {
3125 rtv->view()->foreach_regionview (sigc::bind (
3126 sigc::ptr_fun (add_if_covered),
3127 &(*t), &new_selection));
3130 begin_reversible_command (_("separate"));
3134 /* pick up changes to existing regions */
3136 vector<Command*> cmds;
3137 playlist->rdiff (cmds);
3138 _session->add_commands (cmds);
3140 /* pick up changes to the playlist itself (adds/removes)
3143 _session->add_command(new StatefulDiffCommand (playlist));
3150 // selection->set (new_selection);
3152 commit_reversible_command ();
3156 struct PlaylistState {
3157 boost::shared_ptr<Playlist> playlist;
3161 /** Take tracks from get_tracks_for_range_action and cut any regions
3162 * on those tracks so that the tracks are empty over the time
3166 Editor::separate_region_from_selection ()
3168 /* preferentially use *all* ranges in the time selection if we're in range mode
3169 to allow discontiguous operation, since get_edit_op_range() currently
3170 returns a single range.
3173 if (!selection->time.empty()) {
3175 separate_regions_between (selection->time);
3182 if (get_edit_op_range (start, end)) {
3184 AudioRange ar (start, end, 1);
3188 separate_regions_between (ts);
3194 Editor::separate_region_from_punch ()
3196 Location* loc = _session->locations()->auto_punch_location();
3198 separate_regions_using_location (*loc);
3203 Editor::separate_region_from_loop ()
3205 Location* loc = _session->locations()->auto_loop_location();
3207 separate_regions_using_location (*loc);
3212 Editor::separate_regions_using_location (Location& loc)
3214 if (loc.is_mark()) {
3218 AudioRange ar (loc.start(), loc.end(), 1);
3223 separate_regions_between (ts);
3226 /** Separate regions under the selected region */
3228 Editor::separate_under_selected_regions ()
3230 vector<PlaylistState> playlists;
3234 rs = get_regions_from_selection_and_entered();
3236 if (!_session || rs.empty()) {
3240 begin_reversible_command (_("separate region under"));
3242 list<boost::shared_ptr<Region> > regions_to_remove;
3244 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3245 // we can't just remove the region(s) in this loop because
3246 // this removes them from the RegionSelection, and they thus
3247 // disappear from underneath the iterator, and the ++i above
3248 // SEGVs in a puzzling fashion.
3250 // so, first iterate over the regions to be removed from rs and
3251 // add them to the regions_to_remove list, and then
3252 // iterate over the list to actually remove them.
3254 regions_to_remove.push_back ((*i)->region());
3257 for (list<boost::shared_ptr<Region> >::iterator rl = regions_to_remove.begin(); rl != regions_to_remove.end(); ++rl) {
3259 boost::shared_ptr<Playlist> playlist = (*rl)->playlist();
3262 // is this check necessary?
3266 vector<PlaylistState>::iterator i;
3268 //only take state if this is a new playlist.
3269 for (i = playlists.begin(); i != playlists.end(); ++i) {
3270 if ((*i).playlist == playlist) {
3275 if (i == playlists.end()) {
3277 PlaylistState before;
3278 before.playlist = playlist;
3279 before.before = &playlist->get_state();
3281 playlist->freeze ();
3282 playlists.push_back(before);
3285 //Partition on the region bounds
3286 playlist->partition ((*rl)->first_frame() - 1, (*rl)->last_frame() + 1, true);
3288 //Re-add region that was just removed due to the partition operation
3289 playlist->add_region( (*rl), (*rl)->first_frame() );
3292 vector<PlaylistState>::iterator pl;
3294 for (pl = playlists.begin(); pl != playlists.end(); ++pl) {
3295 (*pl).playlist->thaw ();
3296 _session->add_command(new MementoCommand<Playlist>(*(*pl).playlist, (*pl).before, &(*pl).playlist->get_state()));
3299 commit_reversible_command ();
3303 Editor::crop_region_to_selection ()
3305 if (!selection->time.empty()) {
3307 crop_region_to (selection->time.start(), selection->time.end_frame());
3314 if (get_edit_op_range (start, end)) {
3315 crop_region_to (start, end);
3322 Editor::crop_region_to (framepos_t start, framepos_t end)
3324 vector<boost::shared_ptr<Playlist> > playlists;
3325 boost::shared_ptr<Playlist> playlist;
3328 if (selection->tracks.empty()) {
3329 ts = track_views.filter_to_unique_playlists();
3331 ts = selection->tracks.filter_to_unique_playlists ();
3334 sort_track_selection (ts);
3336 for (TrackSelection::iterator i = ts.begin(); i != ts.end(); ++i) {
3338 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> ((*i));
3344 boost::shared_ptr<Track> t = rtv->track();
3346 if (t != 0 && ! t->destructive()) {
3348 if ((playlist = rtv->playlist()) != 0) {
3349 playlists.push_back (playlist);
3354 if (playlists.empty()) {
3359 framepos_t new_start;
3361 framecnt_t new_length;
3362 bool in_command = false;
3364 for (vector<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
3366 /* Only the top regions at start and end have to be cropped */
3367 boost::shared_ptr<Region> region_at_start = (*i)->top_region_at(start);
3368 boost::shared_ptr<Region> region_at_end = (*i)->top_region_at(end);
3370 vector<boost::shared_ptr<Region> > regions;
3372 if (region_at_start != 0) {
3373 regions.push_back (region_at_start);
3375 if (region_at_end != 0) {
3376 regions.push_back (region_at_end);
3379 /* now adjust lengths */
3380 for (vector<boost::shared_ptr<Region> >::iterator i = regions.begin(); i != regions.end(); ++i) {
3382 pos = (*i)->position();
3383 new_start = max (start, pos);
3384 if (max_framepos - pos > (*i)->length()) {
3385 new_end = pos + (*i)->length() - 1;
3387 new_end = max_framepos;
3389 new_end = min (end, new_end);
3390 new_length = new_end - new_start + 1;
3393 begin_reversible_command (_("trim to selection"));
3396 (*i)->clear_changes ();
3397 (*i)->trim_to (new_start, new_length);
3398 _session->add_command (new StatefulDiffCommand (*i));
3403 commit_reversible_command ();
3408 Editor::region_fill_track ()
3410 boost::shared_ptr<Playlist> playlist;
3411 RegionSelection regions = get_regions_from_selection_and_entered ();
3412 RegionSelection foo;
3414 framepos_t const end = _session->current_end_frame ();
3416 if (regions.empty () || regions.end_frame () + 1 >= end) {
3420 framepos_t const start_frame = regions.start ();
3421 framepos_t const end_frame = regions.end_frame ();
3422 framecnt_t const gap = end_frame - start_frame + 1;
3424 begin_reversible_command (Operations::region_fill);
3426 selection->clear_regions ();
3428 for (RegionSelection::iterator i = regions.begin(); i != regions.end(); ++i) {
3430 boost::shared_ptr<Region> r ((*i)->region());
3432 TimeAxisView& tv = (*i)->get_time_axis_view();
3433 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (&tv);
3434 latest_regionviews.clear ();
3435 sigc::connection c = rtv->view()->RegionViewAdded.connect (sigc::mem_fun(*this, &Editor::collect_new_region_view));
3437 framepos_t const position = end_frame + (r->first_frame() - start_frame + 1);
3438 playlist = (*i)->region()->playlist();
3439 playlist->clear_changes ();
3440 playlist->duplicate_until (r, position, gap, end);
3441 _session->add_command(new StatefulDiffCommand (playlist));
3445 foo.insert (foo.end(), latest_regionviews.begin(), latest_regionviews.end());
3449 selection->set (foo);
3452 commit_reversible_command ();
3456 Editor::set_region_sync_position ()
3458 set_sync_point (get_preferred_edit_position (), get_regions_from_selection_and_edit_point ());
3462 Editor::set_sync_point (framepos_t where, const RegionSelection& rs)
3464 bool in_command = false;
3466 for (RegionSelection::const_iterator r = rs.begin(); r != rs.end(); ++r) {
3468 if (!(*r)->region()->covers (where)) {
3472 boost::shared_ptr<Region> region ((*r)->region());
3475 begin_reversible_command (_("set sync point"));
3479 region->clear_changes ();
3480 region->set_sync_position (where);
3481 _session->add_command(new StatefulDiffCommand (region));
3485 commit_reversible_command ();
3489 /** Remove the sync positions of the selection */
3491 Editor::remove_region_sync ()
3493 RegionSelection rs = get_regions_from_selection_and_entered ();
3499 begin_reversible_command (_("remove region sync"));
3501 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3503 (*i)->region()->clear_changes ();
3504 (*i)->region()->clear_sync_position ();
3505 _session->add_command(new StatefulDiffCommand ((*i)->region()));
3508 commit_reversible_command ();
3512 Editor::naturalize_region ()
3514 RegionSelection rs = get_regions_from_selection_and_entered ();
3520 if (rs.size() > 1) {
3521 begin_reversible_command (_("move regions to original position"));
3523 begin_reversible_command (_("move region to original position"));
3526 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3527 (*i)->region()->clear_changes ();
3528 (*i)->region()->move_to_natural_position ();
3529 _session->add_command (new StatefulDiffCommand ((*i)->region()));
3532 commit_reversible_command ();
3536 Editor::align_regions (RegionPoint what)
3538 RegionSelection const rs = get_regions_from_selection_and_edit_point ();
3544 begin_reversible_command (_("align selection"));
3546 framepos_t const position = get_preferred_edit_position ();
3548 for (RegionSelection::const_iterator i = rs.begin(); i != rs.end(); ++i) {
3549 align_region_internal ((*i)->region(), what, position);
3552 commit_reversible_command ();
3555 struct RegionSortByTime {
3556 bool operator() (const RegionView* a, const RegionView* b) {
3557 return a->region()->position() < b->region()->position();
3562 Editor::align_regions_relative (RegionPoint point)
3564 RegionSelection const rs = get_regions_from_selection_and_edit_point ();
3570 framepos_t const position = get_preferred_edit_position ();
3572 framepos_t distance = 0;
3576 list<RegionView*> sorted;
3577 rs.by_position (sorted);
3579 boost::shared_ptr<Region> r ((*sorted.begin())->region());
3584 if (position > r->position()) {
3585 distance = position - r->position();
3587 distance = r->position() - position;
3593 if (position > r->last_frame()) {
3594 distance = position - r->last_frame();
3595 pos = r->position() + distance;
3597 distance = r->last_frame() - position;
3598 pos = r->position() - distance;
3604 pos = r->adjust_to_sync (position);
3605 if (pos > r->position()) {
3606 distance = pos - r->position();
3608 distance = r->position() - pos;
3614 if (pos == r->position()) {
3618 begin_reversible_command (_("align selection (relative)"));
3620 /* move first one specially */
3622 r->clear_changes ();
3623 r->set_position (pos);
3624 _session->add_command(new StatefulDiffCommand (r));
3626 /* move rest by the same amount */
3630 for (list<RegionView*>::iterator i = sorted.begin(); i != sorted.end(); ++i) {
3632 boost::shared_ptr<Region> region ((*i)->region());
3634 region->clear_changes ();
3637 region->set_position (region->position() + distance);
3639 region->set_position (region->position() - distance);
3642 _session->add_command(new StatefulDiffCommand (region));
3646 commit_reversible_command ();
3650 Editor::align_region (boost::shared_ptr<Region> region, RegionPoint point, framepos_t position)
3652 begin_reversible_command (_("align region"));
3653 align_region_internal (region, point, position);
3654 commit_reversible_command ();
3658 Editor::align_region_internal (boost::shared_ptr<Region> region, RegionPoint point, framepos_t position)
3660 region->clear_changes ();
3664 region->set_position (region->adjust_to_sync (position));
3668 if (position > region->length()) {
3669 region->set_position (position - region->length());
3674 region->set_position (position);
3678 _session->add_command(new StatefulDiffCommand (region));
3682 Editor::trim_region_front ()
3688 Editor::trim_region_back ()
3690 trim_region (false);
3694 Editor::trim_region (bool front)
3696 framepos_t where = get_preferred_edit_position();
3697 RegionSelection rs = get_regions_from_selection_and_edit_point ();
3703 begin_reversible_command (front ? _("trim front") : _("trim back"));
3705 for (list<RegionView*>::const_iterator i = rs.by_layer().begin(); i != rs.by_layer().end(); ++i) {
3706 if (!(*i)->region()->locked()) {
3708 (*i)->region()->clear_changes ();
3711 (*i)->region()->trim_front (where);
3713 (*i)->region()->trim_end (where);
3716 _session->add_command (new StatefulDiffCommand ((*i)->region()));
3720 commit_reversible_command ();
3723 /** Trim the end of the selected regions to the position of the edit cursor */
3725 Editor::trim_region_to_loop ()
3727 Location* loc = _session->locations()->auto_loop_location();
3731 trim_region_to_location (*loc, _("trim to loop"));
3735 Editor::trim_region_to_punch ()
3737 Location* loc = _session->locations()->auto_punch_location();
3741 trim_region_to_location (*loc, _("trim to punch"));
3745 Editor::trim_region_to_location (const Location& loc, const char* str)
3747 RegionSelection rs = get_regions_from_selection_and_entered ();
3748 bool in_command = false;
3750 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
3751 RegionView* rv = (*x);
3753 /* require region to span proposed trim */
3754 switch (rv->region()->coverage (loc.start(), loc.end())) {
3755 case Evoral::OverlapInternal:
3761 RouteTimeAxisView* tav = dynamic_cast<RouteTimeAxisView*> (&rv->get_time_axis_view());
3770 if (tav->track() != 0) {
3771 speed = tav->track()->speed();
3774 start = session_frame_to_track_frame (loc.start(), speed);
3775 end = session_frame_to_track_frame (loc.end(), speed);
3777 rv->region()->clear_changes ();
3778 rv->region()->trim_to (start, (end - start));
3781 begin_reversible_command (str);
3784 _session->add_command(new StatefulDiffCommand (rv->region()));
3788 commit_reversible_command ();
3793 Editor::trim_region_to_previous_region_end ()
3795 return trim_to_region(false);
3799 Editor::trim_region_to_next_region_start ()
3801 return trim_to_region(true);
3805 Editor::trim_to_region(bool forward)
3807 RegionSelection rs = get_regions_from_selection_and_entered ();
3808 bool in_command = false;
3810 boost::shared_ptr<Region> next_region;
3812 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
3814 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*x);
3820 AudioTimeAxisView* atav = dynamic_cast<AudioTimeAxisView*> (&arv->get_time_axis_view());
3828 if (atav->track() != 0) {
3829 speed = atav->track()->speed();
3833 boost::shared_ptr<Region> region = arv->region();
3834 boost::shared_ptr<Playlist> playlist (region->playlist());
3836 region->clear_changes ();
3840 next_region = playlist->find_next_region (region->first_frame(), Start, 1);
3846 region->trim_end((framepos_t) ( (next_region->first_frame() - 1) * speed));
3847 arv->region_changed (PropertyChange (ARDOUR::Properties::length));
3851 next_region = playlist->find_next_region (region->first_frame(), Start, 0);
3857 region->trim_front((framepos_t) ((next_region->last_frame() + 1) * speed));
3859 arv->region_changed (ARDOUR::bounds_change);
3863 begin_reversible_command (_("trim to region"));
3866 _session->add_command(new StatefulDiffCommand (region));
3870 commit_reversible_command ();
3875 Editor::unfreeze_route ()
3877 if (clicked_routeview == 0 || !clicked_routeview->is_track()) {
3881 clicked_routeview->track()->unfreeze ();
3885 Editor::_freeze_thread (void* arg)
3887 return static_cast<Editor*>(arg)->freeze_thread ();
3891 Editor::freeze_thread ()
3893 /* create event pool because we may need to talk to the session */
3894 SessionEvent::create_per_thread_pool ("freeze events", 64);
3895 /* create per-thread buffers for process() tree to use */
3896 clicked_routeview->audio_track()->freeze_me (*current_interthread_info);
3897 current_interthread_info->done = true;
3902 Editor::freeze_route ()
3908 /* stop transport before we start. this is important */
3910 _session->request_transport_speed (0.0);
3912 /* wait for just a little while, because the above call is asynchronous */
3914 Glib::usleep (250000);
3916 if (clicked_routeview == 0 || !clicked_routeview->is_audio_track()) {
3920 if (!clicked_routeview->track()->bounceable (clicked_routeview->track()->main_outs(), true)) {
3922 _("This track/bus cannot be frozen because the signal adds or loses channels before reaching the outputs.\n"
3923 "This is typically caused by plugins that generate stereo output from mono input or vice versa.")
3925 d.set_title (_("Cannot freeze"));
3930 if (clicked_routeview->track()->has_external_redirects()) {
3931 MessageDialog d (string_compose (_("<b>%1</b>\n\nThis track has at least one send/insert/return as part of its signal flow.\n\n"
3932 "Freezing will only process the signal as far as the first send/insert/return."),
3933 clicked_routeview->track()->name()), true, MESSAGE_INFO, BUTTONS_NONE, true);
3935 d.add_button (_("Freeze anyway"), Gtk::RESPONSE_OK);
3936 d.add_button (_("Don't freeze"), Gtk::RESPONSE_CANCEL);
3937 d.set_title (_("Freeze Limits"));
3939 int response = d.run ();
3942 case Gtk::RESPONSE_CANCEL:
3949 InterThreadInfo itt;
3950 current_interthread_info = &itt;
3952 InterthreadProgressWindow ipw (current_interthread_info, _("Freeze"), _("Cancel Freeze"));
3954 pthread_create_and_store (X_("freezer"), &itt.thread, _freeze_thread, this);
3956 CursorContext::Handle cursor_ctx = CursorContext::create(*this, _cursors->wait);
3958 while (!itt.done && !itt.cancel) {
3959 gtk_main_iteration ();
3962 pthread_join (itt.thread, 0);
3963 current_interthread_info = 0;
3967 Editor::bounce_range_selection (bool replace, bool enable_processing)
3969 if (selection->time.empty()) {
3973 TrackSelection views = selection->tracks;
3975 for (TrackViewList::iterator i = views.begin(); i != views.end(); ++i) {
3977 if (enable_processing) {
3979 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*i);
3981 if (rtv && rtv->track() && replace && enable_processing && !rtv->track()->bounceable (rtv->track()->main_outs(), false)) {
3983 _("You can't perform this operation because the processing of the signal "
3984 "will cause one or more of the tracks to end up with a region with more channels than this track has inputs.\n\n"
3985 "You can do this without processing, which is a different operation.")
3987 d.set_title (_("Cannot bounce"));
3994 framepos_t start = selection->time[clicked_selection].start;
3995 framepos_t end = selection->time[clicked_selection].end;
3996 framepos_t cnt = end - start + 1;
3997 bool in_command = false;
3999 for (TrackViewList::iterator i = views.begin(); i != views.end(); ++i) {
4001 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*i);
4007 boost::shared_ptr<Playlist> playlist;
4009 if ((playlist = rtv->playlist()) == 0) {
4013 InterThreadInfo itt;
4015 playlist->clear_changes ();
4016 playlist->clear_owned_changes ();
4018 boost::shared_ptr<Region> r;
4020 if (enable_processing) {
4021 r = rtv->track()->bounce_range (start, start+cnt, itt, rtv->track()->main_outs(), false);
4023 r = rtv->track()->bounce_range (start, start+cnt, itt, boost::shared_ptr<Processor>(), false);
4031 list<AudioRange> ranges;
4032 ranges.push_back (AudioRange (start, start+cnt, 0));
4033 playlist->cut (ranges); // discard result
4034 playlist->add_region (r, start);
4038 begin_reversible_command (_("bounce range"));
4041 vector<Command*> cmds;
4042 playlist->rdiff (cmds);
4043 _session->add_commands (cmds);
4045 _session->add_command (new StatefulDiffCommand (playlist));
4049 commit_reversible_command ();
4053 /** Delete selected regions, automation points or a time range */
4057 //special case: if the user is pointing in the editor/mixer strip, they may be trying to delete a plugin.
4058 //we need this because the editor-mixer strip is in the editor window, so it doesn't get the bindings from the mix window
4059 bool deleted = false;
4060 if ( current_mixer_strip && current_mixer_strip == MixerStrip::entered_mixer_strip() )
4061 deleted = current_mixer_strip->delete_processors ();
4067 /** Cut selected regions, automation points or a time range */
4074 /** Copy selected regions, automation points or a time range */
4082 /** @return true if a Cut, Copy or Clear is possible */
4084 Editor::can_cut_copy () const
4086 if (!selection->time.empty() || !selection->regions.empty() || !selection->points.empty())
4093 /** Cut, copy or clear selected regions, automation points or a time range.
4094 * @param op Operation (Delete, Cut, Copy or Clear)
4097 Editor::cut_copy (CutCopyOp op)
4099 /* only cancel selection if cut/copy is successful.*/
4105 opname = _("delete");
4114 opname = _("clear");
4118 /* if we're deleting something, and the mouse is still pressed,
4119 the thing we started a drag for will be gone when we release
4120 the mouse button(s). avoid this. see part 2 at the end of
4124 if (op == Delete || op == Cut || op == Clear) {
4125 if (_drags->active ()) {
4130 if ( op != Delete ) //"Delete" doesn't change copy/paste buf
4131 cut_buffer->clear ();
4133 if (entered_marker) {
4135 /* cut/delete op while pointing at a marker */
4138 Location* loc = find_location_from_marker (entered_marker, ignored);
4140 if (_session && loc) {
4141 entered_marker = NULL;
4142 Glib::signal_idle().connect (sigc::bind (sigc::mem_fun(*this, &Editor::really_remove_marker), loc));
4149 switch (mouse_mode) {
4152 begin_reversible_command (opname + ' ' + X_("MIDI"));
4154 commit_reversible_command ();
4160 bool did_edit = false;
4162 if (!selection->regions.empty() || !selection->points.empty()) {
4163 begin_reversible_command (opname + ' ' + _("objects"));
4166 if (!selection->regions.empty()) {
4167 cut_copy_regions (op, selection->regions);
4169 if (op == Cut || op == Delete) {
4170 selection->clear_regions ();
4174 if (!selection->points.empty()) {
4175 cut_copy_points (op);
4177 if (op == Cut || op == Delete) {
4178 selection->clear_points ();
4181 } else if (selection->time.empty()) {
4182 framepos_t start, end;
4183 /* no time selection, see if we can get an edit range
4186 if (get_edit_op_range (start, end)) {
4187 selection->set (start, end);
4189 } else if (!selection->time.empty()) {
4190 begin_reversible_command (opname + ' ' + _("range"));
4193 cut_copy_ranges (op);
4195 if (op == Cut || op == Delete) {
4196 selection->clear_time ();
4201 /* reset repeated paste state */
4204 commit_reversible_command ();
4207 if (op == Delete || op == Cut || op == Clear) {
4213 struct AutomationRecord {
4214 AutomationRecord () : state (0) , line(NULL) {}
4215 AutomationRecord (XMLNode* s, const AutomationLine* l) : state (s) , line (l) {}
4217 XMLNode* state; ///< state before any operation
4218 const AutomationLine* line; ///< line this came from
4219 boost::shared_ptr<Evoral::ControlList> copy; ///< copied events for the cut buffer
4221 struct PointsSelectionPositionSorter {
4222 bool operator() (ControlPoint* a, ControlPoint* b) {
4223 return (*(a->model()))->when < (*(b->model()))->when;
4226 /** Cut, copy or clear selected automation points.
4227 * @param op Operation (Cut, Copy or Clear)
4230 Editor::cut_copy_points (Editing::CutCopyOp op, Evoral::Beats earliest, bool midi)
4232 if (selection->points.empty ()) {
4236 /* XXX: not ideal, as there may be more than one track involved in the point selection */
4237 _last_cut_copy_source_track = &selection->points.front()->line().trackview;
4239 /* Keep a record of the AutomationLists that we end up using in this operation */
4240 typedef std::map<boost::shared_ptr<AutomationList>, AutomationRecord> Lists;
4243 /* user could select points in any order */
4244 selection->points.sort(PointsSelectionPositionSorter ());
4246 /* Go through all selected points, making an AutomationRecord for each distinct AutomationList */
4247 for (PointSelection::iterator sel_point = selection->points.begin(); sel_point != selection->points.end(); ++sel_point) {
4248 const AutomationLine& line = (*sel_point)->line();
4249 const boost::shared_ptr<AutomationList> al = line.the_list();
4250 if (lists.find (al) == lists.end ()) {
4251 /* We haven't seen this list yet, so make a record for it. This includes
4252 taking a copy of its current state, in case this is needed for undo later.
4254 lists[al] = AutomationRecord (&al->get_state (), &line);
4258 if (op == Cut || op == Copy) {
4259 /* This operation will involve putting things in the cut buffer, so create an empty
4260 ControlList for each of our source lists to put the cut buffer data in.
4262 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
4263 i->second.copy = i->first->create (i->first->parameter (), i->first->descriptor());
4266 /* Add all selected points to the relevant copy ControlLists */
4267 MusicFrame start (std::numeric_limits<framepos_t>::max(), 0);
4268 for (PointSelection::iterator sel_point = selection->points.begin(); sel_point != selection->points.end(); ++sel_point) {
4269 boost::shared_ptr<AutomationList> al = (*sel_point)->line().the_list();
4270 AutomationList::const_iterator ctrl_evt = (*sel_point)->model ();
4272 lists[al].copy->fast_simple_add ((*ctrl_evt)->when, (*ctrl_evt)->value);
4274 /* Update earliest MIDI start time in beats */
4275 earliest = std::min(earliest, Evoral::Beats((*ctrl_evt)->when));
4277 /* Update earliest session start time in frames */
4278 start.frame = std::min(start.frame, (*sel_point)->line().session_position(ctrl_evt));
4282 /* Snap start time backwards, so copy/paste is snap aligned. */
4284 if (earliest == Evoral::Beats::max()) {
4285 earliest = Evoral::Beats(); // Weird... don't offset
4287 earliest.round_down_to_beat();
4289 if (start.frame == std::numeric_limits<double>::max()) {
4290 start.frame = 0; // Weird... don't offset
4292 snap_to(start, RoundDownMaybe);
4295 const double line_offset = midi ? earliest.to_double() : start.frame;
4296 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
4297 /* Correct this copy list so that it is relative to the earliest
4298 start time, so relative ordering between points is preserved
4299 when copying from several lists and the paste starts at the
4300 earliest copied piece of data. */
4301 boost::shared_ptr<Evoral::ControlList> &al_cpy = i->second.copy;
4302 for (AutomationList::iterator ctrl_evt = al_cpy->begin(); ctrl_evt != al_cpy->end(); ++ctrl_evt) {
4303 (*ctrl_evt)->when -= line_offset;
4306 /* And add it to the cut buffer */
4307 cut_buffer->add (al_cpy);
4311 if (op == Delete || op == Cut) {
4312 /* This operation needs to remove things from the main AutomationList, so do that now */
4314 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
4315 i->first->freeze ();
4318 /* Remove each selected point from its AutomationList */
4319 for (PointSelection::iterator sel_point = selection->points.begin(); sel_point != selection->points.end(); ++sel_point) {
4320 AutomationLine& line = (*sel_point)->line ();
4321 boost::shared_ptr<AutomationList> al = line.the_list();
4325 if (dynamic_cast<AudioRegionGainLine*> (&line)) {
4326 /* removing of first and last gain point in region gain lines is prohibited*/
4327 if (line.is_last_point (*(*sel_point)) || line.is_first_point (*(*sel_point))) {
4333 al->erase ((*sel_point)->model ());
4337 /* Thaw the lists and add undo records for them */
4338 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
4339 boost::shared_ptr<AutomationList> al = i->first;
4341 _session->add_command (new MementoCommand<AutomationList> (*al.get(), i->second.state, &(al->get_state ())));
4346 /** Cut, copy or clear selected automation points.
4347 * @param op Operation (Cut, Copy or Clear)
4350 Editor::cut_copy_midi (CutCopyOp op)
4352 Evoral::Beats earliest = Evoral::Beats::max();
4353 for (MidiRegionSelection::iterator i = selection->midi_regions.begin(); i != selection->midi_regions.end(); ++i) {
4354 MidiRegionView* mrv = dynamic_cast<MidiRegionView*>(*i);
4356 if (!mrv->selection().empty()) {
4357 earliest = std::min(earliest, (*mrv->selection().begin())->note()->time());
4359 mrv->cut_copy_clear (op);
4361 /* XXX: not ideal, as there may be more than one track involved in the selection */
4362 _last_cut_copy_source_track = &mrv->get_time_axis_view();
4366 if (!selection->points.empty()) {
4367 cut_copy_points (op, earliest, true);
4368 if (op == Cut || op == Delete) {
4369 selection->clear_points ();
4374 struct lt_playlist {
4375 bool operator () (const PlaylistState& a, const PlaylistState& b) {
4376 return a.playlist < b.playlist;
4380 struct PlaylistMapping {
4382 boost::shared_ptr<Playlist> pl;
4384 PlaylistMapping (TimeAxisView* tvp) : tv (tvp) {}
4387 /** Remove `clicked_regionview' */
4389 Editor::remove_clicked_region ()
4391 if (clicked_routeview == 0 || clicked_regionview == 0) {
4395 begin_reversible_command (_("remove region"));
4397 boost::shared_ptr<Playlist> playlist = clicked_routeview->playlist();
4399 playlist->clear_changes ();
4400 playlist->clear_owned_changes ();
4401 playlist->remove_region (clicked_regionview->region());
4402 if (Config->get_edit_mode() == Ripple)
4403 playlist->ripple (clicked_regionview->region()->position(), -clicked_regionview->region()->length(), boost::shared_ptr<Region>());
4405 /* We might have removed regions, which alters other regions' layering_index,
4406 so we need to do a recursive diff here.
4408 vector<Command*> cmds;
4409 playlist->rdiff (cmds);
4410 _session->add_commands (cmds);
4412 _session->add_command(new StatefulDiffCommand (playlist));
4413 commit_reversible_command ();
4417 /** Remove the selected regions */
4419 Editor::remove_selected_regions ()
4421 RegionSelection rs = get_regions_from_selection_and_entered ();
4423 if (!_session || rs.empty()) {
4427 list<boost::shared_ptr<Region> > regions_to_remove;
4429 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
4430 // we can't just remove the region(s) in this loop because
4431 // this removes them from the RegionSelection, and they thus
4432 // disappear from underneath the iterator, and the ++i above
4433 // SEGVs in a puzzling fashion.
4435 // so, first iterate over the regions to be removed from rs and
4436 // add them to the regions_to_remove list, and then
4437 // iterate over the list to actually remove them.
4439 regions_to_remove.push_back ((*i)->region());
4442 vector<boost::shared_ptr<Playlist> > playlists;
4444 for (list<boost::shared_ptr<Region> >::iterator rl = regions_to_remove.begin(); rl != regions_to_remove.end(); ++rl) {
4446 boost::shared_ptr<Playlist> playlist = (*rl)->playlist();
4449 // is this check necessary?
4453 /* get_regions_from_selection_and_entered() guarantees that
4454 the playlists involved are unique, so there is no need
4458 playlists.push_back (playlist);
4460 playlist->clear_changes ();
4461 playlist->clear_owned_changes ();
4462 playlist->freeze ();
4463 playlist->remove_region (*rl);
4464 if (Config->get_edit_mode() == Ripple)
4465 playlist->ripple ((*rl)->position(), -(*rl)->length(), boost::shared_ptr<Region>());
4469 vector<boost::shared_ptr<Playlist> >::iterator pl;
4470 bool in_command = false;
4472 for (pl = playlists.begin(); pl != playlists.end(); ++pl) {
4475 /* We might have removed regions, which alters other regions' layering_index,
4476 so we need to do a recursive diff here.
4480 begin_reversible_command (_("remove region"));
4483 vector<Command*> cmds;
4484 (*pl)->rdiff (cmds);
4485 _session->add_commands (cmds);
4487 _session->add_command(new StatefulDiffCommand (*pl));
4491 commit_reversible_command ();
4495 /** Cut, copy or clear selected regions.
4496 * @param op Operation (Cut, Copy or Clear)
4499 Editor::cut_copy_regions (CutCopyOp op, RegionSelection& rs)
4501 /* we can't use a std::map here because the ordering is important, and we can't trivially sort
4502 a map when we want ordered access to both elements. i think.
4505 vector<PlaylistMapping> pmap;
4507 framepos_t first_position = max_framepos;
4509 typedef set<boost::shared_ptr<Playlist> > FreezeList;
4510 FreezeList freezelist;
4512 /* get ordering correct before we cut/copy */
4514 rs.sort_by_position_and_track ();
4516 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
4518 first_position = min ((framepos_t) (*x)->region()->position(), first_position);
4520 if (op == Cut || op == Clear || op == Delete) {
4521 boost::shared_ptr<Playlist> pl = (*x)->region()->playlist();
4524 FreezeList::iterator fl;
4526 // only take state if this is a new playlist.
4527 for (fl = freezelist.begin(); fl != freezelist.end(); ++fl) {
4533 if (fl == freezelist.end()) {
4534 pl->clear_changes();
4535 pl->clear_owned_changes ();
4537 freezelist.insert (pl);
4542 TimeAxisView* tv = &(*x)->get_time_axis_view();
4543 vector<PlaylistMapping>::iterator z;
4545 for (z = pmap.begin(); z != pmap.end(); ++z) {
4546 if ((*z).tv == tv) {
4551 if (z == pmap.end()) {
4552 pmap.push_back (PlaylistMapping (tv));
4556 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ) {
4558 boost::shared_ptr<Playlist> pl = (*x)->region()->playlist();
4561 /* region not yet associated with a playlist (e.g. unfinished
4568 TimeAxisView& tv = (*x)->get_time_axis_view();
4569 boost::shared_ptr<Playlist> npl;
4570 RegionSelection::iterator tmp;
4577 vector<PlaylistMapping>::iterator z;
4579 for (z = pmap.begin(); z != pmap.end(); ++z) {
4580 if ((*z).tv == &tv) {
4585 assert (z != pmap.end());
4588 npl = PlaylistFactory::create (pl->data_type(), *_session, "cutlist", true);
4596 boost::shared_ptr<Region> r = (*x)->region();
4597 boost::shared_ptr<Region> _xx;
4603 pl->remove_region (r);
4604 if (Config->get_edit_mode() == Ripple)
4605 pl->ripple (r->position(), -r->length(), boost::shared_ptr<Region>());
4609 _xx = RegionFactory::create (r);
4610 npl->add_region (_xx, r->position() - first_position);
4611 pl->remove_region (r);
4612 if (Config->get_edit_mode() == Ripple)
4613 pl->ripple (r->position(), -r->length(), boost::shared_ptr<Region>());
4617 /* copy region before adding, so we're not putting same object into two different playlists */
4618 npl->add_region (RegionFactory::create (r), r->position() - first_position);
4622 pl->remove_region (r);
4623 if (Config->get_edit_mode() == Ripple)
4624 pl->ripple (r->position(), -r->length(), boost::shared_ptr<Region>());
4633 list<boost::shared_ptr<Playlist> > foo;
4635 /* the pmap is in the same order as the tracks in which selected regions occurred */
4637 for (vector<PlaylistMapping>::iterator i = pmap.begin(); i != pmap.end(); ++i) {
4640 foo.push_back ((*i).pl);
4645 cut_buffer->set (foo);
4649 _last_cut_copy_source_track = 0;
4651 _last_cut_copy_source_track = pmap.front().tv;
4655 for (FreezeList::iterator pl = freezelist.begin(); pl != freezelist.end(); ++pl) {
4658 /* We might have removed regions, which alters other regions' layering_index,
4659 so we need to do a recursive diff here.
4661 vector<Command*> cmds;
4662 (*pl)->rdiff (cmds);
4663 _session->add_commands (cmds);
4665 _session->add_command (new StatefulDiffCommand (*pl));
4670 Editor::cut_copy_ranges (CutCopyOp op)
4672 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4674 /* Sort the track selection now, so that it if is used, the playlists
4675 selected by the calls below to cut_copy_clear are in the order that
4676 their tracks appear in the editor. This makes things like paste
4677 of ranges work properly.
4680 sort_track_selection (ts);
4683 if (!entered_track) {
4686 ts.push_back (entered_track);
4689 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4690 (*i)->cut_copy_clear (*selection, op);
4695 Editor::paste (float times, bool from_context)
4697 DEBUG_TRACE (DEBUG::CutNPaste, "paste to preferred edit pos\n");
4698 MusicFrame where (get_preferred_edit_position (EDIT_IGNORE_NONE, from_context), 0);
4699 paste_internal (where.frame, times, 0);
4703 Editor::mouse_paste ()
4705 MusicFrame where (0, 0);
4707 if (!mouse_frame (where.frame, ignored)) {
4712 paste_internal (where.frame, 1, where.division);
4716 Editor::paste_internal (framepos_t position, float times, const int32_t sub_num)
4718 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("apparent paste position is %1\n", position));
4720 if (cut_buffer->empty(internal_editing())) {
4724 if (position == max_framepos) {
4725 position = get_preferred_edit_position();
4726 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("preferred edit position is %1\n", position));
4729 if (position == last_paste_pos) {
4730 /* repeated paste in the same position */
4733 /* paste in new location, reset repeated paste state */
4735 last_paste_pos = position;
4738 /* get everything in the correct order */
4741 if (!selection->tracks.empty()) {
4742 /* If there is a track selection, paste into exactly those tracks and
4743 only those tracks. This allows the user to be explicit and override
4744 the below "do the reasonable thing" logic. */
4745 ts = selection->tracks.filter_to_unique_playlists ();
4746 sort_track_selection (ts);
4748 /* Figure out which track to base the paste at. */
4749 TimeAxisView* base_track = NULL;
4750 if (_edit_point == Editing::EditAtMouse && entered_track) {
4751 /* With the mouse edit point, paste onto the track under the mouse. */
4752 base_track = entered_track;
4753 } else if (_edit_point == Editing::EditAtMouse && entered_regionview) {
4754 /* With the mouse edit point, paste onto the track of the region under the mouse. */
4755 base_track = &entered_regionview->get_time_axis_view();
4756 } else if (_last_cut_copy_source_track) {
4757 /* Paste to the track that the cut/copy came from (see mantis #333). */
4758 base_track = _last_cut_copy_source_track;
4760 /* This is "impossible" since we've copied... well, do nothing. */
4764 /* Walk up to parent if necessary, so base track is a route. */
4765 while (base_track->get_parent()) {
4766 base_track = base_track->get_parent();
4769 /* Add base track and all tracks below it. The paste logic will select
4770 the appropriate object types from the cut buffer in relative order. */
4771 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4772 if ((*i)->order() >= base_track->order()) {
4777 /* Sort tracks so the nth track of type T will pick the nth object of type T. */
4778 sort_track_selection (ts);
4780 /* Add automation children of each track in order, for pasting several lines. */
4781 for (TrackViewList::iterator i = ts.begin(); i != ts.end();) {
4782 /* Add any automation children for pasting several lines */
4783 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*i++);
4788 typedef RouteTimeAxisView::AutomationTracks ATracks;
4789 const ATracks& atracks = rtv->automation_tracks();
4790 for (ATracks::const_iterator a = atracks.begin(); a != atracks.end(); ++a) {
4791 i = ts.insert(i, a->second.get());
4796 /* We now have a list of trackviews starting at base_track, including
4797 automation children, in the order shown in the editor, e.g. R1,
4798 R1.A1, R1.A2, R2, R2.A1, ... */
4801 begin_reversible_command (Operations::paste);
4803 if (ts.size() == 1 && cut_buffer->lines.size() == 1 &&
4804 dynamic_cast<AutomationTimeAxisView*>(ts.front())) {
4805 /* Only one line copied, and one automation track selected. Do a
4806 "greedy" paste from one automation type to another. */
4808 PasteContext ctx(paste_count, times, ItemCounts(), true);
4809 ts.front()->paste (position, *cut_buffer, ctx, sub_num);
4813 /* Paste into tracks */
4815 PasteContext ctx(paste_count, times, ItemCounts(), false);
4816 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4817 (*i)->paste (position, *cut_buffer, ctx, sub_num);
4821 commit_reversible_command ();
4825 Editor::duplicate_regions (float times)
4827 RegionSelection rs (get_regions_from_selection_and_entered());
4828 duplicate_some_regions (rs, times);
4832 Editor::duplicate_some_regions (RegionSelection& regions, float times)
4834 if (regions.empty ()) {
4838 boost::shared_ptr<Playlist> playlist;
4839 RegionSelection sel = regions; // clear (below) may clear the argument list if its the current region selection
4840 RegionSelection foo;
4842 framepos_t const start_frame = regions.start ();
4843 framepos_t const end_frame = regions.end_frame ();
4844 framecnt_t const gap = end_frame - start_frame + 1;
4846 begin_reversible_command (Operations::duplicate_region);
4848 selection->clear_regions ();
4850 for (RegionSelection::iterator i = sel.begin(); i != sel.end(); ++i) {
4852 boost::shared_ptr<Region> r ((*i)->region());
4854 TimeAxisView& tv = (*i)->get_time_axis_view();
4855 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (&tv);
4856 latest_regionviews.clear ();
4857 sigc::connection c = rtv->view()->RegionViewAdded.connect (sigc::mem_fun(*this, &Editor::collect_new_region_view));
4859 framepos_t const position = end_frame + (r->first_frame() - start_frame + 1);
4860 playlist = (*i)->region()->playlist();
4861 playlist->clear_changes ();
4862 playlist->duplicate (r, position, gap, times);
4863 _session->add_command(new StatefulDiffCommand (playlist));
4867 foo.insert (foo.end(), latest_regionviews.begin(), latest_regionviews.end());
4871 selection->set (foo);
4874 commit_reversible_command ();
4878 Editor::duplicate_selection (float times)
4880 if (selection->time.empty() || selection->tracks.empty()) {
4884 boost::shared_ptr<Playlist> playlist;
4886 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4888 bool in_command = false;
4890 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4891 if ((playlist = (*i)->playlist()) == 0) {
4894 playlist->clear_changes ();
4896 if (clicked_selection) {
4897 playlist->duplicate_range (selection->time[clicked_selection], times);
4899 playlist->duplicate_ranges (selection->time, times);
4903 begin_reversible_command (_("duplicate range selection"));
4906 _session->add_command (new StatefulDiffCommand (playlist));
4911 if (times == 1.0f) {
4912 // now "move" range selection to after the current range selection
4913 framecnt_t distance = 0;
4915 if (clicked_selection) {
4917 selection->time[clicked_selection].end - selection->time[clicked_selection].start;
4919 distance = selection->time.end_frame () - selection->time.start ();
4922 selection->move_time (distance);
4924 commit_reversible_command ();
4928 /** Reset all selected points to the relevant default value */
4930 Editor::reset_point_selection ()
4932 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
4933 ARDOUR::AutomationList::iterator j = (*i)->model ();
4934 (*j)->value = (*i)->line().the_list()->default_value ();
4939 Editor::center_playhead ()
4941 float const page = _visible_canvas_width * samples_per_pixel;
4942 center_screen_internal (playhead_cursor->current_frame (), page);
4946 Editor::center_edit_point ()
4948 float const page = _visible_canvas_width * samples_per_pixel;
4949 center_screen_internal (get_preferred_edit_position(), page);
4952 /** Caller must begin and commit a reversible command */
4954 Editor::clear_playlist (boost::shared_ptr<Playlist> playlist)
4956 playlist->clear_changes ();
4958 _session->add_command (new StatefulDiffCommand (playlist));
4962 Editor::nudge_track (bool use_edit, bool forwards)
4964 boost::shared_ptr<Playlist> playlist;
4965 framepos_t distance;
4966 framepos_t next_distance;
4970 start = get_preferred_edit_position();
4975 if ((distance = get_nudge_distance (start, next_distance)) == 0) {
4979 if (selection->tracks.empty()) {
4983 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4984 bool in_command = false;
4986 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4988 if ((playlist = (*i)->playlist()) == 0) {
4992 playlist->clear_changes ();
4993 playlist->clear_owned_changes ();
4995 playlist->nudge_after (start, distance, forwards);
4998 begin_reversible_command (_("nudge track"));
5001 vector<Command*> cmds;
5003 playlist->rdiff (cmds);
5004 _session->add_commands (cmds);
5006 _session->add_command (new StatefulDiffCommand (playlist));
5010 commit_reversible_command ();
5015 Editor::remove_last_capture ()
5017 vector<string> choices;
5024 if (Config->get_verify_remove_last_capture()) {
5025 prompt = _("Do you really want to destroy the last capture?"
5026 "\n(This is destructive and cannot be undone)");
5028 choices.push_back (_("No, do nothing."));
5029 choices.push_back (_("Yes, destroy it."));
5031 Gtkmm2ext::Choice prompter (_("Destroy last capture"), prompt, choices);
5033 if (prompter.run () == 1) {
5034 _session->remove_last_capture ();
5035 _regions->redisplay ();
5039 _session->remove_last_capture();
5040 _regions->redisplay ();
5045 Editor::normalize_region ()
5051 RegionSelection rs = get_regions_from_selection_and_entered ();
5057 NormalizeDialog dialog (rs.size() > 1);
5059 if (dialog.run () != RESPONSE_ACCEPT) {
5063 CursorContext::Handle cursor_ctx = CursorContext::create(*this, _cursors->wait);
5066 /* XXX: should really only count audio regions here */
5067 int const regions = rs.size ();
5069 /* Make a list of the selected audio regions' maximum amplitudes, and also
5070 obtain the maximum amplitude of them all.
5072 list<double> max_amps;
5073 list<double> rms_vals;
5076 bool use_rms = dialog.constrain_rms ();
5078 for (RegionSelection::const_iterator i = rs.begin(); i != rs.end(); ++i) {
5079 AudioRegionView const * arv = dynamic_cast<AudioRegionView const *> (*i);
5083 dialog.descend (1.0 / regions);
5084 double const a = arv->audio_region()->maximum_amplitude (&dialog);
5086 double r = arv->audio_region()->rms (&dialog);
5087 max_rms = max (max_rms, r);
5088 rms_vals.push_back (r);
5092 /* the user cancelled the operation */
5096 max_amps.push_back (a);
5097 max_amp = max (max_amp, a);
5101 list<double>::const_iterator a = max_amps.begin ();
5102 list<double>::const_iterator l = rms_vals.begin ();
5103 bool in_command = false;
5105 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
5106 AudioRegionView* const arv = dynamic_cast<AudioRegionView*> (*r);
5111 arv->region()->clear_changes ();
5113 double amp = dialog.normalize_individually() ? *a : max_amp;
5114 double target = dialog.target_peak (); // dB
5117 double const amp_rms = dialog.normalize_individually() ? *l : max_rms;
5118 const double t_rms = dialog.target_rms ();
5119 const gain_t c_peak = dB_to_coefficient (target);
5120 const gain_t c_rms = dB_to_coefficient (t_rms);
5121 if ((amp_rms / c_rms) > (amp / c_peak)) {
5127 arv->audio_region()->normalize (amp, target);
5130 begin_reversible_command (_("normalize"));
5133 _session->add_command (new StatefulDiffCommand (arv->region()));
5140 commit_reversible_command ();
5146 Editor::reset_region_scale_amplitude ()
5152 RegionSelection rs = get_regions_from_selection_and_entered ();
5158 bool in_command = false;
5160 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
5161 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
5164 arv->region()->clear_changes ();
5165 arv->audio_region()->set_scale_amplitude (1.0f);
5168 begin_reversible_command ("reset gain");
5171 _session->add_command (new StatefulDiffCommand (arv->region()));
5175 commit_reversible_command ();
5180 Editor::adjust_region_gain (bool up)
5182 RegionSelection rs = get_regions_from_selection_and_entered ();
5184 if (!_session || rs.empty()) {
5188 bool in_command = false;
5190 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
5191 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
5196 arv->region()->clear_changes ();
5198 double dB = accurate_coefficient_to_dB (arv->audio_region()->scale_amplitude ());
5206 arv->audio_region()->set_scale_amplitude (dB_to_coefficient (dB));
5209 begin_reversible_command ("adjust region gain");
5212 _session->add_command (new StatefulDiffCommand (arv->region()));
5216 commit_reversible_command ();
5221 Editor::reset_region_gain ()
5223 RegionSelection rs = get_regions_from_selection_and_entered ();
5225 if (!_session || rs.empty()) {
5229 bool in_command = false;
5231 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
5232 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
5237 arv->region()->clear_changes ();
5239 arv->audio_region()->set_scale_amplitude (1.0f);
5242 begin_reversible_command ("reset region gain");
5245 _session->add_command (new StatefulDiffCommand (arv->region()));
5249 commit_reversible_command ();
5254 Editor::reverse_region ()
5260 Reverse rev (*_session);
5261 apply_filter (rev, _("reverse regions"));
5265 Editor::strip_region_silence ()
5271 RegionSelection rs = get_regions_from_selection_and_entered ();
5277 std::list<RegionView*> audio_only;
5279 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5280 AudioRegionView* const arv = dynamic_cast<AudioRegionView*> (*i);
5282 audio_only.push_back (arv);
5286 assert (!audio_only.empty());
5288 StripSilenceDialog d (_session, audio_only);
5289 int const r = d.run ();
5293 if (r == Gtk::RESPONSE_OK) {
5294 ARDOUR::AudioIntervalMap silences;
5295 d.silences (silences);
5296 StripSilence s (*_session, silences, d.fade_length());
5298 apply_filter (s, _("strip silence"), &d);
5303 Editor::apply_midi_note_edit_op_to_region (MidiOperator& op, MidiRegionView& mrv)
5305 Evoral::Sequence<Evoral::Beats>::Notes selected;
5306 mrv.selection_as_notelist (selected, true);
5308 vector<Evoral::Sequence<Evoral::Beats>::Notes> v;
5309 v.push_back (selected);
5311 Evoral::Beats pos_beats = Evoral::Beats (mrv.midi_region()->beat()) - mrv.midi_region()->start_beats();
5313 return op (mrv.midi_region()->model(), pos_beats, v);
5317 Editor::apply_midi_note_edit_op (MidiOperator& op, const RegionSelection& rs)
5323 bool in_command = false;
5325 for (RegionSelection::const_iterator r = rs.begin(); r != rs.end(); ) {
5326 RegionSelection::const_iterator tmp = r;
5329 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*r);
5332 Command* cmd = apply_midi_note_edit_op_to_region (op, *mrv);
5335 begin_reversible_command (op.name ());
5339 _session->add_command (cmd);
5347 commit_reversible_command ();
5352 Editor::fork_region ()
5354 RegionSelection rs = get_regions_from_selection_and_entered ();
5360 CursorContext::Handle cursor_ctx = CursorContext::create(*this, _cursors->wait);
5361 bool in_command = false;
5365 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
5366 RegionSelection::iterator tmp = r;
5369 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*>(*r);
5373 boost::shared_ptr<Playlist> playlist = mrv->region()->playlist();
5374 boost::shared_ptr<MidiSource> new_source = _session->create_midi_source_by_stealing_name (mrv->midi_view()->track());
5375 boost::shared_ptr<MidiRegion> newregion = mrv->midi_region()->clone (new_source);
5378 begin_reversible_command (_("Fork Region(s)"));
5381 playlist->clear_changes ();
5382 playlist->replace_region (mrv->region(), newregion, mrv->region()->position());
5383 _session->add_command(new StatefulDiffCommand (playlist));
5385 error << string_compose (_("Could not unlink %1"), mrv->region()->name()) << endmsg;
5393 commit_reversible_command ();
5398 Editor::quantize_region ()
5401 quantize_regions(get_regions_from_selection_and_entered ());
5406 Editor::quantize_regions (const RegionSelection& rs)
5408 if (rs.n_midi_regions() == 0) {
5412 if (!quantize_dialog) {
5413 quantize_dialog = new QuantizeDialog (*this);
5416 if (quantize_dialog->is_mapped()) {
5417 /* in progress already */
5421 quantize_dialog->present ();
5422 const int r = quantize_dialog->run ();
5423 quantize_dialog->hide ();
5425 if (r == Gtk::RESPONSE_OK) {
5426 Quantize quant (quantize_dialog->snap_start(),
5427 quantize_dialog->snap_end(),
5428 quantize_dialog->start_grid_size(),
5429 quantize_dialog->end_grid_size(),
5430 quantize_dialog->strength(),
5431 quantize_dialog->swing(),
5432 quantize_dialog->threshold());
5434 apply_midi_note_edit_op (quant, rs);
5439 Editor::legatize_region (bool shrink_only)
5442 legatize_regions(get_regions_from_selection_and_entered (), shrink_only);
5447 Editor::legatize_regions (const RegionSelection& rs, bool shrink_only)
5449 if (rs.n_midi_regions() == 0) {
5453 Legatize legatize(shrink_only);
5454 apply_midi_note_edit_op (legatize, rs);
5458 Editor::transform_region ()
5461 transform_regions(get_regions_from_selection_and_entered ());
5466 Editor::transform_regions (const RegionSelection& rs)
5468 if (rs.n_midi_regions() == 0) {
5475 const int r = td.run();
5478 if (r == Gtk::RESPONSE_OK) {
5479 Transform transform(td.get());
5480 apply_midi_note_edit_op(transform, rs);
5485 Editor::transpose_region ()
5488 transpose_regions(get_regions_from_selection_and_entered ());
5493 Editor::transpose_regions (const RegionSelection& rs)
5495 if (rs.n_midi_regions() == 0) {
5500 int const r = d.run ();
5502 if (r == RESPONSE_ACCEPT) {
5503 Transpose transpose(d.semitones ());
5504 apply_midi_note_edit_op (transpose, rs);
5509 Editor::insert_patch_change (bool from_context)
5511 RegionSelection rs = get_regions_from_selection_and_entered ();
5517 const framepos_t p = get_preferred_edit_position (EDIT_IGNORE_NONE, from_context);
5519 /* XXX: bit of a hack; use the MIDNAM from the first selected region;
5520 there may be more than one, but the PatchChangeDialog can only offer
5521 one set of patch menus.
5523 MidiRegionView* first = dynamic_cast<MidiRegionView*> (rs.front ());
5525 Evoral::PatchChange<Evoral::Beats> empty (Evoral::Beats(), 0, 0, 0);
5526 PatchChangeDialog d (0, _session, empty, first->instrument_info(), Gtk::Stock::ADD);
5528 if (d.run() == RESPONSE_CANCEL) {
5532 for (RegionSelection::iterator i = rs.begin (); i != rs.end(); ++i) {
5533 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*i);
5535 if (p >= mrv->region()->first_frame() && p <= mrv->region()->last_frame()) {
5536 mrv->add_patch_change (p - mrv->region()->position(), d.patch ());
5543 Editor::apply_filter (Filter& filter, string command, ProgressReporter* progress)
5545 RegionSelection rs = get_regions_from_selection_and_entered ();
5551 CursorContext::Handle cursor_ctx = CursorContext::create(*this, _cursors->wait);
5552 bool in_command = false;
5557 int const N = rs.size ();
5559 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
5560 RegionSelection::iterator tmp = r;
5563 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
5565 boost::shared_ptr<Playlist> playlist = arv->region()->playlist();
5568 progress->descend (1.0 / N);
5571 if (arv->audio_region()->apply (filter, progress) == 0) {
5573 playlist->clear_changes ();
5574 playlist->clear_owned_changes ();
5577 begin_reversible_command (command);
5581 if (filter.results.empty ()) {
5583 /* no regions returned; remove the old one */
5584 playlist->remove_region (arv->region ());
5588 std::vector<boost::shared_ptr<Region> >::iterator res = filter.results.begin ();
5590 /* first region replaces the old one */
5591 playlist->replace_region (arv->region(), *res, (*res)->position());
5595 while (res != filter.results.end()) {
5596 playlist->add_region (*res, (*res)->position());
5602 /* We might have removed regions, which alters other regions' layering_index,
5603 so we need to do a recursive diff here.
5605 vector<Command*> cmds;
5606 playlist->rdiff (cmds);
5607 _session->add_commands (cmds);
5609 _session->add_command(new StatefulDiffCommand (playlist));
5613 progress->ascend ();
5622 commit_reversible_command ();
5627 Editor::external_edit_region ()
5633 Editor::reset_region_gain_envelopes ()
5635 RegionSelection rs = get_regions_from_selection_and_entered ();
5637 if (!_session || rs.empty()) {
5641 bool in_command = false;
5643 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5644 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
5646 boost::shared_ptr<AutomationList> alist (arv->audio_region()->envelope());
5647 XMLNode& before (alist->get_state());
5649 arv->audio_region()->set_default_envelope ();
5652 begin_reversible_command (_("reset region gain"));
5655 _session->add_command (new MementoCommand<AutomationList>(*arv->audio_region()->envelope().get(), &before, &alist->get_state()));
5660 commit_reversible_command ();
5665 Editor::set_region_gain_visibility (RegionView* rv)
5667 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (rv);
5669 arv->update_envelope_visibility();
5674 Editor::set_gain_envelope_visibility ()
5680 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5681 AudioTimeAxisView* v = dynamic_cast<AudioTimeAxisView*>(*i);
5683 v->audio_view()->foreach_regionview (sigc::mem_fun (this, &Editor::set_region_gain_visibility));
5689 Editor::toggle_gain_envelope_active ()
5691 if (_ignore_region_action) {
5695 RegionSelection rs = get_regions_from_selection_and_entered ();
5697 if (!_session || rs.empty()) {
5701 bool in_command = false;
5703 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5704 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
5706 arv->region()->clear_changes ();
5707 arv->audio_region()->set_envelope_active (!arv->audio_region()->envelope_active());
5710 begin_reversible_command (_("region gain envelope active"));
5713 _session->add_command (new StatefulDiffCommand (arv->region()));
5718 commit_reversible_command ();
5723 Editor::toggle_region_lock ()
5725 if (_ignore_region_action) {
5729 RegionSelection rs = get_regions_from_selection_and_entered ();
5731 if (!_session || rs.empty()) {
5735 begin_reversible_command (_("toggle region lock"));
5737 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5738 (*i)->region()->clear_changes ();
5739 (*i)->region()->set_locked (!(*i)->region()->locked());
5740 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5743 commit_reversible_command ();
5747 Editor::toggle_region_video_lock ()
5749 if (_ignore_region_action) {
5753 RegionSelection rs = get_regions_from_selection_and_entered ();
5755 if (!_session || rs.empty()) {
5759 begin_reversible_command (_("Toggle Video Lock"));
5761 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5762 (*i)->region()->clear_changes ();
5763 (*i)->region()->set_video_locked (!(*i)->region()->video_locked());
5764 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5767 commit_reversible_command ();
5771 Editor::toggle_region_lock_style ()
5773 if (_ignore_region_action) {
5777 RegionSelection rs = get_regions_from_selection_and_entered ();
5779 if (!_session || rs.empty()) {
5783 Glib::RefPtr<ToggleAction> a = Glib::RefPtr<ToggleAction>::cast_dynamic (_region_actions->get_action("toggle-region-lock-style"));
5784 vector<Widget*> proxies = a->get_proxies();
5785 Gtk::CheckMenuItem* cmi = dynamic_cast<Gtk::CheckMenuItem*> (proxies.front());
5789 begin_reversible_command (_("toggle region lock style"));
5791 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5792 (*i)->region()->clear_changes ();
5793 PositionLockStyle const ns = ((*i)->region()->position_lock_style() == AudioTime && !cmi->get_inconsistent()) ? MusicTime : AudioTime;
5794 (*i)->region()->set_position_lock_style (ns);
5795 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5798 commit_reversible_command ();
5802 Editor::toggle_opaque_region ()
5804 if (_ignore_region_action) {
5808 RegionSelection rs = get_regions_from_selection_and_entered ();
5810 if (!_session || rs.empty()) {
5814 begin_reversible_command (_("change region opacity"));
5816 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5817 (*i)->region()->clear_changes ();
5818 (*i)->region()->set_opaque (!(*i)->region()->opaque());
5819 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5822 commit_reversible_command ();
5826 Editor::toggle_record_enable ()
5828 bool new_state = false;
5830 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5831 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5834 if (!rtav->is_track())
5838 new_state = !rtav->track()->rec_enable_control()->get_value();
5842 rtav->track()->rec_enable_control()->set_value (new_state, Controllable::UseGroup);
5847 Editor::toggle_solo ()
5849 bool new_state = false;
5851 boost::shared_ptr<ControlList> cl (new ControlList);
5853 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5854 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5861 new_state = !rtav->route()->soloed ();
5865 cl->push_back (rtav->route()->solo_control());
5868 _session->set_controls (cl, new_state ? 1.0 : 0.0, Controllable::UseGroup);
5872 Editor::toggle_mute ()
5874 bool new_state = false;
5876 boost::shared_ptr<RouteList> rl (new RouteList);
5878 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5879 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5886 new_state = !rtav->route()->muted();
5890 rl->push_back (rtav->route());
5893 _session->set_controls (route_list_to_control_list (rl, &Stripable::mute_control), new_state, Controllable::UseGroup);
5897 Editor::toggle_solo_isolate ()
5903 Editor::fade_range ()
5905 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
5907 begin_reversible_command (_("fade range"));
5909 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
5910 (*i)->fade_range (selection->time);
5913 commit_reversible_command ();
5918 Editor::set_fade_length (bool in)
5920 RegionSelection rs = get_regions_from_selection_and_entered ();
5926 /* we need a region to measure the offset from the start */
5928 RegionView* rv = rs.front ();
5930 framepos_t pos = get_preferred_edit_position();
5934 if (pos > rv->region()->last_frame() || pos < rv->region()->first_frame()) {
5935 /* edit point is outside the relevant region */
5940 if (pos <= rv->region()->position()) {
5944 len = pos - rv->region()->position();
5945 cmd = _("set fade in length");
5947 if (pos >= rv->region()->last_frame()) {
5951 len = rv->region()->last_frame() - pos;
5952 cmd = _("set fade out length");
5955 bool in_command = false;
5957 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5958 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5964 boost::shared_ptr<AutomationList> alist;
5966 alist = tmp->audio_region()->fade_in();
5968 alist = tmp->audio_region()->fade_out();
5971 XMLNode &before = alist->get_state();
5974 tmp->audio_region()->set_fade_in_length (len);
5975 tmp->audio_region()->set_fade_in_active (true);
5977 tmp->audio_region()->set_fade_out_length (len);
5978 tmp->audio_region()->set_fade_out_active (true);
5982 begin_reversible_command (cmd);
5985 XMLNode &after = alist->get_state();
5986 _session->add_command(new MementoCommand<AutomationList>(*alist, &before, &after));
5990 commit_reversible_command ();
5995 Editor::set_fade_in_shape (FadeShape shape)
5997 RegionSelection rs = get_regions_from_selection_and_entered ();
6002 bool in_command = false;
6004 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
6005 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
6011 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_in();
6012 XMLNode &before = alist->get_state();
6014 tmp->audio_region()->set_fade_in_shape (shape);
6017 begin_reversible_command (_("set fade in shape"));
6020 XMLNode &after = alist->get_state();
6021 _session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
6025 commit_reversible_command ();
6030 Editor::set_fade_out_shape (FadeShape shape)
6032 RegionSelection rs = get_regions_from_selection_and_entered ();
6037 bool in_command = false;
6039 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
6040 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
6046 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_out();
6047 XMLNode &before = alist->get_state();
6049 tmp->audio_region()->set_fade_out_shape (shape);
6052 begin_reversible_command (_("set fade out shape"));
6055 XMLNode &after = alist->get_state();
6056 _session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
6060 commit_reversible_command ();
6065 Editor::set_fade_in_active (bool yn)
6067 RegionSelection rs = get_regions_from_selection_and_entered ();
6072 bool in_command = false;
6074 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
6075 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
6082 boost::shared_ptr<AudioRegion> ar (tmp->audio_region());
6084 ar->clear_changes ();
6085 ar->set_fade_in_active (yn);
6088 begin_reversible_command (_("set fade in active"));
6091 _session->add_command (new StatefulDiffCommand (ar));
6095 commit_reversible_command ();
6100 Editor::set_fade_out_active (bool yn)
6102 RegionSelection rs = get_regions_from_selection_and_entered ();
6107 bool in_command = false;
6109 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
6110 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
6116 boost::shared_ptr<AudioRegion> ar (tmp->audio_region());
6118 ar->clear_changes ();
6119 ar->set_fade_out_active (yn);
6122 begin_reversible_command (_("set fade out active"));
6125 _session->add_command(new StatefulDiffCommand (ar));
6129 commit_reversible_command ();
6134 Editor::toggle_region_fades (int dir)
6136 if (_ignore_region_action) {
6140 boost::shared_ptr<AudioRegion> ar;
6143 RegionSelection rs = get_regions_from_selection_and_entered ();
6149 RegionSelection::iterator i;
6150 for (i = rs.begin(); i != rs.end(); ++i) {
6151 if ((ar = boost::dynamic_pointer_cast<AudioRegion>((*i)->region())) != 0) {
6153 yn = ar->fade_out_active ();
6155 yn = ar->fade_in_active ();
6161 if (i == rs.end()) {
6165 /* XXX should this undo-able? */
6166 bool in_command = false;
6168 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
6169 if ((ar = boost::dynamic_pointer_cast<AudioRegion>((*i)->region())) == 0) {
6172 ar->clear_changes ();
6174 if (dir == 1 || dir == 0) {
6175 ar->set_fade_in_active (!yn);
6178 if (dir == -1 || dir == 0) {
6179 ar->set_fade_out_active (!yn);
6182 begin_reversible_command (_("toggle fade active"));
6185 _session->add_command(new StatefulDiffCommand (ar));
6189 commit_reversible_command ();
6194 /** Update region fade visibility after its configuration has been changed */
6196 Editor::update_region_fade_visibility ()
6198 bool _fade_visibility = _session->config.get_show_region_fades ();
6200 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
6201 AudioTimeAxisView* v = dynamic_cast<AudioTimeAxisView*>(*i);
6203 if (_fade_visibility) {
6204 v->audio_view()->show_all_fades ();
6206 v->audio_view()->hide_all_fades ();
6213 Editor::set_edit_point ()
6216 MusicFrame where (0, 0);
6218 if (!mouse_frame (where.frame, ignored)) {
6224 if (selection->markers.empty()) {
6226 mouse_add_new_marker (where.frame);
6231 Location* loc = find_location_from_marker (selection->markers.front(), ignored);
6234 loc->move_to (where.frame, where.division);
6240 Editor::set_playhead_cursor ()
6242 if (entered_marker) {
6243 _session->request_locate (entered_marker->position(), _session->transport_rolling());
6245 MusicFrame where (0, 0);
6248 if (!mouse_frame (where.frame, ignored)) {
6255 _session->request_locate (where.frame, _session->transport_rolling());
6259 //not sure what this was for; remove it for now.
6260 // if (UIConfiguration::instance().get_follow_edits() && (!_session || !_session->config.get_external_sync())) {
6261 // cancel_time_selection();
6267 Editor::split_region ()
6269 if (_drags->active ()) {
6273 //if a range is selected, separate it
6274 if ( !selection->time.empty()) {
6275 separate_regions_between (selection->time);
6279 //if no range was selected, try to find some regions to split
6280 if (current_mouse_mode() == MouseObject) { //don't try this for Internal Edit, Stretch, Draw, etc.
6282 RegionSelection rs = get_regions_from_selection_and_edit_point ();
6283 const framepos_t pos = get_preferred_edit_position();
6284 const int32_t division = get_grid_music_divisions (0);
6285 MusicFrame where (pos, division);
6291 split_regions_at (where, rs);
6297 Editor::select_next_route()
6299 if (selection->tracks.empty()) {
6300 selection->set (track_views.front());
6304 TimeAxisView* current = selection->tracks.front();
6308 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
6310 if (*i == current) {
6312 if (i != track_views.end()) {
6315 current = (*(track_views.begin()));
6316 //selection->set (*(track_views.begin()));
6322 rui = dynamic_cast<RouteUI *>(current);
6324 } while (current->hidden() || (rui == NULL) || !rui->route()->active());
6326 selection->set (current);
6328 ensure_time_axis_view_is_visible (*current, false);
6332 Editor::select_prev_route()
6334 if (selection->tracks.empty()) {
6335 selection->set (track_views.front());
6339 TimeAxisView* current = selection->tracks.front();
6343 for (TrackViewList::reverse_iterator i = track_views.rbegin(); i != track_views.rend(); ++i) {
6345 if (*i == current) {
6347 if (i != track_views.rend()) {
6350 current = *(track_views.rbegin());
6355 rui = dynamic_cast<RouteUI *>(current);
6357 } while (current->hidden() || (rui == NULL) || !rui->route()->active());
6359 selection->set (current);
6361 ensure_time_axis_view_is_visible (*current, false);
6365 Editor::set_loop_from_selection (bool play)
6367 if (_session == 0) {
6371 framepos_t start, end;
6372 if (!get_selection_extents ( start, end))
6375 set_loop_range (start, end, _("set loop range from selection"));
6378 _session->request_play_loop (true, true);
6383 Editor::set_loop_from_region (bool play)
6385 framepos_t start, end;
6386 if (!get_selection_extents ( start, end))
6389 set_loop_range (start, end, _("set loop range from region"));
6392 _session->request_locate (start, true);
6393 _session->request_play_loop (true);
6398 Editor::set_punch_from_selection ()
6400 if (_session == 0) {
6404 framepos_t start, end;
6405 if (!get_selection_extents ( start, end))
6408 set_punch_range (start, end, _("set punch range from selection"));
6412 Editor::set_auto_punch_range ()
6414 // auto punch in/out button from a single button
6415 // If Punch In is unset, set punch range from playhead to end, enable punch in
6416 // If Punch In is set, the next punch sets Punch Out, unless the playhead has been
6417 // rewound beyond the Punch In marker, in which case that marker will be moved back
6418 // to the current playhead position.
6419 // If punch out is set, it clears the punch range and Punch In/Out buttons
6421 if (_session == 0) {
6425 Location* tpl = transport_punch_location();
6426 framepos_t now = playhead_cursor->current_frame();
6427 framepos_t begin = now;
6428 framepos_t end = _session->current_end_frame();
6430 if (!_session->config.get_punch_in()) {
6431 // First Press - set punch in and create range from here to eternity
6432 set_punch_range (begin, end, _("Auto Punch In"));
6433 _session->config.set_punch_in(true);
6434 } else if (tpl && !_session->config.get_punch_out()) {
6435 // Second press - update end range marker and set punch_out
6436 if (now < tpl->start()) {
6437 // playhead has been rewound - move start back and pretend nothing happened
6439 set_punch_range (begin, end, _("Auto Punch In/Out"));
6441 // normal case for 2nd press - set the punch out
6442 end = playhead_cursor->current_frame ();
6443 set_punch_range (tpl->start(), now, _("Auto Punch In/Out"));
6444 _session->config.set_punch_out(true);
6447 if (_session->config.get_punch_out()) {
6448 _session->config.set_punch_out(false);
6451 if (_session->config.get_punch_in()) {
6452 _session->config.set_punch_in(false);
6457 // third press - unset punch in/out and remove range
6458 _session->locations()->remove(tpl);
6465 Editor::set_session_extents_from_selection ()
6467 if (_session == 0) {
6471 framepos_t start, end;
6472 if (!get_selection_extents ( start, end))
6476 if ((loc = _session->locations()->session_range_location()) == 0) {
6477 _session->set_session_extents (start, end); // this will create a new session range; no need for UNDO
6479 XMLNode &before = loc->get_state();
6481 _session->set_session_extents (start, end);
6483 XMLNode &after = loc->get_state();
6485 begin_reversible_command (_("set session start/end from selection"));
6487 _session->add_command (new MementoCommand<Location>(*loc, &before, &after));
6489 commit_reversible_command ();
6492 _session->set_end_is_free (false);
6496 Editor::set_punch_start_from_edit_point ()
6500 MusicFrame start (0, 0);
6501 framepos_t end = max_framepos;
6503 //use the existing punch end, if any
6504 Location* tpl = transport_punch_location();
6509 if ((_edit_point == EditAtPlayhead) && _session->transport_rolling()) {
6510 start.frame = _session->audible_frame();
6512 start.frame = get_preferred_edit_position();
6515 //snap the selection start/end
6518 //if there's not already a sensible selection endpoint, go "forever"
6519 if (start.frame > end ) {
6523 set_punch_range (start.frame, end, _("set punch start from EP"));
6529 Editor::set_punch_end_from_edit_point ()
6533 framepos_t start = 0;
6534 MusicFrame end (max_framepos, 0);
6536 //use the existing punch start, if any
6537 Location* tpl = transport_punch_location();
6539 start = tpl->start();
6542 if ((_edit_point == EditAtPlayhead) && _session->transport_rolling()) {
6543 end.frame = _session->audible_frame();
6545 end.frame = get_preferred_edit_position();
6548 //snap the selection start/end
6551 set_punch_range (start, end.frame, _("set punch end from EP"));
6557 Editor::set_loop_start_from_edit_point ()
6561 MusicFrame start (0, 0);
6562 framepos_t end = max_framepos;
6564 //use the existing loop end, if any
6565 Location* tpl = transport_loop_location();
6570 if ((_edit_point == EditAtPlayhead) && _session->transport_rolling()) {
6571 start.frame = _session->audible_frame();
6573 start.frame = get_preferred_edit_position();
6576 //snap the selection start/end
6579 //if there's not already a sensible selection endpoint, go "forever"
6580 if (start.frame > end ) {
6584 set_loop_range (start.frame, end, _("set loop start from EP"));
6590 Editor::set_loop_end_from_edit_point ()
6594 framepos_t start = 0;
6595 MusicFrame end (max_framepos, 0);
6597 //use the existing loop start, if any
6598 Location* tpl = transport_loop_location();
6600 start = tpl->start();
6603 if ((_edit_point == EditAtPlayhead) && _session->transport_rolling()) {
6604 end.frame = _session->audible_frame();
6606 end.frame = get_preferred_edit_position();
6609 //snap the selection start/end
6612 set_loop_range (start, end.frame, _("set loop end from EP"));
6617 Editor::set_punch_from_region ()
6619 framepos_t start, end;
6620 if (!get_selection_extents ( start, end))
6623 set_punch_range (start, end, _("set punch range from region"));
6627 Editor::pitch_shift_region ()
6629 RegionSelection rs = get_regions_from_selection_and_entered ();
6631 RegionSelection audio_rs;
6632 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
6633 if (dynamic_cast<AudioRegionView*> (*i)) {
6634 audio_rs.push_back (*i);
6638 if (audio_rs.empty()) {
6642 pitch_shift (audio_rs, 1.2);
6646 Editor::set_tempo_from_region ()
6648 RegionSelection rs = get_regions_from_selection_and_entered ();
6650 if (!_session || rs.empty()) {
6654 RegionView* rv = rs.front();
6656 define_one_bar (rv->region()->position(), rv->region()->last_frame() + 1);
6660 Editor::use_range_as_bar ()
6662 framepos_t start, end;
6663 if (get_edit_op_range (start, end)) {
6664 define_one_bar (start, end);
6669 Editor::define_one_bar (framepos_t start, framepos_t end)
6671 framepos_t length = end - start;
6673 const Meter& m (_session->tempo_map().meter_at_frame (start));
6675 /* length = 1 bar */
6677 /* We're going to deliver a constant tempo here,
6678 so we can use frames per beat to determine length.
6679 now we want frames per beat.
6680 we have frames per bar, and beats per bar, so ...
6683 /* XXXX METER MATH */
6685 double frames_per_beat = length / m.divisions_per_bar();
6687 /* beats per minute = */
6689 double beats_per_minute = (_session->frame_rate() * 60.0) / frames_per_beat;
6691 /* now decide whether to:
6693 (a) set global tempo
6694 (b) add a new tempo marker
6698 const TempoSection& t (_session->tempo_map().tempo_section_at_frame (start));
6700 bool do_global = false;
6702 if ((_session->tempo_map().n_tempos() == 1) && (_session->tempo_map().n_meters() == 1)) {
6704 /* only 1 tempo & 1 meter: ask if the user wants to set the tempo
6705 at the start, or create a new marker
6708 vector<string> options;
6709 options.push_back (_("Cancel"));
6710 options.push_back (_("Add new marker"));
6711 options.push_back (_("Set global tempo"));
6714 _("Define one bar"),
6715 _("Do you want to set the global tempo or add a new tempo marker?"),
6719 c.set_default_response (2);
6735 /* more than 1 tempo and/or meter section already, go ahead do the "usual":
6736 if the marker is at the region starter, change it, otherwise add
6741 begin_reversible_command (_("set tempo from region"));
6742 XMLNode& before (_session->tempo_map().get_state());
6745 _session->tempo_map().change_initial_tempo (beats_per_minute, t.note_type(), t.end_note_types_per_minute());
6746 } else if (t.frame() == start) {
6747 _session->tempo_map().change_existing_tempo_at (start, beats_per_minute, t.note_type(), t.end_note_types_per_minute());
6749 /* constant tempo */
6750 const Tempo tempo (beats_per_minute, t.note_type());
6751 _session->tempo_map().add_tempo (tempo, 0.0, start, AudioTime);
6754 XMLNode& after (_session->tempo_map().get_state());
6756 _session->add_command (new MementoCommand<TempoMap>(_session->tempo_map(), &before, &after));
6757 commit_reversible_command ();
6761 Editor::split_region_at_transients ()
6763 AnalysisFeatureList positions;
6765 RegionSelection rs = get_regions_from_selection_and_entered ();
6767 if (!_session || rs.empty()) {
6771 begin_reversible_command (_("split regions"));
6773 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ) {
6775 RegionSelection::iterator tmp;
6780 boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion> ((*i)->region());
6783 ar->transients (positions);
6784 split_region_at_points ((*i)->region(), positions, true);
6791 commit_reversible_command ();
6796 Editor::split_region_at_points (boost::shared_ptr<Region> r, AnalysisFeatureList& positions, bool can_ferret, bool select_new)
6798 bool use_rhythmic_rodent = false;
6800 boost::shared_ptr<Playlist> pl = r->playlist();
6802 list<boost::shared_ptr<Region> > new_regions;
6808 if (positions.empty()) {
6812 if (positions.size() > 20 && can_ferret) {
6813 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);
6814 MessageDialog msg (msgstr,
6817 Gtk::BUTTONS_OK_CANCEL);
6820 msg.add_button (_("Call for the Ferret!"), RESPONSE_APPLY);
6821 msg.set_secondary_text (_("Press OK to continue with this split operation\nor ask the Ferret dialog to tune the analysis"));
6823 msg.set_secondary_text (_("Press OK to continue with this split operation"));
6826 msg.set_title (_("Excessive split?"));
6829 int response = msg.run();
6835 case RESPONSE_APPLY:
6836 use_rhythmic_rodent = true;
6843 if (use_rhythmic_rodent) {
6844 show_rhythm_ferret ();
6848 AnalysisFeatureList::const_iterator x;
6850 pl->clear_changes ();
6851 pl->clear_owned_changes ();
6853 x = positions.begin();
6855 if (x == positions.end()) {
6860 pl->remove_region (r);
6864 framepos_t rstart = r->first_frame ();
6865 framepos_t rend = r->last_frame ();
6867 while (x != positions.end()) {
6869 /* deal with positons that are out of scope of present region bounds */
6870 if (*x <= rstart || *x > rend) {
6875 /* file start = original start + how far we from the initial position ? */
6877 framepos_t file_start = r->start() + pos;
6879 /* length = next position - current position */
6881 framepos_t len = (*x) - pos - rstart;
6883 /* XXX we do we really want to allow even single-sample regions?
6884 * shouldn't we have some kind of lower limit on region size?
6893 if (RegionFactory::region_name (new_name, r->name())) {
6897 /* do NOT announce new regions 1 by one, just wait till they are all done */
6901 plist.add (ARDOUR::Properties::start, file_start);
6902 plist.add (ARDOUR::Properties::length, len);
6903 plist.add (ARDOUR::Properties::name, new_name);
6904 plist.add (ARDOUR::Properties::layer, 0);
6905 // TODO set transients_offset
6907 boost::shared_ptr<Region> nr = RegionFactory::create (r->sources(), plist, false);
6908 /* because we set annouce to false, manually add the new region to the
6911 RegionFactory::map_add (nr);
6913 pl->add_region (nr, rstart + pos);
6916 new_regions.push_front(nr);
6925 RegionFactory::region_name (new_name, r->name());
6927 /* Add the final region */
6930 plist.add (ARDOUR::Properties::start, r->start() + pos);
6931 plist.add (ARDOUR::Properties::length, r->last_frame() - (r->position() + pos) + 1);
6932 plist.add (ARDOUR::Properties::name, new_name);
6933 plist.add (ARDOUR::Properties::layer, 0);
6935 boost::shared_ptr<Region> nr = RegionFactory::create (r->sources(), plist, false);
6936 /* because we set annouce to false, manually add the new region to the
6939 RegionFactory::map_add (nr);
6940 pl->add_region (nr, r->position() + pos);
6943 new_regions.push_front(nr);
6948 /* We might have removed regions, which alters other regions' layering_index,
6949 so we need to do a recursive diff here.
6951 vector<Command*> cmds;
6953 _session->add_commands (cmds);
6955 _session->add_command (new StatefulDiffCommand (pl));
6959 for (list<boost::shared_ptr<Region> >::iterator i = new_regions.begin(); i != new_regions.end(); ++i){
6960 set_selected_regionview_from_region_list ((*i), Selection::Add);
6966 Editor::place_transient()
6972 RegionSelection rs = get_regions_from_selection_and_edit_point ();
6978 framepos_t where = get_preferred_edit_position();
6980 begin_reversible_command (_("place transient"));
6982 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6983 (*r)->region()->add_transient(where);
6986 commit_reversible_command ();
6990 Editor::remove_transient(ArdourCanvas::Item* item)
6996 ArdourCanvas::Line* _line = reinterpret_cast<ArdourCanvas::Line*> (item);
6999 AudioRegionView* _arv = reinterpret_cast<AudioRegionView*> (item->get_data ("regionview"));
7000 _arv->remove_transient (*(float*) _line->get_data ("position"));
7004 Editor::snap_regions_to_grid ()
7006 list <boost::shared_ptr<Playlist > > used_playlists;
7008 RegionSelection rs = get_regions_from_selection_and_entered ();
7010 if (!_session || rs.empty()) {
7014 begin_reversible_command (_("snap regions to grid"));
7016 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
7018 boost::shared_ptr<Playlist> pl = (*r)->region()->playlist();
7020 if (!pl->frozen()) {
7021 /* we haven't seen this playlist before */
7023 /* remember used playlists so we can thaw them later */
7024 used_playlists.push_back(pl);
7027 (*r)->region()->clear_changes ();
7029 MusicFrame start ((*r)->region()->first_frame (), 0);
7031 (*r)->region()->set_position (start.frame, start.division);
7032 _session->add_command(new StatefulDiffCommand ((*r)->region()));
7035 while (used_playlists.size() > 0) {
7036 list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
7038 used_playlists.pop_front();
7041 commit_reversible_command ();
7045 Editor::close_region_gaps ()
7047 list <boost::shared_ptr<Playlist > > used_playlists;
7049 RegionSelection rs = get_regions_from_selection_and_entered ();
7051 if (!_session || rs.empty()) {
7055 Dialog dialog (_("Close Region Gaps"));
7058 table.set_spacings (12);
7059 table.set_border_width (12);
7060 Label* l = manage (left_aligned_label (_("Crossfade length")));
7061 table.attach (*l, 0, 1, 0, 1);
7063 SpinButton spin_crossfade (1, 0);
7064 spin_crossfade.set_range (0, 15);
7065 spin_crossfade.set_increments (1, 1);
7066 spin_crossfade.set_value (5);
7067 table.attach (spin_crossfade, 1, 2, 0, 1);
7069 table.attach (*manage (new Label (_("ms"))), 2, 3, 0, 1);
7071 l = manage (left_aligned_label (_("Pull-back length")));
7072 table.attach (*l, 0, 1, 1, 2);
7074 SpinButton spin_pullback (1, 0);
7075 spin_pullback.set_range (0, 100);
7076 spin_pullback.set_increments (1, 1);
7077 spin_pullback.set_value(30);
7078 table.attach (spin_pullback, 1, 2, 1, 2);
7080 table.attach (*manage (new Label (_("ms"))), 2, 3, 1, 2);
7082 dialog.get_vbox()->pack_start (table);
7083 dialog.add_button (Stock::CANCEL, RESPONSE_CANCEL);
7084 dialog.add_button (_("Ok"), RESPONSE_ACCEPT);
7087 if (dialog.run () == RESPONSE_CANCEL) {
7091 framepos_t crossfade_len = spin_crossfade.get_value();
7092 framepos_t pull_back_frames = spin_pullback.get_value();
7094 crossfade_len = lrintf (crossfade_len * _session->frame_rate()/1000);
7095 pull_back_frames = lrintf (pull_back_frames * _session->frame_rate()/1000);
7097 /* Iterate over the region list and make adjacent regions overlap by crossfade_len_ms */
7099 begin_reversible_command (_("close region gaps"));
7102 boost::shared_ptr<Region> last_region;
7104 rs.sort_by_position_and_track();
7106 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
7108 boost::shared_ptr<Playlist> pl = (*r)->region()->playlist();
7110 if (!pl->frozen()) {
7111 /* we haven't seen this playlist before */
7113 /* remember used playlists so we can thaw them later */
7114 used_playlists.push_back(pl);
7118 framepos_t position = (*r)->region()->position();
7120 if (idx == 0 || position < last_region->position()){
7121 last_region = (*r)->region();
7126 (*r)->region()->clear_changes ();
7127 (*r)->region()->trim_front( (position - pull_back_frames));
7129 last_region->clear_changes ();
7130 last_region->trim_end( (position - pull_back_frames + crossfade_len));
7132 _session->add_command (new StatefulDiffCommand ((*r)->region()));
7133 _session->add_command (new StatefulDiffCommand (last_region));
7135 last_region = (*r)->region();
7139 while (used_playlists.size() > 0) {
7140 list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
7142 used_playlists.pop_front();
7145 commit_reversible_command ();
7149 Editor::tab_to_transient (bool forward)
7151 AnalysisFeatureList positions;
7153 RegionSelection rs = get_regions_from_selection_and_entered ();
7159 framepos_t pos = _session->audible_frame ();
7161 if (!selection->tracks.empty()) {
7163 /* don't waste time searching for transients in duplicate playlists.
7166 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
7168 for (TrackViewList::iterator t = ts.begin(); t != ts.end(); ++t) {
7170 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*t);
7173 boost::shared_ptr<Track> tr = rtv->track();
7175 boost::shared_ptr<Playlist> pl = tr->playlist ();
7177 framepos_t result = pl->find_next_transient (pos, forward ? 1 : -1);
7180 positions.push_back (result);
7193 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
7194 (*r)->region()->get_transients (positions);
7198 TransientDetector::cleanup_transients (positions, _session->frame_rate(), 3.0);
7201 AnalysisFeatureList::iterator x;
7203 for (x = positions.begin(); x != positions.end(); ++x) {
7209 if (x != positions.end ()) {
7210 _session->request_locate (*x);
7214 AnalysisFeatureList::reverse_iterator x;
7216 for (x = positions.rbegin(); x != positions.rend(); ++x) {
7222 if (x != positions.rend ()) {
7223 _session->request_locate (*x);
7229 Editor::playhead_forward_to_grid ()
7235 MusicFrame pos (playhead_cursor->current_frame (), 0);
7237 if (pos.frame < max_framepos - 1) {
7239 snap_to_internal (pos, RoundUpAlways, false);
7240 _session->request_locate (pos.frame);
7246 Editor::playhead_backward_to_grid ()
7252 MusicFrame pos (playhead_cursor->current_frame (), 0);
7254 if (pos.frame > 2) {
7256 snap_to_internal (pos, RoundDownAlways, false);
7257 _session->request_locate (pos.frame);
7262 Editor::set_track_height (Height h)
7264 TrackSelection& ts (selection->tracks);
7266 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
7267 (*x)->set_height_enum (h);
7272 Editor::toggle_tracks_active ()
7274 TrackSelection& ts (selection->tracks);
7276 bool target = false;
7282 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
7283 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*x);
7287 target = !rtv->_route->active();
7290 rtv->_route->set_active (target, this);
7296 Editor::remove_tracks ()
7298 /* this will delete GUI objects that may be the subject of an event
7299 handler in which this method is called. Defer actual deletion to the
7300 next idle callback, when all event handling is finished.
7302 Glib::signal_idle().connect (sigc::mem_fun (*this, &Editor::idle_remove_tracks));
7306 Editor::idle_remove_tracks ()
7308 Session::StateProtector sp (_session);
7310 return false; /* do not call again */
7314 Editor::_remove_tracks ()
7316 TrackSelection& ts (selection->tracks);
7322 vector<string> choices;
7326 const char* trackstr;
7328 vector<boost::shared_ptr<Route> > routes;
7329 bool special_bus = false;
7331 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
7332 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*x);
7336 if (rtv->is_track()) {
7341 routes.push_back (rtv->_route);
7343 if (rtv->route()->is_master() || rtv->route()->is_monitor()) {
7348 if (special_bus && !Config->get_allow_special_bus_removal()) {
7349 MessageDialog msg (_("That would be bad news ...."),
7353 msg.set_secondary_text (string_compose (_(
7354 "Removing the master or monitor bus is such a bad idea\n\
7355 that %1 is not going to allow it.\n\
7357 If you really want to do this sort of thing\n\
7358 edit your ardour.rc file to set the\n\
7359 \"allow-special-bus-removal\" option to be \"yes\""), PROGRAM_NAME));
7366 if (ntracks + nbusses == 0) {
7370 trackstr = P_("track", "tracks", ntracks);
7371 busstr = P_("bus", "busses", nbusses);
7375 prompt = string_compose (_("Do you really want to remove %1 %2 and %3 %4?\n"
7376 "(You may also lose the playlists associated with the %2)\n\n"
7377 "This action cannot be undone, and the session file will be overwritten!"),
7378 ntracks, trackstr, nbusses, busstr);
7380 prompt = string_compose (_("Do you really want to remove %1 %2?\n"
7381 "(You may also lose the playlists associated with the %2)\n\n"
7382 "This action cannot be undone, and the session file will be overwritten!"),
7385 } else if (nbusses) {
7386 prompt = string_compose (_("Do you really want to remove %1 %2?\n\n"
7387 "This action cannot be undone, and the session file will be overwritten"),
7391 choices.push_back (_("No, do nothing."));
7392 if (ntracks + nbusses > 1) {
7393 choices.push_back (_("Yes, remove them."));
7395 choices.push_back (_("Yes, remove it."));
7400 title = string_compose (_("Remove %1"), trackstr);
7402 title = string_compose (_("Remove %1"), busstr);
7405 Choice prompter (title, prompt, choices);
7407 if (prompter.run () != 1) {
7411 if (current_mixer_strip && routes.size () > 1 && std::find (routes.begin(), routes.end(), current_mixer_strip->route()) != routes.end ()) {
7412 /* Route deletion calls Editor::timeaxisview_deleted() iteratively (for each deleted
7413 * route). If the deleted route is currently displayed in the Editor-Mixer (highly
7414 * likely because deletion requires selection) this will call
7415 * Editor::set_selected_mixer_strip () which is expensive ( MixerStrip::set_route() ).
7416 * It's likewise likely that the route that has just been displayed in the
7417 * Editor-Mixer will be next in line for deletion.
7419 * So simply switch to the master-bus (if present)
7421 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
7422 if ((*i)->stripable ()->is_master ()) {
7423 set_selected_mixer_strip (*(*i));
7430 PresentationInfo::ChangeSuspender cs;
7431 DisplaySuspender ds;
7433 boost::shared_ptr<RouteList> rl (new RouteList);
7434 for (vector<boost::shared_ptr<Route> >::iterator x = routes.begin(); x != routes.end(); ++x) {
7437 _session->remove_routes (rl);
7439 /* TrackSelection and RouteList leave scope,
7440 * destructors are called,
7441 * diskstream drops references, save_state is called (again for every track)
7446 Editor::do_insert_time ()
7448 if (selection->tracks.empty()) {
7452 InsertRemoveTimeDialog d (*this);
7453 int response = d.run ();
7455 if (response != RESPONSE_OK) {
7459 if (d.distance() == 0) {
7466 d.intersected_region_action (),
7470 d.move_glued_markers(),
7471 d.move_locked_markers(),
7477 Editor::insert_time (
7478 framepos_t pos, framecnt_t frames, InsertTimeOption opt,
7479 bool all_playlists, bool ignore_music_glue, bool markers_too, bool glued_markers_too, bool locked_markers_too, bool tempo_too
7483 if (Config->get_edit_mode() == Lock) {
7486 bool in_command = false;
7488 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
7490 for (TrackViewList::iterator x = ts.begin(); x != ts.end(); ++x) {
7494 /* don't operate on any playlist more than once, which could
7495 * happen if "all playlists" is enabled, but there is more
7496 * than 1 track using playlists "from" a given track.
7499 set<boost::shared_ptr<Playlist> > pl;
7501 if (all_playlists) {
7502 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*x);
7503 if (rtav && rtav->track ()) {
7504 vector<boost::shared_ptr<Playlist> > all = _session->playlists->playlists_for_track (rtav->track ());
7505 for (vector<boost::shared_ptr<Playlist> >::iterator p = all.begin(); p != all.end(); ++p) {
7510 if ((*x)->playlist ()) {
7511 pl.insert ((*x)->playlist ());
7515 for (set<boost::shared_ptr<Playlist> >::iterator i = pl.begin(); i != pl.end(); ++i) {
7517 (*i)->clear_changes ();
7518 (*i)->clear_owned_changes ();
7521 begin_reversible_command (_("insert time"));
7525 if (opt == SplitIntersected) {
7526 /* non musical split */
7527 (*i)->split (MusicFrame (pos, 0));
7530 (*i)->shift (pos, frames, (opt == MoveIntersected), ignore_music_glue);
7532 vector<Command*> cmds;
7534 _session->add_commands (cmds);
7536 _session->add_command (new StatefulDiffCommand (*i));
7540 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*x);
7543 begin_reversible_command (_("insert time"));
7546 rtav->route ()->shift (pos, frames);
7553 const int32_t divisions = get_grid_music_divisions (0);
7554 XMLNode& before (_session->locations()->get_state());
7555 Locations::LocationList copy (_session->locations()->list());
7557 for (Locations::LocationList::iterator i = copy.begin(); i != copy.end(); ++i) {
7559 Locations::LocationList::const_iterator tmp;
7561 if ((*i)->position_lock_style() == AudioTime || glued_markers_too) {
7562 bool const was_locked = (*i)->locked ();
7563 if (locked_markers_too) {
7567 if ((*i)->start() >= pos) {
7568 // move end first, in case we're moving by more than the length of the range
7569 if (!(*i)->is_mark()) {
7570 (*i)->set_end ((*i)->end() + frames, false, true, divisions);
7572 (*i)->set_start ((*i)->start() + frames, false, true, divisions);
7584 begin_reversible_command (_("insert time"));
7587 XMLNode& after (_session->locations()->get_state());
7588 _session->add_command (new MementoCommand<Locations>(*_session->locations(), &before, &after));
7594 begin_reversible_command (_("insert time"));
7597 XMLNode& before (_session->tempo_map().get_state());
7598 _session->tempo_map().insert_time (pos, frames);
7599 XMLNode& after (_session->tempo_map().get_state());
7600 _session->add_command (new MementoCommand<TempoMap>(_session->tempo_map(), &before, &after));
7604 commit_reversible_command ();
7609 Editor::do_remove_time ()
7611 if (selection->tracks.empty()) {
7615 InsertRemoveTimeDialog d (*this, true);
7617 int response = d.run ();
7619 if (response != RESPONSE_OK) {
7623 framecnt_t distance = d.distance();
7625 if (distance == 0) {
7635 d.move_glued_markers(),
7636 d.move_locked_markers(),
7642 Editor::remove_time (framepos_t pos, framecnt_t frames, InsertTimeOption opt,
7643 bool ignore_music_glue, bool markers_too, bool glued_markers_too, bool locked_markers_too, bool tempo_too)
7645 if (Config->get_edit_mode() == Lock) {
7646 error << (_("Cannot insert or delete time when in Lock edit.")) << endmsg;
7649 bool in_command = false;
7651 for (TrackSelection::iterator x = selection->tracks.begin(); x != selection->tracks.end(); ++x) {
7653 boost::shared_ptr<Playlist> pl = (*x)->playlist();
7657 XMLNode &before = pl->get_state();
7660 begin_reversible_command (_("remove time"));
7664 std::list<AudioRange> rl;
7665 AudioRange ar(pos, pos+frames, 0);
7668 pl->shift (pos, -frames, true, ignore_music_glue);
7670 XMLNode &after = pl->get_state();
7672 _session->add_command (new MementoCommand<Playlist> (*pl, &before, &after));
7676 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*x);
7679 begin_reversible_command (_("remove time"));
7682 rtav->route ()->shift (pos, -frames);
7686 const int32_t divisions = get_grid_music_divisions (0);
7687 std::list<Location*> loc_kill_list;
7692 XMLNode& before (_session->locations()->get_state());
7693 Locations::LocationList copy (_session->locations()->list());
7695 for (Locations::LocationList::iterator i = copy.begin(); i != copy.end(); ++i) {
7696 if ((*i)->position_lock_style() == AudioTime || glued_markers_too) {
7698 bool const was_locked = (*i)->locked ();
7699 if (locked_markers_too) {
7703 if (!(*i)->is_mark()) { // it's a range; have to handle both start and end
7704 if ((*i)->end() >= pos
7705 && (*i)->end() < pos+frames
7706 && (*i)->start() >= pos
7707 && (*i)->end() < pos+frames) { // range is completely enclosed; kill it
7709 loc_kill_list.push_back(*i);
7710 } else { // only start or end is included, try to do the right thing
7711 // move start before moving end, to avoid trying to move the end to before the start
7712 // if we're removing more time than the length of the range
7713 if ((*i)->start() >= pos && (*i)->start() < pos+frames) {
7714 // start is within cut
7715 (*i)->set_start (pos, false, true,divisions); // bring the start marker to the beginning of the cut
7717 } else if ((*i)->start() >= pos+frames) {
7718 // start (and thus entire range) lies beyond end of cut
7719 (*i)->set_start ((*i)->start() - frames, false, true, divisions); // slip the start marker back
7722 if ((*i)->end() >= pos && (*i)->end() < pos+frames) {
7723 // end is inside cut
7724 (*i)->set_end (pos, false, true, divisions); // bring the end to the cut
7726 } else if ((*i)->end() >= pos+frames) {
7727 // end is beyond end of cut
7728 (*i)->set_end ((*i)->end() - frames, false, true, divisions); // slip the end marker back
7733 } else if ((*i)->start() >= pos && (*i)->start() < pos+frames ) {
7734 loc_kill_list.push_back(*i);
7736 } else if ((*i)->start() >= pos) {
7737 (*i)->set_start ((*i)->start() -frames, false, true, divisions);
7747 for (list<Location*>::iterator i = loc_kill_list.begin(); i != loc_kill_list.end(); ++i) {
7748 _session->locations()->remove( *i );
7753 begin_reversible_command (_("remove time"));
7756 XMLNode& after (_session->locations()->get_state());
7757 _session->add_command (new MementoCommand<Locations>(*_session->locations(), &before, &after));
7762 XMLNode& before (_session->tempo_map().get_state());
7764 if (_session->tempo_map().remove_time (pos, frames) ) {
7766 begin_reversible_command (_("remove time"));
7769 XMLNode& after (_session->tempo_map().get_state());
7770 _session->add_command (new MementoCommand<TempoMap>(_session->tempo_map(), &before, &after));
7775 commit_reversible_command ();
7780 Editor::fit_selection ()
7782 if (!selection->tracks.empty()) {
7783 fit_tracks (selection->tracks);
7787 /* no selected tracks - use tracks with selected regions */
7789 if (!selection->regions.empty()) {
7790 for (RegionSelection::iterator r = selection->regions.begin(); r != selection->regions.end(); ++r) {
7791 tvl.push_back (&(*r)->get_time_axis_view ());
7797 } else if (internal_editing()) {
7798 /* no selected tracks, or regions, but in internal edit mode, so follow the mouse and use
7801 if (entered_track) {
7802 tvl.push_back (entered_track);
7811 Editor::fit_tracks (TrackViewList & tracks)
7813 if (tracks.empty()) {
7817 uint32_t child_heights = 0;
7818 int visible_tracks = 0;
7820 for (TrackSelection::iterator t = tracks.begin(); t != tracks.end(); ++t) {
7822 if (!(*t)->marked_for_display()) {
7826 child_heights += (*t)->effective_height() - (*t)->current_height();
7830 /* compute the per-track height from:
7832 total canvas visible height -
7833 height that will be taken by visible children of selected
7834 tracks - height of the ruler/hscroll area
7836 uint32_t h = (uint32_t) floor ((trackviews_height() - child_heights) / visible_tracks);
7837 double first_y_pos = DBL_MAX;
7839 if (h < TimeAxisView::preset_height (HeightSmall)) {
7840 MessageDialog msg (_("There are too many tracks to fit in the current window"));
7841 /* too small to be displayed */
7845 undo_visual_stack.push_back (current_visual_state (true));
7846 PBD::Unwinder<bool> nsv (no_save_visual, true);
7848 /* build a list of all tracks, including children */
7851 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
7853 TimeAxisView::Children c = (*i)->get_child_list ();
7854 for (TimeAxisView::Children::iterator j = c.begin(); j != c.end(); ++j) {
7855 all.push_back (j->get());
7860 // find selection range.
7861 // if someone knows how to user TrackViewList::iterator for this
7863 int selected_top = -1;
7864 int selected_bottom = -1;
7866 for (TrackViewList::iterator t = all.begin(); t != all.end(); ++t, ++i) {
7867 if ((*t)->marked_for_display ()) {
7868 if (tracks.contains(*t)) {
7869 if (selected_top == -1) {
7872 selected_bottom = i;
7878 for (TrackViewList::iterator t = all.begin(); t != all.end(); ++t, ++i) {
7879 if ((*t)->marked_for_display ()) {
7880 if (tracks.contains(*t)) {
7881 (*t)->set_height (h);
7882 first_y_pos = std::min ((*t)->y_position (), first_y_pos);
7884 if (i > selected_top && i < selected_bottom) {
7885 hide_track_in_display (*t);
7892 set the controls_layout height now, because waiting for its size
7893 request signal handler will cause the vertical adjustment setting to fail
7896 controls_layout.property_height () = _full_canvas_height;
7897 vertical_adjustment.set_value (first_y_pos);
7899 redo_visual_stack.push_back (current_visual_state (true));
7901 visible_tracks_selector.set_text (_("Sel"));
7905 Editor::save_visual_state (uint32_t n)
7907 while (visual_states.size() <= n) {
7908 visual_states.push_back (0);
7911 if (visual_states[n] != 0) {
7912 delete visual_states[n];
7915 visual_states[n] = current_visual_state (true);
7920 Editor::goto_visual_state (uint32_t n)
7922 if (visual_states.size() <= n) {
7926 if (visual_states[n] == 0) {
7930 use_visual_state (*visual_states[n]);
7934 Editor::start_visual_state_op (uint32_t n)
7936 save_visual_state (n);
7938 PopUp* pup = new PopUp (WIN_POS_MOUSE, 1000, true);
7940 snprintf (buf, sizeof (buf), _("Saved view %u"), n+1);
7941 pup->set_text (buf);
7946 Editor::cancel_visual_state_op (uint32_t n)
7948 goto_visual_state (n);
7952 Editor::toggle_region_mute ()
7954 if (_ignore_region_action) {
7958 RegionSelection rs = get_regions_from_selection_and_entered ();
7964 if (rs.size() > 1) {
7965 begin_reversible_command (_("mute regions"));
7967 begin_reversible_command (_("mute region"));
7970 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
7972 (*i)->region()->playlist()->clear_changes ();
7973 (*i)->region()->set_muted (!(*i)->region()->muted ());
7974 _session->add_command (new StatefulDiffCommand ((*i)->region()));
7978 commit_reversible_command ();
7982 Editor::combine_regions ()
7984 /* foreach track with selected regions, take all selected regions
7985 and join them into a new region containing the subregions (as a
7989 typedef set<RouteTimeAxisView*> RTVS;
7992 if (selection->regions.empty()) {
7996 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
7997 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(&(*i)->get_time_axis_view());
8000 tracks.insert (rtv);
8004 begin_reversible_command (_("combine regions"));
8006 vector<RegionView*> new_selection;
8008 for (RTVS::iterator i = tracks.begin(); i != tracks.end(); ++i) {
8011 if ((rv = (*i)->combine_regions ()) != 0) {
8012 new_selection.push_back (rv);
8016 selection->clear_regions ();
8017 for (vector<RegionView*>::iterator i = new_selection.begin(); i != new_selection.end(); ++i) {
8018 selection->add (*i);
8021 commit_reversible_command ();
8025 Editor::uncombine_regions ()
8027 typedef set<RouteTimeAxisView*> RTVS;
8030 if (selection->regions.empty()) {
8034 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
8035 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(&(*i)->get_time_axis_view());
8038 tracks.insert (rtv);
8042 begin_reversible_command (_("uncombine regions"));
8044 for (RTVS::iterator i = tracks.begin(); i != tracks.end(); ++i) {
8045 (*i)->uncombine_regions ();
8048 commit_reversible_command ();
8052 Editor::toggle_midi_input_active (bool flip_others)
8055 boost::shared_ptr<RouteList> rl (new RouteList);
8057 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
8058 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
8064 boost::shared_ptr<MidiTrack> mt = rtav->midi_track();
8067 rl->push_back (rtav->route());
8068 onoff = !mt->input_active();
8072 _session->set_exclusive_input_active (rl, onoff, flip_others);
8075 static bool ok_fine (GdkEventAny*) { return true; }
8081 lock_dialog = new Gtk::Dialog (string_compose (_("%1: Locked"), PROGRAM_NAME), true);
8083 Gtk::Image* padlock = manage (new Gtk::Image (ARDOUR_UI_UTILS::get_icon ("padlock_closed")));
8084 lock_dialog->get_vbox()->pack_start (*padlock);
8085 lock_dialog->signal_delete_event ().connect (sigc::ptr_fun (ok_fine));
8087 ArdourButton* b = manage (new ArdourButton);
8088 b->set_name ("lock button");
8089 b->set_text (_("Click to unlock"));
8090 b->signal_clicked.connect (sigc::mem_fun (*this, &Editor::unlock));
8091 lock_dialog->get_vbox()->pack_start (*b);
8093 lock_dialog->get_vbox()->show_all ();
8094 lock_dialog->set_size_request (200, 200);
8097 delete _main_menu_disabler;
8098 _main_menu_disabler = new MainMenuDisabler;
8100 lock_dialog->present ();
8102 lock_dialog->get_window()->set_decorations (Gdk::WMDecoration (0));
8108 lock_dialog->hide ();
8110 delete _main_menu_disabler;
8111 _main_menu_disabler = 0;
8113 if (UIConfiguration::instance().get_lock_gui_after_seconds()) {
8114 start_lock_event_timing ();
8119 Editor::bring_in_callback (Gtk::Label* label, uint32_t n, uint32_t total, string name)
8121 Gtkmm2ext::UI::instance()->call_slot (invalidator (*this), boost::bind (&Editor::update_bring_in_message, this, label, n, total, name));
8125 Editor::update_bring_in_message (Gtk::Label* label, uint32_t n, uint32_t total, string name)
8127 Timers::TimerSuspender t;
8128 label->set_text (string_compose ("Copying %1, %2 of %3", name, n, total));
8129 Gtkmm2ext::UI::instance()->flush_pending (1);
8133 Editor::bring_all_sources_into_session ()
8140 ArdourDialog w (_("Moving embedded files into session folder"));
8141 w.get_vbox()->pack_start (msg);
8144 /* flush all pending GUI events because we're about to start copying
8148 Timers::TimerSuspender t;
8149 Gtkmm2ext::UI::instance()->flush_pending (3);
8153 _session->bring_all_sources_into_session (boost::bind (&Editor::bring_in_callback, this, &msg, _1, _2, _3));