2 Copyright (C) 2000-2004 Paul Davis
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 /* Note: public Editor methods are documented in public_editor.h */
31 #include <gtkmm/messagedialog.h>
33 #include "pbd/error.h"
34 #include "pbd/basename.h"
35 #include "pbd/pthread_utils.h"
36 #include "pbd/memento_command.h"
37 #include "pbd/unwind.h"
38 #include "pbd/whitespace.h"
39 #include "pbd/stateful_diff_command.h"
41 #include "gtkmm2ext/utils.h"
43 #include "widgets/choice.h"
44 #include "widgets/popup.h"
45 #include "widgets/prompter.h"
47 #include "ardour/audio_track.h"
48 #include "ardour/audioregion.h"
49 #include "ardour/boost_debug.h"
50 #include "ardour/dB.h"
51 #include "ardour/location.h"
52 #include "ardour/midi_region.h"
53 #include "ardour/midi_track.h"
54 #include "ardour/operations.h"
55 #include "ardour/playlist_factory.h"
56 #include "ardour/profile.h"
57 #include "ardour/quantize.h"
58 #include "ardour/legatize.h"
59 #include "ardour/region_factory.h"
60 #include "ardour/reverse.h"
61 #include "ardour/session.h"
62 #include "ardour/session_playlists.h"
63 #include "ardour/strip_silence.h"
64 #include "ardour/transient_detector.h"
65 #include "ardour/transpose.h"
66 #include "ardour/vca_manager.h"
68 #include "canvas/canvas.h"
71 #include "audio_region_view.h"
72 #include "audio_streamview.h"
73 #include "audio_time_axis.h"
74 #include "automation_region_view.h"
75 #include "automation_time_axis.h"
76 #include "control_point.h"
80 #include "editor_cursors.h"
81 #include "editor_drag.h"
82 #include "editor_regions.h"
83 #include "editor_routes.h"
84 #include "gui_thread.h"
85 #include "insert_remove_time_dialog.h"
86 #include "interthread_progress_window.h"
87 #include "item_counts.h"
89 #include "midi_region_view.h"
91 #include "mixer_strip.h"
92 #include "mouse_cursors.h"
93 #include "normalize_dialog.h"
95 #include "paste_context.h"
96 #include "patch_change_dialog.h"
97 #include "quantize_dialog.h"
98 #include "region_gain_line.h"
99 #include "rgb_macros.h"
100 #include "route_time_axis.h"
101 #include "selection.h"
102 #include "selection_templates.h"
103 #include "streamview.h"
104 #include "strip_silence_dialog.h"
105 #include "time_axis_view.h"
107 #include "transpose_dialog.h"
108 #include "transform_dialog.h"
109 #include "ui_config.h"
110 #include "vca_time_axis.h"
112 #include "pbd/i18n.h"
115 using namespace ARDOUR;
118 using namespace Gtkmm2ext;
119 using namespace ArdourWidgets;
120 using namespace Editing;
121 using Gtkmm2ext::Keyboard;
123 /***********************************************************************
125 ***********************************************************************/
128 Editor::undo (uint32_t n)
130 if (_session && _session->actively_recording()) {
131 /* no undo allowed while recording. Session will check also,
132 but we don't even want to get to that.
137 if (_drags->active ()) {
143 if (_session->undo_depth() == 0) {
144 undo_action->set_sensitive(false);
146 redo_action->set_sensitive(true);
147 begin_selection_op_history ();
152 Editor::redo (uint32_t n)
154 if (_session && _session->actively_recording()) {
155 /* no redo allowed while recording. Session will check also,
156 but we don't even want to get to that.
161 if (_drags->active ()) {
167 if (_session->redo_depth() == 0) {
168 redo_action->set_sensitive(false);
170 undo_action->set_sensitive(true);
171 begin_selection_op_history ();
176 Editor::split_regions_at (MusicFrame where, RegionSelection& regions, bool snap_frame)
180 RegionSelection pre_selected_regions = selection->regions;
181 bool working_on_selection = !pre_selected_regions.empty();
183 list<boost::shared_ptr<Playlist> > used_playlists;
184 list<RouteTimeAxisView*> used_trackviews;
186 if (regions.empty()) {
190 begin_reversible_command (_("split"));
192 // if splitting a single region, and snap-to is using
193 // region boundaries, don't pay attention to them
195 if (regions.size() == 1) {
196 switch (_snap_type) {
197 case SnapToRegionStart:
198 case SnapToRegionSync:
199 case SnapToRegionEnd:
212 EditorFreeze(); /* Emit Signal */
215 for (RegionSelection::iterator a = regions.begin(); a != regions.end(); ) {
217 RegionSelection::iterator tmp;
219 /* XXX this test needs to be more complicated, to make sure we really
220 have something to split.
223 if (!(*a)->region()->covers (where.frame)) {
231 boost::shared_ptr<Playlist> pl = (*a)->region()->playlist();
239 /* we haven't seen this playlist before */
241 /* remember used playlists so we can thaw them later */
242 used_playlists.push_back(pl);
244 TimeAxisView& tv = (*a)->get_time_axis_view();
245 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (&tv);
247 used_trackviews.push_back (rtv);
254 pl->clear_changes ();
255 pl->split_region ((*a)->region(), where);
256 _session->add_command (new StatefulDiffCommand (pl));
262 latest_regionviews.clear ();
264 vector<sigc::connection> region_added_connections;
266 for (list<RouteTimeAxisView*>::iterator i = used_trackviews.begin(); i != used_trackviews.end(); ++i) {
267 region_added_connections.push_back ((*i)->view()->RegionViewAdded.connect (sigc::mem_fun(*this, &Editor::collect_new_region_view)));
270 while (used_playlists.size() > 0) {
271 list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
273 used_playlists.pop_front();
276 for (vector<sigc::connection>::iterator c = region_added_connections.begin(); c != region_added_connections.end(); ++c) {
281 EditorThaw(); /* Emit Signal */
284 if (working_on_selection) {
285 // IFF we were working on selected regions, try to reinstate the other region selections that existed before the freeze/thaw.
287 RegionSelectionAfterSplit rsas = Config->get_region_selection_after_split();
288 /* There are three classes of regions that we might want selected after
289 splitting selected regions:
290 - regions selected before the split operation, and unaffected by it
291 - newly-created regions before the split
292 - newly-created regions after the split
295 if (rsas & Existing) {
296 // region selections that existed before the split.
297 selection->add ( pre_selected_regions );
300 for (RegionSelection::iterator ri = latest_regionviews.begin(); ri != latest_regionviews.end(); ri++) {
301 if ((*ri)->region()->position() < where.frame) {
302 // new regions created before the split
303 if (rsas & NewlyCreatedLeft) {
304 selection->add (*ri);
307 // new regions created after the split
308 if (rsas & NewlyCreatedRight) {
309 selection->add (*ri);
314 if( working_on_selection ) {
315 selection->add (latest_regionviews); //these are the new regions created after the split
319 commit_reversible_command ();
322 /** Move one extreme of the current range selection. If more than one range is selected,
323 * the start of the earliest range or the end of the latest range is moved.
325 * @param move_end true to move the end of the current range selection, false to move
327 * @param next true to move the extreme to the next region boundary, false to move to
331 Editor::move_range_selection_start_or_end_to_region_boundary (bool move_end, bool next)
333 if (selection->time.start() == selection->time.end_frame()) {
337 framepos_t start = selection->time.start ();
338 framepos_t end = selection->time.end_frame ();
340 /* the position of the thing we may move */
341 framepos_t pos = move_end ? end : start;
342 int dir = next ? 1 : -1;
344 /* so we don't find the current region again */
345 if (dir > 0 || pos > 0) {
349 framepos_t const target = get_region_boundary (pos, dir, true, false);
364 begin_reversible_selection_op (_("alter selection"));
365 selection->set_preserving_all_ranges (start, end);
366 commit_reversible_selection_op ();
370 Editor::nudge_forward_release (GdkEventButton* ev)
372 if (ev->state & Keyboard::PrimaryModifier) {
373 nudge_forward (false, true);
375 nudge_forward (false, false);
381 Editor::nudge_backward_release (GdkEventButton* ev)
383 if (ev->state & Keyboard::PrimaryModifier) {
384 nudge_backward (false, true);
386 nudge_backward (false, false);
393 Editor::nudge_forward (bool next, bool force_playhead)
396 framepos_t next_distance;
402 RegionSelection rs = get_regions_from_selection_and_entered ();
404 if (!force_playhead && !rs.empty()) {
406 begin_reversible_command (_("nudge regions forward"));
408 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
409 boost::shared_ptr<Region> r ((*i)->region());
411 distance = get_nudge_distance (r->position(), next_distance);
414 distance = next_distance;
418 r->set_position (r->position() + distance);
419 _session->add_command (new StatefulDiffCommand (r));
422 commit_reversible_command ();
425 } else if (!force_playhead && !selection->markers.empty()) {
428 bool in_command = false;
429 const int32_t divisions = get_grid_music_divisions (0);
431 for (MarkerSelection::iterator i = selection->markers.begin(); i != selection->markers.end(); ++i) {
433 Location* loc = find_location_from_marker ((*i), is_start);
437 XMLNode& before (loc->get_state());
440 distance = get_nudge_distance (loc->start(), next_distance);
442 distance = next_distance;
444 if (max_framepos - distance > loc->start() + loc->length()) {
445 loc->set_start (loc->start() + distance, false, true, divisions);
447 loc->set_start (max_framepos - loc->length(), false, true, divisions);
450 distance = get_nudge_distance (loc->end(), next_distance);
452 distance = next_distance;
454 if (max_framepos - distance > loc->end()) {
455 loc->set_end (loc->end() + distance, false, true, divisions);
457 loc->set_end (max_framepos, false, true, divisions);
459 if (loc->is_session_range()) {
460 _session->set_end_is_free (false);
464 begin_reversible_command (_("nudge location forward"));
467 XMLNode& after (loc->get_state());
468 _session->add_command (new MementoCommand<Location>(*loc, &before, &after));
473 commit_reversible_command ();
476 distance = get_nudge_distance (playhead_cursor->current_frame (), next_distance);
477 _session->request_locate (playhead_cursor->current_frame () + distance);
482 Editor::nudge_backward (bool next, bool force_playhead)
485 framepos_t next_distance;
491 RegionSelection rs = get_regions_from_selection_and_entered ();
493 if (!force_playhead && !rs.empty()) {
495 begin_reversible_command (_("nudge regions backward"));
497 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
498 boost::shared_ptr<Region> r ((*i)->region());
500 distance = get_nudge_distance (r->position(), next_distance);
503 distance = next_distance;
508 if (r->position() > distance) {
509 r->set_position (r->position() - distance);
513 _session->add_command (new StatefulDiffCommand (r));
516 commit_reversible_command ();
518 } else if (!force_playhead && !selection->markers.empty()) {
521 bool in_command = false;
523 for (MarkerSelection::iterator i = selection->markers.begin(); i != selection->markers.end(); ++i) {
525 Location* loc = find_location_from_marker ((*i), is_start);
529 XMLNode& before (loc->get_state());
532 distance = get_nudge_distance (loc->start(), next_distance);
534 distance = next_distance;
536 if (distance < loc->start()) {
537 loc->set_start (loc->start() - distance, false, true, get_grid_music_divisions(0));
539 loc->set_start (0, false, true, get_grid_music_divisions(0));
542 distance = get_nudge_distance (loc->end(), next_distance);
545 distance = next_distance;
548 if (distance < loc->end() - loc->length()) {
549 loc->set_end (loc->end() - distance, false, true, get_grid_music_divisions(0));
551 loc->set_end (loc->length(), false, true, get_grid_music_divisions(0));
553 if (loc->is_session_range()) {
554 _session->set_end_is_free (false);
558 begin_reversible_command (_("nudge location forward"));
561 XMLNode& after (loc->get_state());
562 _session->add_command (new MementoCommand<Location>(*loc, &before, &after));
566 commit_reversible_command ();
571 distance = get_nudge_distance (playhead_cursor->current_frame (), next_distance);
573 if (playhead_cursor->current_frame () > distance) {
574 _session->request_locate (playhead_cursor->current_frame () - distance);
576 _session->goto_start();
582 Editor::nudge_forward_capture_offset ()
584 RegionSelection rs = get_regions_from_selection_and_entered ();
586 if (!_session || rs.empty()) {
590 begin_reversible_command (_("nudge forward"));
592 framepos_t const distance = _session->worst_output_latency();
594 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
595 boost::shared_ptr<Region> r ((*i)->region());
598 r->set_position (r->position() + distance);
599 _session->add_command(new StatefulDiffCommand (r));
602 commit_reversible_command ();
606 Editor::nudge_backward_capture_offset ()
608 RegionSelection rs = get_regions_from_selection_and_entered ();
610 if (!_session || rs.empty()) {
614 begin_reversible_command (_("nudge backward"));
616 framepos_t const distance = _session->worst_output_latency();
618 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
619 boost::shared_ptr<Region> r ((*i)->region());
623 if (r->position() > distance) {
624 r->set_position (r->position() - distance);
628 _session->add_command(new StatefulDiffCommand (r));
631 commit_reversible_command ();
634 struct RegionSelectionPositionSorter {
635 bool operator() (RegionView* a, RegionView* b) {
636 return a->region()->position() < b->region()->position();
641 Editor::sequence_regions ()
644 framepos_t r_end_prev;
652 RegionSelection rs = get_regions_from_selection_and_entered ();
653 rs.sort(RegionSelectionPositionSorter());
657 bool in_command = false;
659 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
660 boost::shared_ptr<Region> r ((*i)->region());
668 if(r->position_locked())
675 r->set_position(r_end_prev);
679 begin_reversible_command (_("sequence regions"));
682 _session->add_command (new StatefulDiffCommand (r));
684 r_end=r->position() + r->length();
690 commit_reversible_command ();
699 Editor::move_to_start ()
701 _session->goto_start ();
705 Editor::move_to_end ()
708 _session->request_locate (_session->current_end_frame());
712 Editor::build_region_boundary_cache ()
715 vector<RegionPoint> interesting_points;
716 boost::shared_ptr<Region> r;
717 TrackViewList tracks;
720 region_boundary_cache.clear ();
726 bool maybe_first_frame = false;
728 switch (_snap_type) {
729 case SnapToRegionStart:
730 interesting_points.push_back (Start);
731 maybe_first_frame = true;
733 case SnapToRegionEnd:
734 interesting_points.push_back (End);
736 case SnapToRegionSync:
737 interesting_points.push_back (SyncPoint);
739 case SnapToRegionBoundary:
740 interesting_points.push_back (Start);
741 interesting_points.push_back (End);
742 maybe_first_frame = true;
745 fatal << string_compose (_("build_region_boundary_cache called with snap_type = %1"), _snap_type) << endmsg;
746 abort(); /*NOTREACHED*/
750 TimeAxisView *ontrack = 0;
753 if (!selection->tracks.empty()) {
754 tlist = selection->tracks.filter_to_unique_playlists ();
756 tlist = track_views.filter_to_unique_playlists ();
759 if (maybe_first_frame) {
760 TrackViewList::const_iterator i;
761 for (i = tlist.begin(); i != tlist.end(); ++i) {
762 boost::shared_ptr<Playlist> pl = (*i)->playlist();
763 if (pl && pl->count_regions_at (0)) {
764 region_boundary_cache.push_back (0);
770 while (pos < _session->current_end_frame() && !at_end) {
773 framepos_t lpos = max_framepos;
775 for (vector<RegionPoint>::iterator p = interesting_points.begin(); p != interesting_points.end(); ++p) {
777 if ((r = find_next_region (pos, *p, 1, tlist, &ontrack)) == 0) {
778 if (*p == interesting_points.back()) {
781 /* move to next point type */
787 rpos = r->first_frame();
791 rpos = r->last_frame();
795 rpos = r->sync_position ();
803 RouteTimeAxisView *rtav;
805 if (ontrack != 0 && (rtav = dynamic_cast<RouteTimeAxisView*>(ontrack)) != 0 ) {
806 if (rtav->track() != 0) {
807 speed = rtav->track()->speed();
811 rpos = track_frame_to_session_frame (rpos, speed);
817 /* prevent duplicates, but we don't use set<> because we want to be able
821 vector<framepos_t>::iterator ri;
823 for (ri = region_boundary_cache.begin(); ri != region_boundary_cache.end(); ++ri) {
829 if (ri == region_boundary_cache.end()) {
830 region_boundary_cache.push_back (rpos);
837 /* finally sort to be sure that the order is correct */
839 sort (region_boundary_cache.begin(), region_boundary_cache.end());
842 boost::shared_ptr<Region>
843 Editor::find_next_region (framepos_t frame, RegionPoint point, int32_t dir, TrackViewList& tracks, TimeAxisView **ontrack)
845 TrackViewList::iterator i;
846 framepos_t closest = max_framepos;
847 boost::shared_ptr<Region> ret;
851 framepos_t track_frame;
852 RouteTimeAxisView *rtav;
854 for (i = tracks.begin(); i != tracks.end(); ++i) {
857 boost::shared_ptr<Region> r;
860 if ( (rtav = dynamic_cast<RouteTimeAxisView*>(*i)) != 0 ) {
861 if (rtav->track()!=0)
862 track_speed = rtav->track()->speed();
865 track_frame = session_frame_to_track_frame(frame, track_speed);
867 if ((r = (*i)->find_next_region (track_frame, point, dir)) == 0) {
873 rpos = r->first_frame ();
877 rpos = r->last_frame ();
881 rpos = r->sync_position ();
885 // rpos is a "track frame", converting it to "_session frame"
886 rpos = track_frame_to_session_frame(rpos, track_speed);
889 distance = rpos - frame;
891 distance = frame - rpos;
894 if (distance < closest) {
906 Editor::find_next_region_boundary (framepos_t pos, int32_t dir, const TrackViewList& tracks)
908 framecnt_t distance = max_framepos;
909 framepos_t current_nearest = -1;
911 for (TrackViewList::const_iterator i = tracks.begin(); i != tracks.end(); ++i) {
912 framepos_t contender;
915 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*i);
921 if ((contender = rtv->find_next_region_boundary (pos, dir)) < 0) {
925 d = ::llabs (pos - contender);
928 current_nearest = contender;
933 return current_nearest;
937 Editor::get_region_boundary (framepos_t pos, int32_t dir, bool with_selection, bool only_onscreen)
942 if (with_selection && Config->get_region_boundaries_from_selected_tracks()) {
944 if (!selection->tracks.empty()) {
946 target = find_next_region_boundary (pos, dir, selection->tracks);
950 if (only_onscreen || Config->get_region_boundaries_from_onscreen_tracks()) {
951 get_onscreen_tracks (tvl);
952 target = find_next_region_boundary (pos, dir, tvl);
954 target = find_next_region_boundary (pos, dir, track_views);
960 if (only_onscreen || Config->get_region_boundaries_from_onscreen_tracks()) {
961 get_onscreen_tracks (tvl);
962 target = find_next_region_boundary (pos, dir, tvl);
964 target = find_next_region_boundary (pos, dir, track_views);
972 Editor::cursor_to_region_boundary (bool with_selection, int32_t dir)
974 framepos_t pos = playhead_cursor->current_frame ();
981 // so we don't find the current region again..
982 if (dir > 0 || pos > 0) {
986 if ((target = get_region_boundary (pos, dir, with_selection, false)) < 0) {
990 _session->request_locate (target);
994 Editor::cursor_to_next_region_boundary (bool with_selection)
996 cursor_to_region_boundary (with_selection, 1);
1000 Editor::cursor_to_previous_region_boundary (bool with_selection)
1002 cursor_to_region_boundary (with_selection, -1);
1006 Editor::cursor_to_region_point (EditorCursor* cursor, RegionPoint point, int32_t dir)
1008 boost::shared_ptr<Region> r;
1009 framepos_t pos = cursor->current_frame ();
1015 TimeAxisView *ontrack = 0;
1017 // so we don't find the current region again..
1021 if (!selection->tracks.empty()) {
1023 r = find_next_region (pos, point, dir, selection->tracks, &ontrack);
1025 } else if (clicked_axisview) {
1028 t.push_back (clicked_axisview);
1030 r = find_next_region (pos, point, dir, t, &ontrack);
1034 r = find_next_region (pos, point, dir, track_views, &ontrack);
1043 pos = r->first_frame ();
1047 pos = r->last_frame ();
1051 pos = r->sync_position ();
1056 RouteTimeAxisView *rtav;
1058 if ( ontrack != 0 && (rtav = dynamic_cast<RouteTimeAxisView*>(ontrack)) != 0 ) {
1059 if (rtav->track() != 0) {
1060 speed = rtav->track()->speed();
1064 pos = track_frame_to_session_frame(pos, speed);
1066 if (cursor == playhead_cursor) {
1067 _session->request_locate (pos);
1069 cursor->set_position (pos);
1074 Editor::cursor_to_next_region_point (EditorCursor* cursor, RegionPoint point)
1076 cursor_to_region_point (cursor, point, 1);
1080 Editor::cursor_to_previous_region_point (EditorCursor* cursor, RegionPoint point)
1082 cursor_to_region_point (cursor, point, -1);
1086 Editor::cursor_to_selection_start (EditorCursor *cursor)
1090 switch (mouse_mode) {
1092 if (!selection->regions.empty()) {
1093 pos = selection->regions.start();
1098 if (!selection->time.empty()) {
1099 pos = selection->time.start ();
1107 if (cursor == playhead_cursor) {
1108 _session->request_locate (pos);
1110 cursor->set_position (pos);
1115 Editor::cursor_to_selection_end (EditorCursor *cursor)
1119 switch (mouse_mode) {
1121 if (!selection->regions.empty()) {
1122 pos = selection->regions.end_frame();
1127 if (!selection->time.empty()) {
1128 pos = selection->time.end_frame ();
1136 if (cursor == playhead_cursor) {
1137 _session->request_locate (pos);
1139 cursor->set_position (pos);
1144 Editor::selected_marker_to_region_boundary (bool with_selection, int32_t dir)
1154 if (selection->markers.empty()) {
1158 if (!mouse_frame (mouse, ignored)) {
1162 add_location_mark (mouse);
1165 if ((loc = find_location_from_marker (selection->markers.front(), ignored)) == 0) {
1169 framepos_t pos = loc->start();
1171 // so we don't find the current region again..
1172 if (dir > 0 || pos > 0) {
1176 if ((target = get_region_boundary (pos, dir, with_selection, false)) < 0) {
1180 loc->move_to (target, 0);
1184 Editor::selected_marker_to_next_region_boundary (bool with_selection)
1186 selected_marker_to_region_boundary (with_selection, 1);
1190 Editor::selected_marker_to_previous_region_boundary (bool with_selection)
1192 selected_marker_to_region_boundary (with_selection, -1);
1196 Editor::selected_marker_to_region_point (RegionPoint point, int32_t dir)
1198 boost::shared_ptr<Region> r;
1203 if (!_session || selection->markers.empty()) {
1207 if ((loc = find_location_from_marker (selection->markers.front(), ignored)) == 0) {
1211 TimeAxisView *ontrack = 0;
1215 // so we don't find the current region again..
1219 if (!selection->tracks.empty()) {
1221 r = find_next_region (pos, point, dir, selection->tracks, &ontrack);
1225 r = find_next_region (pos, point, dir, track_views, &ontrack);
1234 pos = r->first_frame ();
1238 pos = r->last_frame ();
1242 pos = r->adjust_to_sync (r->first_frame());
1247 RouteTimeAxisView *rtav;
1249 if (ontrack != 0 && (rtav = dynamic_cast<RouteTimeAxisView*>(ontrack)) != 0) {
1250 if (rtav->track() != 0) {
1251 speed = rtav->track()->speed();
1255 pos = track_frame_to_session_frame(pos, speed);
1257 loc->move_to (pos, 0);
1261 Editor::selected_marker_to_next_region_point (RegionPoint point)
1263 selected_marker_to_region_point (point, 1);
1267 Editor::selected_marker_to_previous_region_point (RegionPoint point)
1269 selected_marker_to_region_point (point, -1);
1273 Editor::selected_marker_to_selection_start ()
1279 if (!_session || selection->markers.empty()) {
1283 if ((loc = find_location_from_marker (selection->markers.front(), ignored)) == 0) {
1287 switch (mouse_mode) {
1289 if (!selection->regions.empty()) {
1290 pos = selection->regions.start();
1295 if (!selection->time.empty()) {
1296 pos = selection->time.start ();
1304 loc->move_to (pos, 0);
1308 Editor::selected_marker_to_selection_end ()
1314 if (!_session || selection->markers.empty()) {
1318 if ((loc = find_location_from_marker (selection->markers.front(), ignored)) == 0) {
1322 switch (mouse_mode) {
1324 if (!selection->regions.empty()) {
1325 pos = selection->regions.end_frame();
1330 if (!selection->time.empty()) {
1331 pos = selection->time.end_frame ();
1339 loc->move_to (pos, 0);
1343 Editor::scroll_playhead (bool forward)
1345 framepos_t pos = playhead_cursor->current_frame ();
1346 framecnt_t delta = (framecnt_t) floor (current_page_samples() / 0.8);
1349 if (pos == max_framepos) {
1353 if (pos < max_framepos - delta) {
1372 _session->request_locate (pos);
1376 Editor::cursor_align (bool playhead_to_edit)
1382 if (playhead_to_edit) {
1384 if (selection->markers.empty()) {
1388 _session->request_locate (selection->markers.front()->position(), _session->transport_rolling());
1391 const int32_t divisions = get_grid_music_divisions (0);
1392 /* move selected markers to playhead */
1394 for (MarkerSelection::iterator i = selection->markers.begin(); i != selection->markers.end(); ++i) {
1397 Location* loc = find_location_from_marker (*i, ignored);
1399 if (loc->is_mark()) {
1400 loc->set_start (playhead_cursor->current_frame (), false, true, divisions);
1402 loc->set (playhead_cursor->current_frame (),
1403 playhead_cursor->current_frame () + loc->length(), true, divisions);
1410 Editor::scroll_backward (float pages)
1412 framepos_t const one_page = (framepos_t) rint (_visible_canvas_width * samples_per_pixel);
1413 framepos_t const cnt = (framepos_t) floor (pages * one_page);
1416 if (leftmost_frame < cnt) {
1419 frame = leftmost_frame - cnt;
1422 reset_x_origin (frame);
1426 Editor::scroll_forward (float pages)
1428 framepos_t const one_page = (framepos_t) rint (_visible_canvas_width * samples_per_pixel);
1429 framepos_t const cnt = (framepos_t) floor (pages * one_page);
1432 if (max_framepos - cnt < leftmost_frame) {
1433 frame = max_framepos - cnt;
1435 frame = leftmost_frame + cnt;
1438 reset_x_origin (frame);
1442 Editor::scroll_tracks_down ()
1444 double vert_value = vertical_adjustment.get_value() + vertical_adjustment.get_page_size();
1445 if (vert_value > vertical_adjustment.get_upper() - _visible_canvas_height) {
1446 vert_value = vertical_adjustment.get_upper() - _visible_canvas_height;
1449 vertical_adjustment.set_value (vert_value);
1453 Editor::scroll_tracks_up ()
1455 vertical_adjustment.set_value (vertical_adjustment.get_value() - vertical_adjustment.get_page_size());
1459 Editor::scroll_tracks_down_line ()
1461 double vert_value = vertical_adjustment.get_value() + 60;
1463 if (vert_value > vertical_adjustment.get_upper() - _visible_canvas_height) {
1464 vert_value = vertical_adjustment.get_upper() - _visible_canvas_height;
1467 vertical_adjustment.set_value (vert_value);
1471 Editor::scroll_tracks_up_line ()
1473 reset_y_origin (vertical_adjustment.get_value() - 60);
1477 Editor::select_topmost_track ()
1479 const double top_of_trackviews = vertical_adjustment.get_value();
1480 for (TrackViewList::iterator t = track_views.begin(); t != track_views.end(); ++t) {
1481 if ((*t)->hidden()) {
1484 std::pair<TimeAxisView*,double> res = (*t)->covers_y_position (top_of_trackviews);
1486 selection->set (*t);
1493 Editor::scroll_down_one_track (bool skip_child_views)
1495 TrackViewList::reverse_iterator next = track_views.rend();
1496 const double top_of_trackviews = vertical_adjustment.get_value();
1498 for (TrackViewList::reverse_iterator t = track_views.rbegin(); t != track_views.rend(); ++t) {
1499 if ((*t)->hidden()) {
1503 /* If this is the upper-most visible trackview, we want to display
1504 * the one above it (next)
1506 * Note that covers_y_position() is recursive and includes child views
1508 std::pair<TimeAxisView*,double> res = (*t)->covers_y_position (top_of_trackviews);
1511 if (skip_child_views) {
1514 /* automation lane (one level, non-recursive)
1516 * - if no automation lane exists -> move to next tack
1517 * - if the first (here: bottom-most) matches -> move to next tack
1518 * - if no y-axis match is found -> the current track is at the top
1519 * -> move to last (here: top-most) automation lane
1521 TimeAxisView::Children kids = (*t)->get_child_list();
1522 TimeAxisView::Children::reverse_iterator nkid = kids.rend();
1524 for (TimeAxisView::Children::reverse_iterator ci = kids.rbegin(); ci != kids.rend(); ++ci) {
1525 if ((*ci)->hidden()) {
1529 std::pair<TimeAxisView*,double> dev;
1530 dev = (*ci)->covers_y_position (top_of_trackviews);
1532 /* some automation lane is currently at the top */
1533 if (ci == kids.rbegin()) {
1534 /* first (bottom-most) autmation lane is at the top.
1535 * -> move to next track
1544 if (nkid != kids.rend()) {
1545 ensure_time_axis_view_is_visible (**nkid, true);
1553 /* move to the track below the first one that covers the */
1555 if (next != track_views.rend()) {
1556 ensure_time_axis_view_is_visible (**next, true);
1564 Editor::scroll_up_one_track (bool skip_child_views)
1566 TrackViewList::iterator prev = track_views.end();
1567 double top_of_trackviews = vertical_adjustment.get_value ();
1569 for (TrackViewList::iterator t = track_views.begin(); t != track_views.end(); ++t) {
1571 if ((*t)->hidden()) {
1575 /* find the trackview at the top of the trackview group
1577 * Note that covers_y_position() is recursive and includes child views
1579 std::pair<TimeAxisView*,double> res = (*t)->covers_y_position (top_of_trackviews);
1582 if (skip_child_views) {
1585 /* automation lane (one level, non-recursive)
1587 * - if no automation lane exists -> move to prev tack
1588 * - if no y-axis match is found -> the current track is at the top -> move to prev track
1589 * (actually last automation lane of previous track, see below)
1590 * - if first (top-most) lane is at the top -> move to this track
1591 * - else move up one lane
1593 TimeAxisView::Children kids = (*t)->get_child_list();
1594 TimeAxisView::Children::iterator pkid = kids.end();
1596 for (TimeAxisView::Children::iterator ci = kids.begin(); ci != kids.end(); ++ci) {
1597 if ((*ci)->hidden()) {
1601 std::pair<TimeAxisView*,double> dev;
1602 dev = (*ci)->covers_y_position (top_of_trackviews);
1604 /* some automation lane is currently at the top */
1605 if (ci == kids.begin()) {
1606 /* first (top-most) autmation lane is at the top.
1607 * jump directly to this track's top
1609 ensure_time_axis_view_is_visible (**t, true);
1612 else if (pkid != kids.end()) {
1613 /* some other automation lane is at the top.
1614 * move up to prev automation lane.
1616 ensure_time_axis_view_is_visible (**pkid, true);
1619 assert(0); // not reached
1630 if (prev != track_views.end()) {
1631 // move to bottom-most automation-lane of the previous track
1632 TimeAxisView::Children kids = (*prev)->get_child_list();
1633 TimeAxisView::Children::reverse_iterator pkid = kids.rend();
1634 if (!skip_child_views) {
1635 // find the last visible lane
1636 for (TimeAxisView::Children::reverse_iterator ci = kids.rbegin(); ci != kids.rend(); ++ci) {
1637 if (!(*ci)->hidden()) {
1643 if (pkid != kids.rend()) {
1644 ensure_time_axis_view_is_visible (**pkid, true);
1646 ensure_time_axis_view_is_visible (**prev, true);
1655 Editor::scroll_left_step ()
1657 framepos_t xdelta = (current_page_samples() / 8);
1659 if (leftmost_frame > xdelta) {
1660 reset_x_origin (leftmost_frame - xdelta);
1668 Editor::scroll_right_step ()
1670 framepos_t xdelta = (current_page_samples() / 8);
1672 if (max_framepos - xdelta > leftmost_frame) {
1673 reset_x_origin (leftmost_frame + xdelta);
1675 reset_x_origin (max_framepos - current_page_samples());
1680 Editor::scroll_left_half_page ()
1682 framepos_t xdelta = (current_page_samples() / 2);
1683 if (leftmost_frame > xdelta) {
1684 reset_x_origin (leftmost_frame - xdelta);
1691 Editor::scroll_right_half_page ()
1693 framepos_t xdelta = (current_page_samples() / 2);
1694 if (max_framepos - xdelta > leftmost_frame) {
1695 reset_x_origin (leftmost_frame + xdelta);
1697 reset_x_origin (max_framepos - current_page_samples());
1704 Editor::tav_zoom_step (bool coarser)
1706 DisplaySuspender ds;
1710 if (selection->tracks.empty()) {
1713 ts = &selection->tracks;
1716 for (TrackViewList::iterator i = ts->begin(); i != ts->end(); ++i) {
1717 TimeAxisView *tv = (static_cast<TimeAxisView*>(*i));
1718 tv->step_height (coarser);
1723 Editor::tav_zoom_smooth (bool coarser, bool force_all)
1725 DisplaySuspender ds;
1729 if (selection->tracks.empty() || force_all) {
1732 ts = &selection->tracks;
1735 for (TrackViewList::iterator i = ts->begin(); i != ts->end(); ++i) {
1736 TimeAxisView *tv = (static_cast<TimeAxisView*>(*i));
1737 uint32_t h = tv->current_height ();
1742 if (h >= TimeAxisView::preset_height (HeightSmall)) {
1747 tv->set_height (h + 5);
1753 Editor::temporal_zoom_step_mouse_focus_scale (bool zoom_out, double scale)
1755 Editing::ZoomFocus temp_focus = zoom_focus;
1756 zoom_focus = Editing::ZoomFocusMouse;
1757 temporal_zoom_step_scale (zoom_out, scale);
1758 zoom_focus = temp_focus;
1762 Editor::temporal_zoom_step_mouse_focus (bool zoom_out)
1764 temporal_zoom_step_mouse_focus_scale (zoom_out, 2.0);
1768 Editor::temporal_zoom_step (bool zoom_out)
1770 temporal_zoom_step_scale (zoom_out, 2.0);
1774 Editor::temporal_zoom_step_scale (bool zoom_out, double scale)
1776 ENSURE_GUI_THREAD (*this, &Editor::temporal_zoom_step, zoom_out, scale)
1778 framecnt_t nspp = samples_per_pixel;
1782 if (nspp == samples_per_pixel) {
1787 if (nspp == samples_per_pixel) {
1792 //zoom-behavior-tweaks
1793 //limit our maximum zoom to the session gui extents value
1794 std::pair<framepos_t, framepos_t> ext = session_gui_extents();
1795 framecnt_t session_extents_pp = ( ext.second - ext.first ) / _visible_canvas_width;
1796 if (nspp > session_extents_pp)
1797 nspp = session_extents_pp;
1799 temporal_zoom (nspp);
1803 Editor::temporal_zoom (framecnt_t fpp)
1809 framepos_t current_page = current_page_samples();
1810 framepos_t current_leftmost = leftmost_frame;
1811 framepos_t current_rightmost;
1812 framepos_t current_center;
1813 framepos_t new_page_size;
1814 framepos_t half_page_size;
1815 framepos_t leftmost_after_zoom = 0;
1817 bool in_track_canvas;
1818 bool use_mouse_frame = true;
1822 if (fpp == samples_per_pixel) {
1826 // Imposing an arbitrary limit to zoom out as too much zoom out produces
1827 // segfaults for lack of memory. If somebody decides this is not high enough I
1828 // believe it can be raisen to higher values but some limit must be in place.
1830 // This constant represents 1 day @ 48kHz on a 1600 pixel wide display
1831 // all of which is used for the editor track displays. The whole day
1832 // would be 4147200000 samples, so 2592000 samples per pixel.
1834 nfpp = min (fpp, (framecnt_t) 2592000);
1835 nfpp = max ((framecnt_t) 1, nfpp);
1837 new_page_size = (framepos_t) floor (_visible_canvas_width * nfpp);
1838 half_page_size = new_page_size / 2;
1840 switch (zoom_focus) {
1842 leftmost_after_zoom = current_leftmost;
1845 case ZoomFocusRight:
1846 current_rightmost = leftmost_frame + current_page;
1847 if (current_rightmost < new_page_size) {
1848 leftmost_after_zoom = 0;
1850 leftmost_after_zoom = current_rightmost - new_page_size;
1854 case ZoomFocusCenter:
1855 current_center = current_leftmost + (current_page/2);
1856 if (current_center < half_page_size) {
1857 leftmost_after_zoom = 0;
1859 leftmost_after_zoom = current_center - half_page_size;
1863 case ZoomFocusPlayhead:
1864 /* centre playhead */
1865 l = playhead_cursor->current_frame () - (new_page_size * 0.5);
1868 leftmost_after_zoom = 0;
1869 } else if (l > max_framepos) {
1870 leftmost_after_zoom = max_framepos - new_page_size;
1872 leftmost_after_zoom = (framepos_t) l;
1876 case ZoomFocusMouse:
1877 /* try to keep the mouse over the same point in the display */
1879 if (_drags->active()) {
1880 where = _drags->current_pointer_frame ();
1881 } else if (!mouse_frame (where, in_track_canvas)) {
1882 use_mouse_frame = false;
1885 if (use_mouse_frame) {
1886 l = - ((new_page_size * ((where - current_leftmost)/(double)current_page)) - where);
1889 leftmost_after_zoom = 0;
1890 } else if (l > max_framepos) {
1891 leftmost_after_zoom = max_framepos - new_page_size;
1893 leftmost_after_zoom = (framepos_t) l;
1896 /* use playhead instead */
1897 where = playhead_cursor->current_frame ();
1899 if (where < half_page_size) {
1900 leftmost_after_zoom = 0;
1902 leftmost_after_zoom = where - half_page_size;
1908 /* try to keep the edit point in the same place */
1909 where = get_preferred_edit_position ();
1913 double l = - ((new_page_size * ((where - current_leftmost)/(double)current_page)) - where);
1916 leftmost_after_zoom = 0;
1917 } else if (l > max_framepos) {
1918 leftmost_after_zoom = max_framepos - new_page_size;
1920 leftmost_after_zoom = (framepos_t) l;
1924 /* edit point not defined */
1931 // leftmost_after_zoom = min (leftmost_after_zoom, _session->current_end_frame());
1933 reposition_and_zoom (leftmost_after_zoom, nfpp);
1937 Editor::calc_extra_zoom_edges(framepos_t &start, framepos_t &end)
1939 /* this func helps make sure we leave a little space
1940 at each end of the editor so that the zoom doesn't fit the region
1941 precisely to the screen.
1944 GdkScreen* screen = gdk_screen_get_default ();
1945 const gint pixwidth = gdk_screen_get_width (screen);
1946 const gint mmwidth = gdk_screen_get_width_mm (screen);
1947 const double pix_per_mm = (double) pixwidth/ (double) mmwidth;
1948 const double one_centimeter_in_pixels = pix_per_mm * 10.0;
1950 const framepos_t range = end - start;
1951 const framecnt_t new_fpp = (framecnt_t) ceil ((double) range / (double) _visible_canvas_width);
1952 const framepos_t extra_samples = (framepos_t) floor (one_centimeter_in_pixels * new_fpp);
1954 if (start > extra_samples) {
1955 start -= extra_samples;
1960 if (max_framepos - extra_samples > end) {
1961 end += extra_samples;
1968 Editor::get_selection_extents (framepos_t &start, framepos_t &end) const
1970 start = max_framepos;
1974 //ToDo: if notes are selected, set extents to that selection
1976 //ToDo: if control points are selected, set extents to that selection
1978 if ( !selection->regions.empty() ) {
1979 RegionSelection rs = get_regions_from_selection_and_entered ();
1981 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
1983 if ((*i)->region()->position() < start) {
1984 start = (*i)->region()->position();
1987 if ((*i)->region()->last_frame() + 1 > end) {
1988 end = (*i)->region()->last_frame() + 1;
1992 } else if (!selection->time.empty()) {
1993 start = selection->time.start();
1994 end = selection->time.end_frame();
1996 ret = false; //no selection found
1999 if ((start == 0 && end == 0) || end < start) {
2008 Editor::temporal_zoom_selection (Editing::ZoomAxis axes)
2010 if (!selection) return;
2012 //ToDo: if notes are selected, zoom to that
2014 //ToDo: if control points are selected, zoom to that
2016 if (axes == Horizontal || axes == Both) {
2018 framepos_t start, end;
2019 if (get_selection_extents (start, end)) {
2020 calc_extra_zoom_edges (start, end);
2021 temporal_zoom_by_frame (start, end);
2025 if (axes == Vertical || axes == Both) {
2031 Editor::temporal_zoom_session ()
2033 ENSURE_GUI_THREAD (*this, &Editor::temporal_zoom_session)
2036 framecnt_t start = _session->current_start_frame();
2037 framecnt_t end = _session->current_end_frame();
2039 if (_session->actively_recording () ) {
2040 framepos_t cur = playhead_cursor->current_frame ();
2042 /* recording beyond the end marker; zoom out
2043 * by 5 seconds more so that if 'follow
2044 * playhead' is active we don't immediately
2047 end = cur + _session->frame_rate() * 5;
2051 if ((start == 0 && end == 0) || end < start) {
2055 calc_extra_zoom_edges(start, end);
2057 temporal_zoom_by_frame (start, end);
2062 Editor::temporal_zoom_extents ()
2064 ENSURE_GUI_THREAD (*this, &Editor::temporal_zoom_extents)
2067 std::pair<framepos_t, framepos_t> ext = session_gui_extents( false ); //in this case we want to zoom to the extents explicitly; ignore the users prefs for extra padding
2069 framecnt_t start = ext.first;
2070 framecnt_t end = ext.second;
2072 if (_session->actively_recording () ) {
2073 framepos_t cur = playhead_cursor->current_frame ();
2075 /* recording beyond the end marker; zoom out
2076 * by 5 seconds more so that if 'follow
2077 * playhead' is active we don't immediately
2080 end = cur + _session->frame_rate() * 5;
2084 if ((start == 0 && end == 0) || end < start) {
2088 calc_extra_zoom_edges(start, end);
2090 temporal_zoom_by_frame (start, end);
2095 Editor::temporal_zoom_by_frame (framepos_t start, framepos_t end)
2097 if (!_session) return;
2099 if ((start == 0 && end == 0) || end < start) {
2103 framepos_t range = end - start;
2105 const framecnt_t new_fpp = (framecnt_t) ceil ((double) range / (double) _visible_canvas_width);
2107 framepos_t new_page = range;
2108 framepos_t middle = (framepos_t) floor ((double) start + ((double) range / 2.0f));
2109 framepos_t new_leftmost = (framepos_t) floor ((double) middle - ((double) new_page / 2.0f));
2111 if (new_leftmost > middle) {
2115 if (new_leftmost < 0) {
2119 reposition_and_zoom (new_leftmost, new_fpp);
2123 Editor::temporal_zoom_to_frame (bool coarser, framepos_t frame)
2129 framecnt_t range_before = frame - leftmost_frame;
2133 if (samples_per_pixel <= 1) {
2136 new_spp = samples_per_pixel + (samples_per_pixel/2);
2138 range_before += range_before/2;
2140 if (samples_per_pixel >= 1) {
2141 new_spp = samples_per_pixel - (samples_per_pixel/2);
2143 /* could bail out here since we cannot zoom any finer,
2144 but leave that to the equality test below
2146 new_spp = samples_per_pixel;
2149 range_before -= range_before/2;
2152 if (new_spp == samples_per_pixel) {
2156 /* zoom focus is automatically taken as @param frame when this
2160 framepos_t new_leftmost = frame - (framepos_t)range_before;
2162 if (new_leftmost > frame) {
2166 if (new_leftmost < 0) {
2170 reposition_and_zoom (new_leftmost, new_spp);
2175 Editor::choose_new_marker_name(string &name) {
2177 if (!UIConfiguration::instance().get_name_new_markers()) {
2178 /* don't prompt user for a new name */
2182 Prompter dialog (true);
2184 dialog.set_prompt (_("New Name:"));
2186 dialog.set_title (_("New Location Marker"));
2188 dialog.set_name ("MarkNameWindow");
2189 dialog.set_size_request (250, -1);
2190 dialog.set_position (Gtk::WIN_POS_MOUSE);
2192 dialog.add_button (Stock::OK, RESPONSE_ACCEPT);
2193 dialog.set_initial_text (name);
2197 switch (dialog.run ()) {
2198 case RESPONSE_ACCEPT:
2204 dialog.get_result(name);
2211 Editor::add_location_from_selection ()
2215 if (selection->time.empty()) {
2219 if (_session == 0 || clicked_axisview == 0) {
2223 framepos_t start = selection->time[clicked_selection].start;
2224 framepos_t end = selection->time[clicked_selection].end;
2226 _session->locations()->next_available_name(rangename,"selection");
2227 Location *location = new Location (*_session, start, end, rangename, Location::IsRangeMarker, get_grid_music_divisions(0));
2229 begin_reversible_command (_("add marker"));
2231 XMLNode &before = _session->locations()->get_state();
2232 _session->locations()->add (location, true);
2233 XMLNode &after = _session->locations()->get_state();
2234 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2236 commit_reversible_command ();
2240 Editor::add_location_mark (framepos_t where)
2244 select_new_marker = true;
2246 _session->locations()->next_available_name(markername,"mark");
2247 if (!choose_new_marker_name(markername)) {
2250 Location *location = new Location (*_session, where, where, markername, Location::IsMark, get_grid_music_divisions (0));
2251 begin_reversible_command (_("add marker"));
2253 XMLNode &before = _session->locations()->get_state();
2254 _session->locations()->add (location, true);
2255 XMLNode &after = _session->locations()->get_state();
2256 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2258 commit_reversible_command ();
2262 Editor::set_session_start_from_playhead ()
2268 if ((loc = _session->locations()->session_range_location()) == 0) { //should never happen
2269 _session->set_session_extents ( _session->audible_frame(), _session->audible_frame() );
2271 XMLNode &before = loc->get_state();
2273 _session->set_session_extents ( _session->audible_frame(), loc->end() );
2275 XMLNode &after = loc->get_state();
2277 begin_reversible_command (_("Set session start"));
2279 _session->add_command (new MementoCommand<Location>(*loc, &before, &after));
2281 commit_reversible_command ();
2286 Editor::set_session_end_from_playhead ()
2292 if ((loc = _session->locations()->session_range_location()) == 0) { //should never happen
2293 _session->set_session_extents ( _session->audible_frame(), _session->audible_frame() );
2295 XMLNode &before = loc->get_state();
2297 _session->set_session_extents ( loc->start(), _session->audible_frame() );
2299 XMLNode &after = loc->get_state();
2301 begin_reversible_command (_("Set session start"));
2303 _session->add_command (new MementoCommand<Location>(*loc, &before, &after));
2305 commit_reversible_command ();
2308 _session->set_end_is_free (false);
2313 Editor::toggle_location_at_playhead_cursor ()
2315 if (!do_remove_location_at_playhead_cursor())
2317 add_location_from_playhead_cursor();
2322 Editor::add_location_from_playhead_cursor ()
2324 add_location_mark (_session->audible_frame());
2328 Editor::do_remove_location_at_playhead_cursor ()
2330 bool removed = false;
2333 XMLNode &before = _session->locations()->get_state();
2335 //find location(s) at this time
2336 Locations::LocationList locs;
2337 _session->locations()->find_all_between (_session->audible_frame(), _session->audible_frame()+1, locs, Location::Flags(0));
2338 for (Locations::LocationList::iterator i = locs.begin(); i != locs.end(); ++i) {
2339 if ((*i)->is_mark()) {
2340 _session->locations()->remove (*i);
2347 begin_reversible_command (_("remove marker"));
2348 XMLNode &after = _session->locations()->get_state();
2349 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2350 commit_reversible_command ();
2357 Editor::remove_location_at_playhead_cursor ()
2359 do_remove_location_at_playhead_cursor ();
2362 /** Add a range marker around each selected region */
2364 Editor::add_locations_from_region ()
2366 RegionSelection rs = get_regions_from_selection_and_entered ();
2371 bool commit = false;
2373 XMLNode &before = _session->locations()->get_state();
2375 for (RegionSelection::iterator i = rs.begin (); i != rs.end (); ++i) {
2377 boost::shared_ptr<Region> region = (*i)->region ();
2379 Location *location = new Location (*_session, region->position(), region->last_frame(), region->name(), Location::IsRangeMarker, 0);
2381 _session->locations()->add (location, true);
2386 begin_reversible_command (selection->regions.size () > 1 ? _("add markers") : _("add marker"));
2387 XMLNode &after = _session->locations()->get_state();
2388 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2389 commit_reversible_command ();
2393 /** Add a single range marker around all selected regions */
2395 Editor::add_location_from_region ()
2397 RegionSelection rs = get_regions_from_selection_and_entered ();
2403 XMLNode &before = _session->locations()->get_state();
2407 if (rs.size() > 1) {
2408 _session->locations()->next_available_name(markername, "regions");
2410 RegionView* rv = *(rs.begin());
2411 boost::shared_ptr<Region> region = rv->region();
2412 markername = region->name();
2415 if (!choose_new_marker_name(markername)) {
2419 // single range spanning all selected
2420 Location *location = new Location (*_session, selection->regions.start(), selection->regions.end_frame(), markername, Location::IsRangeMarker, 0);
2421 _session->locations()->add (location, true);
2423 begin_reversible_command (_("add marker"));
2424 XMLNode &after = _session->locations()->get_state();
2425 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2426 commit_reversible_command ();
2432 Editor::jump_forward_to_mark ()
2438 framepos_t pos = _session->locations()->first_mark_after (playhead_cursor->current_frame());
2444 _session->request_locate (pos, _session->transport_rolling());
2448 Editor::jump_backward_to_mark ()
2454 framepos_t pos = _session->locations()->first_mark_before (playhead_cursor->current_frame());
2456 //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...
2457 if ( _session->transport_rolling() ) {
2458 if ( (playhead_cursor->current_frame() - pos) < _session->frame_rate()/2 ) {
2459 framepos_t prior = _session->locations()->first_mark_before ( pos );
2468 _session->request_locate (pos, _session->transport_rolling());
2474 framepos_t const pos = _session->audible_frame ();
2477 _session->locations()->next_available_name (markername, "mark");
2479 if (!choose_new_marker_name (markername)) {
2483 _session->locations()->add (new Location (*_session, pos, 0, markername, Location::IsMark, 0), true);
2487 Editor::clear_markers ()
2490 begin_reversible_command (_("clear markers"));
2492 XMLNode &before = _session->locations()->get_state();
2493 _session->locations()->clear_markers ();
2494 XMLNode &after = _session->locations()->get_state();
2495 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2497 commit_reversible_command ();
2502 Editor::clear_ranges ()
2505 begin_reversible_command (_("clear ranges"));
2507 XMLNode &before = _session->locations()->get_state();
2509 _session->locations()->clear_ranges ();
2511 XMLNode &after = _session->locations()->get_state();
2512 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2514 commit_reversible_command ();
2519 Editor::clear_locations ()
2521 begin_reversible_command (_("clear locations"));
2523 XMLNode &before = _session->locations()->get_state();
2524 _session->locations()->clear ();
2525 XMLNode &after = _session->locations()->get_state();
2526 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2528 commit_reversible_command ();
2532 Editor::unhide_markers ()
2534 for (LocationMarkerMap::iterator i = location_markers.begin(); i != location_markers.end(); ++i) {
2535 Location *l = (*i).first;
2536 if (l->is_hidden() && l->is_mark()) {
2537 l->set_hidden(false, this);
2543 Editor::unhide_ranges ()
2545 for (LocationMarkerMap::iterator i = location_markers.begin(); i != location_markers.end(); ++i) {
2546 Location *l = (*i).first;
2547 if (l->is_hidden() && l->is_range_marker()) {
2548 l->set_hidden(false, this);
2553 /* INSERT/REPLACE */
2556 Editor::insert_region_list_selection (float times)
2558 RouteTimeAxisView *tv = 0;
2559 boost::shared_ptr<Playlist> playlist;
2561 if (clicked_routeview != 0) {
2562 tv = clicked_routeview;
2563 } else if (!selection->tracks.empty()) {
2564 if ((tv = dynamic_cast<RouteTimeAxisView*>(selection->tracks.front())) == 0) {
2567 } else if (entered_track != 0) {
2568 if ((tv = dynamic_cast<RouteTimeAxisView*>(entered_track)) == 0) {
2575 if ((playlist = tv->playlist()) == 0) {
2579 boost::shared_ptr<Region> region = _regions->get_single_selection ();
2584 begin_reversible_command (_("insert region"));
2585 playlist->clear_changes ();
2586 playlist->add_region ((RegionFactory::create (region, true)), get_preferred_edit_position(), times);
2587 if (Config->get_edit_mode() == Ripple)
2588 playlist->ripple (get_preferred_edit_position(), region->length() * times, boost::shared_ptr<Region>());
2590 _session->add_command(new StatefulDiffCommand (playlist));
2591 commit_reversible_command ();
2594 /* BUILT-IN EFFECTS */
2597 Editor::reverse_selection ()
2602 /* GAIN ENVELOPE EDITING */
2605 Editor::edit_envelope ()
2612 Editor::transition_to_rolling (bool fwd)
2618 if (_session->config.get_external_sync()) {
2619 switch (Config->get_sync_source()) {
2623 /* transport controlled by the master */
2628 if (_session->is_auditioning()) {
2629 _session->cancel_audition ();
2633 _session->request_transport_speed (fwd ? 1.0f : -1.0f);
2637 Editor::play_from_start ()
2639 _session->request_locate (_session->current_start_frame(), true);
2643 Editor::play_from_edit_point ()
2645 _session->request_locate (get_preferred_edit_position(), true);
2649 Editor::play_from_edit_point_and_return ()
2651 framepos_t start_frame;
2652 framepos_t return_frame;
2654 start_frame = get_preferred_edit_position ( EDIT_IGNORE_PHEAD );
2656 if (_session->transport_rolling()) {
2657 _session->request_locate (start_frame, false);
2661 /* don't reset the return frame if its already set */
2663 if ((return_frame = _session->requested_return_frame()) < 0) {
2664 return_frame = _session->audible_frame();
2667 if (start_frame >= 0) {
2668 _session->request_roll_at_and_return (start_frame, return_frame);
2673 Editor::play_selection ()
2675 framepos_t start, end;
2676 if (!get_selection_extents ( start, end))
2679 AudioRange ar (start, end, 0);
2680 list<AudioRange> lar;
2683 _session->request_play_range (&lar, true);
2688 Editor::maybe_locate_with_edit_preroll (framepos_t location)
2690 if ( _session->transport_rolling() || !UIConfiguration::instance().get_follow_edits() || _session->config.get_external_sync() )
2693 location -= _session->preroll_samples (location);
2695 //don't try to locate before the beginning of time
2700 //if follow_playhead is on, keep the playhead on the screen
2701 if ( _follow_playhead )
2702 if ( location < leftmost_frame )
2703 location = leftmost_frame;
2705 _session->request_locate( location );
2709 Editor::play_with_preroll ()
2711 framepos_t start, end;
2712 if ( UIConfiguration::instance().get_follow_edits() && get_selection_extents ( start, end) ) {
2713 const framepos_t preroll = _session->preroll_samples (start);
2715 framepos_t ret = start;
2717 if (start > preroll) {
2718 start = start - preroll;
2721 end = end + preroll; //"post-roll"
2723 AudioRange ar (start, end, 0);
2724 list<AudioRange> lar;
2727 _session->request_play_range (&lar, true);
2728 _session->set_requested_return_frame (ret); //force auto-return to return to range start, without the preroll
2730 framepos_t ph = playhead_cursor->current_frame ();
2731 const framepos_t preroll = _session->preroll_samples (ph);
2734 start = ph - preroll;
2738 _session->request_locate (start, true);
2739 _session->set_requested_return_frame (ph); //force auto-return to return to playhead location, without the preroll
2744 Editor::rec_with_preroll ()
2746 framepos_t ph = playhead_cursor->current_frame ();
2747 framepos_t preroll = _session->preroll_samples (ph);
2748 _session->request_preroll_record_trim (ph, preroll);
2752 Editor::rec_with_count_in ()
2754 _session->request_count_in_record ();
2758 Editor::play_location (Location& location)
2760 if (location.start() <= location.end()) {
2764 _session->request_bounded_roll (location.start(), location.end());
2768 Editor::loop_location (Location& location)
2770 if (location.start() <= location.end()) {
2776 if ((tll = transport_loop_location()) != 0) {
2777 tll->set (location.start(), location.end());
2779 // enable looping, reposition and start rolling
2780 _session->request_locate (tll->start(), true);
2781 _session->request_play_loop (true);
2786 Editor::do_layer_operation (LayerOperation op)
2788 if (selection->regions.empty ()) {
2792 bool const multiple = selection->regions.size() > 1;
2796 begin_reversible_command (_("raise regions"));
2798 begin_reversible_command (_("raise region"));
2804 begin_reversible_command (_("raise regions to top"));
2806 begin_reversible_command (_("raise region to top"));
2812 begin_reversible_command (_("lower regions"));
2814 begin_reversible_command (_("lower region"));
2820 begin_reversible_command (_("lower regions to bottom"));
2822 begin_reversible_command (_("lower region"));
2827 set<boost::shared_ptr<Playlist> > playlists = selection->regions.playlists ();
2828 for (set<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
2829 (*i)->clear_owned_changes ();
2832 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
2833 boost::shared_ptr<Region> r = (*i)->region ();
2845 r->lower_to_bottom ();
2849 for (set<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
2850 vector<Command*> cmds;
2852 _session->add_commands (cmds);
2855 commit_reversible_command ();
2859 Editor::raise_region ()
2861 do_layer_operation (Raise);
2865 Editor::raise_region_to_top ()
2867 do_layer_operation (RaiseToTop);
2871 Editor::lower_region ()
2873 do_layer_operation (Lower);
2877 Editor::lower_region_to_bottom ()
2879 do_layer_operation (LowerToBottom);
2882 /** Show the region editor for the selected regions */
2884 Editor::show_region_properties ()
2886 selection->foreach_regionview (&RegionView::show_region_editor);
2889 /** Show the midi list editor for the selected MIDI regions */
2891 Editor::show_midi_list_editor ()
2893 selection->foreach_midi_regionview (&MidiRegionView::show_list_editor);
2897 Editor::rename_region ()
2899 RegionSelection rs = get_regions_from_selection_and_entered ();
2905 ArdourDialog d (_("Rename Region"), true, false);
2907 Label label (_("New name:"));
2910 hbox.set_spacing (6);
2911 hbox.pack_start (label, false, false);
2912 hbox.pack_start (entry, true, true);
2914 d.get_vbox()->set_border_width (12);
2915 d.get_vbox()->pack_start (hbox, false, false);
2917 d.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
2918 d.add_button(Gtk::Stock::OK, Gtk::RESPONSE_OK);
2920 d.set_size_request (300, -1);
2922 entry.set_text (rs.front()->region()->name());
2923 entry.select_region (0, -1);
2925 entry.signal_activate().connect (sigc::bind (sigc::mem_fun (d, &Dialog::response), RESPONSE_OK));
2931 int const ret = d.run();
2935 if (ret != RESPONSE_OK) {
2939 std::string str = entry.get_text();
2940 strip_whitespace_edges (str);
2942 rs.front()->region()->set_name (str);
2943 _regions->redisplay ();
2947 /** Start an audition of the first selected region */
2949 Editor::play_edit_range ()
2951 framepos_t start, end;
2953 if (get_edit_op_range (start, end)) {
2954 _session->request_bounded_roll (start, end);
2959 Editor::play_selected_region ()
2961 framepos_t start = max_framepos;
2964 RegionSelection rs = get_regions_from_selection_and_entered ();
2970 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
2971 if ((*i)->region()->position() < start) {
2972 start = (*i)->region()->position();
2974 if ((*i)->region()->last_frame() + 1 > end) {
2975 end = (*i)->region()->last_frame() + 1;
2979 _session->request_bounded_roll (start, end);
2983 Editor::audition_playlist_region_standalone (boost::shared_ptr<Region> region)
2985 _session->audition_region (region);
2989 Editor::region_from_selection ()
2991 if (clicked_axisview == 0) {
2995 if (selection->time.empty()) {
2999 framepos_t start = selection->time[clicked_selection].start;
3000 framepos_t end = selection->time[clicked_selection].end;
3002 TrackViewList tracks = get_tracks_for_range_action ();
3004 framepos_t selection_cnt = end - start + 1;
3006 for (TrackSelection::iterator i = tracks.begin(); i != tracks.end(); ++i) {
3007 boost::shared_ptr<Region> current;
3008 boost::shared_ptr<Playlist> pl;
3009 framepos_t internal_start;
3012 if ((pl = (*i)->playlist()) == 0) {
3016 if ((current = pl->top_region_at (start)) == 0) {
3020 internal_start = start - current->position();
3021 RegionFactory::region_name (new_name, current->name(), true);
3025 plist.add (ARDOUR::Properties::start, current->start() + internal_start);
3026 plist.add (ARDOUR::Properties::length, selection_cnt);
3027 plist.add (ARDOUR::Properties::name, new_name);
3028 plist.add (ARDOUR::Properties::layer, 0);
3030 boost::shared_ptr<Region> region (RegionFactory::create (current, plist));
3035 Editor::create_region_from_selection (vector<boost::shared_ptr<Region> >& new_regions)
3037 if (selection->time.empty() || selection->tracks.empty()) {
3041 framepos_t start, end;
3042 if (clicked_selection) {
3043 start = selection->time[clicked_selection].start;
3044 end = selection->time[clicked_selection].end;
3046 start = selection->time.start();
3047 end = selection->time.end_frame();
3050 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
3051 sort_track_selection (ts);
3053 for (TrackSelection::iterator i = ts.begin(); i != ts.end(); ++i) {
3054 boost::shared_ptr<Region> current;
3055 boost::shared_ptr<Playlist> playlist;
3056 framepos_t internal_start;
3059 if ((playlist = (*i)->playlist()) == 0) {
3063 if ((current = playlist->top_region_at(start)) == 0) {
3067 internal_start = start - current->position();
3068 RegionFactory::region_name (new_name, current->name(), true);
3072 plist.add (ARDOUR::Properties::start, current->start() + internal_start);
3073 plist.add (ARDOUR::Properties::length, end - start + 1);
3074 plist.add (ARDOUR::Properties::name, new_name);
3076 new_regions.push_back (RegionFactory::create (current, plist));
3081 Editor::split_multichannel_region ()
3083 RegionSelection rs = get_regions_from_selection_and_entered ();
3089 vector< boost::shared_ptr<Region> > v;
3091 for (list<RegionView*>::iterator x = rs.begin(); x != rs.end(); ++x) {
3092 (*x)->region()->separate_by_channel (v);
3097 Editor::new_region_from_selection ()
3099 region_from_selection ();
3100 cancel_selection ();
3104 add_if_covered (RegionView* rv, const AudioRange* ar, RegionSelection* rs)
3106 switch (rv->region()->coverage (ar->start, ar->end - 1)) {
3107 // n.b. -1 because AudioRange::end is one past the end, but coverage expects inclusive ranges
3108 case Evoral::OverlapNone:
3116 * - selected tracks, or if there are none...
3117 * - tracks containing selected regions, or if there are none...
3122 Editor::get_tracks_for_range_action () const
3126 if (selection->tracks.empty()) {
3128 /* use tracks with selected regions */
3130 RegionSelection rs = selection->regions;
3132 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3133 TimeAxisView* tv = &(*i)->get_time_axis_view();
3135 if (!t.contains (tv)) {
3141 /* no regions and no tracks: use all tracks */
3147 t = selection->tracks;
3150 return t.filter_to_unique_playlists();
3154 Editor::separate_regions_between (const TimeSelection& ts)
3156 bool in_command = false;
3157 boost::shared_ptr<Playlist> playlist;
3158 RegionSelection new_selection;
3160 TrackViewList tmptracks = get_tracks_for_range_action ();
3161 sort_track_selection (tmptracks);
3163 for (TrackSelection::iterator i = tmptracks.begin(); i != tmptracks.end(); ++i) {
3165 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> ((*i));
3171 if (!rtv->is_track()) {
3175 /* no edits to destructive tracks */
3177 if (rtv->track()->destructive()) {
3181 if ((playlist = rtv->playlist()) != 0) {
3183 playlist->clear_changes ();
3185 /* XXX need to consider musical time selections here at some point */
3187 double speed = rtv->track()->speed();
3189 for (list<AudioRange>::const_iterator t = ts.begin(); t != ts.end(); ++t) {
3191 sigc::connection c = rtv->view()->RegionViewAdded.connect (
3192 sigc::mem_fun(*this, &Editor::collect_new_region_view));
3194 latest_regionviews.clear ();
3196 playlist->partition ((framepos_t)((*t).start * speed),
3197 (framepos_t)((*t).end * speed), false);
3201 if (!latest_regionviews.empty()) {
3203 rtv->view()->foreach_regionview (sigc::bind (
3204 sigc::ptr_fun (add_if_covered),
3205 &(*t), &new_selection));
3208 begin_reversible_command (_("separate"));
3212 /* pick up changes to existing regions */
3214 vector<Command*> cmds;
3215 playlist->rdiff (cmds);
3216 _session->add_commands (cmds);
3218 /* pick up changes to the playlist itself (adds/removes)
3221 _session->add_command(new StatefulDiffCommand (playlist));
3228 // selection->set (new_selection);
3230 commit_reversible_command ();
3234 struct PlaylistState {
3235 boost::shared_ptr<Playlist> playlist;
3239 /** Take tracks from get_tracks_for_range_action and cut any regions
3240 * on those tracks so that the tracks are empty over the time
3244 Editor::separate_region_from_selection ()
3246 /* preferentially use *all* ranges in the time selection if we're in range mode
3247 to allow discontiguous operation, since get_edit_op_range() currently
3248 returns a single range.
3251 if (!selection->time.empty()) {
3253 separate_regions_between (selection->time);
3260 if (get_edit_op_range (start, end)) {
3262 AudioRange ar (start, end, 1);
3266 separate_regions_between (ts);
3272 Editor::separate_region_from_punch ()
3274 Location* loc = _session->locations()->auto_punch_location();
3276 separate_regions_using_location (*loc);
3281 Editor::separate_region_from_loop ()
3283 Location* loc = _session->locations()->auto_loop_location();
3285 separate_regions_using_location (*loc);
3290 Editor::separate_regions_using_location (Location& loc)
3292 if (loc.is_mark()) {
3296 AudioRange ar (loc.start(), loc.end(), 1);
3301 separate_regions_between (ts);
3304 /** Separate regions under the selected region */
3306 Editor::separate_under_selected_regions ()
3308 vector<PlaylistState> playlists;
3312 rs = get_regions_from_selection_and_entered();
3314 if (!_session || rs.empty()) {
3318 begin_reversible_command (_("separate region under"));
3320 list<boost::shared_ptr<Region> > regions_to_remove;
3322 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3323 // we can't just remove the region(s) in this loop because
3324 // this removes them from the RegionSelection, and they thus
3325 // disappear from underneath the iterator, and the ++i above
3326 // SEGVs in a puzzling fashion.
3328 // so, first iterate over the regions to be removed from rs and
3329 // add them to the regions_to_remove list, and then
3330 // iterate over the list to actually remove them.
3332 regions_to_remove.push_back ((*i)->region());
3335 for (list<boost::shared_ptr<Region> >::iterator rl = regions_to_remove.begin(); rl != regions_to_remove.end(); ++rl) {
3337 boost::shared_ptr<Playlist> playlist = (*rl)->playlist();
3340 // is this check necessary?
3344 vector<PlaylistState>::iterator i;
3346 //only take state if this is a new playlist.
3347 for (i = playlists.begin(); i != playlists.end(); ++i) {
3348 if ((*i).playlist == playlist) {
3353 if (i == playlists.end()) {
3355 PlaylistState before;
3356 before.playlist = playlist;
3357 before.before = &playlist->get_state();
3358 playlist->clear_changes ();
3359 playlist->freeze ();
3360 playlists.push_back(before);
3363 //Partition on the region bounds
3364 playlist->partition ((*rl)->first_frame() - 1, (*rl)->last_frame() + 1, true);
3366 //Re-add region that was just removed due to the partition operation
3367 playlist->add_region( (*rl), (*rl)->first_frame() );
3370 vector<PlaylistState>::iterator pl;
3372 for (pl = playlists.begin(); pl != playlists.end(); ++pl) {
3373 (*pl).playlist->thaw ();
3374 _session->add_command(new MementoCommand<Playlist>(*(*pl).playlist, (*pl).before, &(*pl).playlist->get_state()));
3377 commit_reversible_command ();
3381 Editor::crop_region_to_selection ()
3383 if (!selection->time.empty()) {
3385 begin_reversible_command (_("Crop Regions to Time Selection"));
3386 for (std::list<AudioRange>::iterator i = selection->time.begin(); i != selection->time.end(); ++i) {
3387 crop_region_to ((*i).start, (*i).end);
3389 commit_reversible_command();
3395 if (get_edit_op_range (start, end)) {
3396 begin_reversible_command (_("Crop Regions to Edit Range"));
3398 crop_region_to (start, end);
3400 commit_reversible_command();
3407 Editor::crop_region_to (framepos_t start, framepos_t end)
3409 vector<boost::shared_ptr<Playlist> > playlists;
3410 boost::shared_ptr<Playlist> playlist;
3413 if (selection->tracks.empty()) {
3414 ts = track_views.filter_to_unique_playlists();
3416 ts = selection->tracks.filter_to_unique_playlists ();
3419 sort_track_selection (ts);
3421 for (TrackSelection::iterator i = ts.begin(); i != ts.end(); ++i) {
3423 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> ((*i));
3429 boost::shared_ptr<Track> t = rtv->track();
3431 if (t != 0 && ! t->destructive()) {
3433 if ((playlist = rtv->playlist()) != 0) {
3434 playlists.push_back (playlist);
3439 if (playlists.empty()) {
3444 framepos_t new_start;
3446 framecnt_t new_length;
3448 for (vector<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
3450 /* Only the top regions at start and end have to be cropped */
3451 boost::shared_ptr<Region> region_at_start = (*i)->top_region_at(start);
3452 boost::shared_ptr<Region> region_at_end = (*i)->top_region_at(end);
3454 vector<boost::shared_ptr<Region> > regions;
3456 if (region_at_start != 0) {
3457 regions.push_back (region_at_start);
3459 if (region_at_end != 0) {
3460 regions.push_back (region_at_end);
3463 /* now adjust lengths */
3464 for (vector<boost::shared_ptr<Region> >::iterator i = regions.begin(); i != regions.end(); ++i) {
3466 pos = (*i)->position();
3467 new_start = max (start, pos);
3468 if (max_framepos - pos > (*i)->length()) {
3469 new_end = pos + (*i)->length() - 1;
3471 new_end = max_framepos;
3473 new_end = min (end, new_end);
3474 new_length = new_end - new_start + 1;
3476 (*i)->clear_changes ();
3477 (*i)->trim_to (new_start, new_length);
3478 _session->add_command (new StatefulDiffCommand (*i));
3484 Editor::region_fill_track ()
3486 boost::shared_ptr<Playlist> playlist;
3487 RegionSelection regions = get_regions_from_selection_and_entered ();
3488 RegionSelection foo;
3490 framepos_t const end = _session->current_end_frame ();
3492 if (regions.empty () || regions.end_frame () + 1 >= end) {
3496 framepos_t const start_frame = regions.start ();
3497 framepos_t const end_frame = regions.end_frame ();
3498 framecnt_t const gap = end_frame - start_frame + 1;
3500 begin_reversible_command (Operations::region_fill);
3502 selection->clear_regions ();
3504 for (RegionSelection::iterator i = regions.begin(); i != regions.end(); ++i) {
3506 boost::shared_ptr<Region> r ((*i)->region());
3508 TimeAxisView& tv = (*i)->get_time_axis_view();
3509 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (&tv);
3510 latest_regionviews.clear ();
3511 sigc::connection c = rtv->view()->RegionViewAdded.connect (sigc::mem_fun(*this, &Editor::collect_new_region_view));
3513 framepos_t const position = end_frame + (r->first_frame() - start_frame + 1);
3514 playlist = (*i)->region()->playlist();
3515 playlist->clear_changes ();
3516 playlist->duplicate_until (r, position, gap, end);
3517 _session->add_command(new StatefulDiffCommand (playlist));
3521 foo.insert (foo.end(), latest_regionviews.begin(), latest_regionviews.end());
3525 selection->set (foo);
3528 commit_reversible_command ();
3532 Editor::set_region_sync_position ()
3534 set_sync_point (get_preferred_edit_position (), get_regions_from_selection_and_edit_point ());
3538 Editor::set_sync_point (framepos_t where, const RegionSelection& rs)
3540 bool in_command = false;
3542 for (RegionSelection::const_iterator r = rs.begin(); r != rs.end(); ++r) {
3544 if (!(*r)->region()->covers (where)) {
3548 boost::shared_ptr<Region> region ((*r)->region());
3551 begin_reversible_command (_("set sync point"));
3555 region->clear_changes ();
3556 region->set_sync_position (where);
3557 _session->add_command(new StatefulDiffCommand (region));
3561 commit_reversible_command ();
3565 /** Remove the sync positions of the selection */
3567 Editor::remove_region_sync ()
3569 RegionSelection rs = get_regions_from_selection_and_entered ();
3575 begin_reversible_command (_("remove region sync"));
3577 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3579 (*i)->region()->clear_changes ();
3580 (*i)->region()->clear_sync_position ();
3581 _session->add_command(new StatefulDiffCommand ((*i)->region()));
3584 commit_reversible_command ();
3588 Editor::naturalize_region ()
3590 RegionSelection rs = get_regions_from_selection_and_entered ();
3596 if (rs.size() > 1) {
3597 begin_reversible_command (_("move regions to original position"));
3599 begin_reversible_command (_("move region to original position"));
3602 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3603 (*i)->region()->clear_changes ();
3604 (*i)->region()->move_to_natural_position ();
3605 _session->add_command (new StatefulDiffCommand ((*i)->region()));
3608 commit_reversible_command ();
3612 Editor::align_regions (RegionPoint what)
3614 RegionSelection const rs = get_regions_from_selection_and_edit_point ();
3620 begin_reversible_command (_("align selection"));
3622 framepos_t const position = get_preferred_edit_position ();
3624 for (RegionSelection::const_iterator i = rs.begin(); i != rs.end(); ++i) {
3625 align_region_internal ((*i)->region(), what, position);
3628 commit_reversible_command ();
3631 struct RegionSortByTime {
3632 bool operator() (const RegionView* a, const RegionView* b) {
3633 return a->region()->position() < b->region()->position();
3638 Editor::align_regions_relative (RegionPoint point)
3640 RegionSelection const rs = get_regions_from_selection_and_edit_point ();
3646 framepos_t const position = get_preferred_edit_position ();
3648 framepos_t distance = 0;
3652 list<RegionView*> sorted;
3653 rs.by_position (sorted);
3655 boost::shared_ptr<Region> r ((*sorted.begin())->region());
3660 if (position > r->position()) {
3661 distance = position - r->position();
3663 distance = r->position() - position;
3669 if (position > r->last_frame()) {
3670 distance = position - r->last_frame();
3671 pos = r->position() + distance;
3673 distance = r->last_frame() - position;
3674 pos = r->position() - distance;
3680 pos = r->adjust_to_sync (position);
3681 if (pos > r->position()) {
3682 distance = pos - r->position();
3684 distance = r->position() - pos;
3690 if (pos == r->position()) {
3694 begin_reversible_command (_("align selection (relative)"));
3696 /* move first one specially */
3698 r->clear_changes ();
3699 r->set_position (pos);
3700 _session->add_command(new StatefulDiffCommand (r));
3702 /* move rest by the same amount */
3706 for (list<RegionView*>::iterator i = sorted.begin(); i != sorted.end(); ++i) {
3708 boost::shared_ptr<Region> region ((*i)->region());
3710 region->clear_changes ();
3713 region->set_position (region->position() + distance);
3715 region->set_position (region->position() - distance);
3718 _session->add_command(new StatefulDiffCommand (region));
3722 commit_reversible_command ();
3726 Editor::align_region (boost::shared_ptr<Region> region, RegionPoint point, framepos_t position)
3728 begin_reversible_command (_("align region"));
3729 align_region_internal (region, point, position);
3730 commit_reversible_command ();
3734 Editor::align_region_internal (boost::shared_ptr<Region> region, RegionPoint point, framepos_t position)
3736 region->clear_changes ();
3740 region->set_position (region->adjust_to_sync (position));
3744 if (position > region->length()) {
3745 region->set_position (position - region->length());
3750 region->set_position (position);
3754 _session->add_command(new StatefulDiffCommand (region));
3758 Editor::trim_region_front ()
3764 Editor::trim_region_back ()
3766 trim_region (false);
3770 Editor::trim_region (bool front)
3772 framepos_t where = get_preferred_edit_position();
3773 RegionSelection rs = get_regions_from_selection_and_edit_point ();
3779 begin_reversible_command (front ? _("trim front") : _("trim back"));
3781 for (list<RegionView*>::const_iterator i = rs.by_layer().begin(); i != rs.by_layer().end(); ++i) {
3782 if (!(*i)->region()->locked()) {
3784 (*i)->region()->clear_changes ();
3787 (*i)->region()->trim_front (where);
3789 (*i)->region()->trim_end (where);
3792 _session->add_command (new StatefulDiffCommand ((*i)->region()));
3796 commit_reversible_command ();
3799 /** Trim the end of the selected regions to the position of the edit cursor */
3801 Editor::trim_region_to_loop ()
3803 Location* loc = _session->locations()->auto_loop_location();
3807 trim_region_to_location (*loc, _("trim to loop"));
3811 Editor::trim_region_to_punch ()
3813 Location* loc = _session->locations()->auto_punch_location();
3817 trim_region_to_location (*loc, _("trim to punch"));
3821 Editor::trim_region_to_location (const Location& loc, const char* str)
3823 RegionSelection rs = get_regions_from_selection_and_entered ();
3824 bool in_command = false;
3826 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
3827 RegionView* rv = (*x);
3829 /* require region to span proposed trim */
3830 switch (rv->region()->coverage (loc.start(), loc.end())) {
3831 case Evoral::OverlapInternal:
3837 RouteTimeAxisView* tav = dynamic_cast<RouteTimeAxisView*> (&rv->get_time_axis_view());
3846 if (tav->track() != 0) {
3847 speed = tav->track()->speed();
3850 start = session_frame_to_track_frame (loc.start(), speed);
3851 end = session_frame_to_track_frame (loc.end(), speed);
3853 rv->region()->clear_changes ();
3854 rv->region()->trim_to (start, (end - start));
3857 begin_reversible_command (str);
3860 _session->add_command(new StatefulDiffCommand (rv->region()));
3864 commit_reversible_command ();
3869 Editor::trim_region_to_previous_region_end ()
3871 return trim_to_region(false);
3875 Editor::trim_region_to_next_region_start ()
3877 return trim_to_region(true);
3881 Editor::trim_to_region(bool forward)
3883 RegionSelection rs = get_regions_from_selection_and_entered ();
3884 bool in_command = false;
3886 boost::shared_ptr<Region> next_region;
3888 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
3890 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*x);
3896 AudioTimeAxisView* atav = dynamic_cast<AudioTimeAxisView*> (&arv->get_time_axis_view());
3904 if (atav->track() != 0) {
3905 speed = atav->track()->speed();
3909 boost::shared_ptr<Region> region = arv->region();
3910 boost::shared_ptr<Playlist> playlist (region->playlist());
3912 region->clear_changes ();
3916 next_region = playlist->find_next_region (region->first_frame(), Start, 1);
3922 region->trim_end((framepos_t) ( (next_region->first_frame() - 1) * speed));
3923 arv->region_changed (PropertyChange (ARDOUR::Properties::length));
3927 next_region = playlist->find_next_region (region->first_frame(), Start, 0);
3933 region->trim_front((framepos_t) ((next_region->last_frame() + 1) * speed));
3935 arv->region_changed (ARDOUR::bounds_change);
3939 begin_reversible_command (_("trim to region"));
3942 _session->add_command(new StatefulDiffCommand (region));
3946 commit_reversible_command ();
3951 Editor::unfreeze_route ()
3953 if (clicked_routeview == 0 || !clicked_routeview->is_track()) {
3957 clicked_routeview->track()->unfreeze ();
3961 Editor::_freeze_thread (void* arg)
3963 return static_cast<Editor*>(arg)->freeze_thread ();
3967 Editor::freeze_thread ()
3969 /* create event pool because we may need to talk to the session */
3970 SessionEvent::create_per_thread_pool ("freeze events", 64);
3971 /* create per-thread buffers for process() tree to use */
3972 clicked_routeview->audio_track()->freeze_me (*current_interthread_info);
3973 current_interthread_info->done = true;
3978 Editor::freeze_route ()
3984 /* stop transport before we start. this is important */
3986 _session->request_transport_speed (0.0);
3988 /* wait for just a little while, because the above call is asynchronous */
3990 Glib::usleep (250000);
3992 if (clicked_routeview == 0 || !clicked_routeview->is_audio_track()) {
3996 if (!clicked_routeview->track()->bounceable (clicked_routeview->track()->main_outs(), true)) {
3998 _("This track/bus cannot be frozen because the signal adds or loses channels before reaching the outputs.\n"
3999 "This is typically caused by plugins that generate stereo output from mono input or vice versa.")
4001 d.set_title (_("Cannot freeze"));
4006 if (clicked_routeview->track()->has_external_redirects()) {
4007 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"
4008 "Freezing will only process the signal as far as the first send/insert/return."),
4009 clicked_routeview->track()->name()), true, MESSAGE_INFO, BUTTONS_NONE, true);
4011 d.add_button (_("Freeze anyway"), Gtk::RESPONSE_OK);
4012 d.add_button (_("Don't freeze"), Gtk::RESPONSE_CANCEL);
4013 d.set_title (_("Freeze Limits"));
4015 int response = d.run ();
4018 case Gtk::RESPONSE_CANCEL:
4025 InterThreadInfo itt;
4026 current_interthread_info = &itt;
4028 InterthreadProgressWindow ipw (current_interthread_info, _("Freeze"), _("Cancel Freeze"));
4030 pthread_create_and_store (X_("freezer"), &itt.thread, _freeze_thread, this);
4032 CursorContext::Handle cursor_ctx = CursorContext::create(*this, _cursors->wait);
4034 while (!itt.done && !itt.cancel) {
4035 gtk_main_iteration ();
4038 pthread_join (itt.thread, 0);
4039 current_interthread_info = 0;
4043 Editor::bounce_range_selection (bool replace, bool enable_processing)
4045 if (selection->time.empty()) {
4049 TrackSelection views = selection->tracks;
4051 for (TrackViewList::iterator i = views.begin(); i != views.end(); ++i) {
4053 if (enable_processing) {
4055 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*i);
4057 if (rtv && rtv->track() && replace && enable_processing && !rtv->track()->bounceable (rtv->track()->main_outs(), false)) {
4059 _("You can't perform this operation because the processing of the signal "
4060 "will cause one or more of the tracks to end up with a region with more channels than this track has inputs.\n\n"
4061 "You can do this without processing, which is a different operation.")
4063 d.set_title (_("Cannot bounce"));
4070 framepos_t start = selection->time[clicked_selection].start;
4071 framepos_t end = selection->time[clicked_selection].end;
4072 framepos_t cnt = end - start + 1;
4073 bool in_command = false;
4075 for (TrackViewList::iterator i = views.begin(); i != views.end(); ++i) {
4077 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*i);
4083 boost::shared_ptr<Playlist> playlist;
4085 if ((playlist = rtv->playlist()) == 0) {
4089 InterThreadInfo itt;
4091 playlist->clear_changes ();
4092 playlist->clear_owned_changes ();
4094 boost::shared_ptr<Region> r;
4096 if (enable_processing) {
4097 r = rtv->track()->bounce_range (start, start+cnt, itt, rtv->track()->main_outs(), false);
4099 r = rtv->track()->bounce_range (start, start+cnt, itt, boost::shared_ptr<Processor>(), false);
4107 list<AudioRange> ranges;
4108 ranges.push_back (AudioRange (start, start+cnt, 0));
4109 playlist->cut (ranges); // discard result
4110 playlist->add_region (r, start);
4114 begin_reversible_command (_("bounce range"));
4117 vector<Command*> cmds;
4118 playlist->rdiff (cmds);
4119 _session->add_commands (cmds);
4121 _session->add_command (new StatefulDiffCommand (playlist));
4125 commit_reversible_command ();
4129 /** Delete selected regions, automation points or a time range */
4133 //special case: if the user is pointing in the editor/mixer strip, they may be trying to delete a plugin.
4134 //we need this because the editor-mixer strip is in the editor window, so it doesn't get the bindings from the mix window
4135 bool deleted = false;
4136 if ( current_mixer_strip && current_mixer_strip == MixerStrip::entered_mixer_strip() )
4137 deleted = current_mixer_strip->delete_processors ();
4143 /** Cut selected regions, automation points or a time range */
4150 /** Copy selected regions, automation points or a time range */
4158 /** @return true if a Cut, Copy or Clear is possible */
4160 Editor::can_cut_copy () const
4162 if (!selection->time.empty() || !selection->regions.empty() || !selection->points.empty())
4169 /** Cut, copy or clear selected regions, automation points or a time range.
4170 * @param op Operation (Delete, Cut, Copy or Clear)
4173 Editor::cut_copy (CutCopyOp op)
4175 /* only cancel selection if cut/copy is successful.*/
4181 opname = _("delete");
4190 opname = _("clear");
4194 /* if we're deleting something, and the mouse is still pressed,
4195 the thing we started a drag for will be gone when we release
4196 the mouse button(s). avoid this. see part 2 at the end of
4200 if (op == Delete || op == Cut || op == Clear) {
4201 if (_drags->active ()) {
4206 if ( op != Delete ) { //"Delete" doesn't change copy/paste buf
4207 cut_buffer->clear ();
4210 if (entered_marker) {
4212 /* cut/delete op while pointing at a marker */
4215 Location* loc = find_location_from_marker (entered_marker, ignored);
4217 if (_session && loc) {
4218 entered_marker = NULL;
4219 Glib::signal_idle().connect (sigc::bind (sigc::mem_fun(*this, &Editor::really_remove_marker), loc));
4226 switch (mouse_mode) {
4229 begin_reversible_command (opname + ' ' + X_("MIDI"));
4231 commit_reversible_command ();
4237 bool did_edit = false;
4239 if (!selection->regions.empty() || !selection->points.empty()) {
4240 begin_reversible_command (opname + ' ' + _("objects"));
4243 if (!selection->regions.empty()) {
4244 cut_copy_regions (op, selection->regions);
4246 if (op == Cut || op == Delete) {
4247 selection->clear_regions ();
4251 if (!selection->points.empty()) {
4252 cut_copy_points (op);
4254 if (op == Cut || op == Delete) {
4255 selection->clear_points ();
4258 } else if (selection->time.empty()) {
4259 framepos_t start, end;
4260 /* no time selection, see if we can get an edit range
4263 if (get_edit_op_range (start, end)) {
4264 selection->set (start, end);
4266 } else if (!selection->time.empty()) {
4267 begin_reversible_command (opname + ' ' + _("range"));
4270 cut_copy_ranges (op);
4272 if (op == Cut || op == Delete) {
4273 selection->clear_time ();
4278 /* reset repeated paste state */
4280 last_paste_pos = -1;
4281 commit_reversible_command ();
4284 if (op == Delete || op == Cut || op == Clear) {
4290 struct AutomationRecord {
4291 AutomationRecord () : state (0) , line(NULL) {}
4292 AutomationRecord (XMLNode* s, const AutomationLine* l) : state (s) , line (l) {}
4294 XMLNode* state; ///< state before any operation
4295 const AutomationLine* line; ///< line this came from
4296 boost::shared_ptr<Evoral::ControlList> copy; ///< copied events for the cut buffer
4299 struct PointsSelectionPositionSorter {
4300 bool operator() (ControlPoint* a, ControlPoint* b) {
4301 return (*(a->model()))->when < (*(b->model()))->when;
4305 /** Cut, copy or clear selected automation points.
4306 * @param op Operation (Cut, Copy or Clear)
4309 Editor::cut_copy_points (Editing::CutCopyOp op, Evoral::Beats earliest, bool midi)
4311 if (selection->points.empty ()) {
4315 /* XXX: not ideal, as there may be more than one track involved in the point selection */
4316 _last_cut_copy_source_track = &selection->points.front()->line().trackview;
4318 /* Keep a record of the AutomationLists that we end up using in this operation */
4319 typedef std::map<boost::shared_ptr<AutomationList>, AutomationRecord> Lists;
4322 /* user could select points in any order */
4323 selection->points.sort(PointsSelectionPositionSorter ());
4325 /* Go through all selected points, making an AutomationRecord for each distinct AutomationList */
4326 for (PointSelection::iterator sel_point = selection->points.begin(); sel_point != selection->points.end(); ++sel_point) {
4327 const AutomationLine& line = (*sel_point)->line();
4328 const boost::shared_ptr<AutomationList> al = line.the_list();
4329 if (lists.find (al) == lists.end ()) {
4330 /* We haven't seen this list yet, so make a record for it. This includes
4331 taking a copy of its current state, in case this is needed for undo later.
4333 lists[al] = AutomationRecord (&al->get_state (), &line);
4337 if (op == Cut || op == Copy) {
4338 /* This operation will involve putting things in the cut buffer, so create an empty
4339 ControlList for each of our source lists to put the cut buffer data in.
4341 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
4342 i->second.copy = i->first->create (i->first->parameter (), i->first->descriptor());
4345 /* Add all selected points to the relevant copy ControlLists */
4346 MusicFrame start (std::numeric_limits<framepos_t>::max(), 0);
4347 for (PointSelection::iterator sel_point = selection->points.begin(); sel_point != selection->points.end(); ++sel_point) {
4348 boost::shared_ptr<AutomationList> al = (*sel_point)->line().the_list();
4349 AutomationList::const_iterator ctrl_evt = (*sel_point)->model ();
4351 lists[al].copy->fast_simple_add ((*ctrl_evt)->when, (*ctrl_evt)->value);
4353 /* Update earliest MIDI start time in beats */
4354 earliest = std::min(earliest, Evoral::Beats((*ctrl_evt)->when));
4356 /* Update earliest session start time in frames */
4357 start.frame = std::min(start.frame, (*sel_point)->line().session_position(ctrl_evt));
4361 /* Snap start time backwards, so copy/paste is snap aligned. */
4363 if (earliest == Evoral::Beats::max()) {
4364 earliest = Evoral::Beats(); // Weird... don't offset
4366 earliest.round_down_to_beat();
4368 if (start.frame == std::numeric_limits<double>::max()) {
4369 start.frame = 0; // Weird... don't offset
4371 snap_to(start, RoundDownMaybe);
4374 const double line_offset = midi ? earliest.to_double() : start.frame;
4375 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
4376 /* Correct this copy list so that it is relative to the earliest
4377 start time, so relative ordering between points is preserved
4378 when copying from several lists and the paste starts at the
4379 earliest copied piece of data. */
4380 boost::shared_ptr<Evoral::ControlList> &al_cpy = i->second.copy;
4381 for (AutomationList::iterator ctrl_evt = al_cpy->begin(); ctrl_evt != al_cpy->end(); ++ctrl_evt) {
4382 (*ctrl_evt)->when -= line_offset;
4385 /* And add it to the cut buffer */
4386 cut_buffer->add (al_cpy);
4390 if (op == Delete || op == Cut) {
4391 /* This operation needs to remove things from the main AutomationList, so do that now */
4393 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
4394 i->first->freeze ();
4397 /* Remove each selected point from its AutomationList */
4398 for (PointSelection::iterator sel_point = selection->points.begin(); sel_point != selection->points.end(); ++sel_point) {
4399 AutomationLine& line = (*sel_point)->line ();
4400 boost::shared_ptr<AutomationList> al = line.the_list();
4404 if (dynamic_cast<AudioRegionGainLine*> (&line)) {
4405 /* removing of first and last gain point in region gain lines is prohibited*/
4406 if (line.is_last_point (*(*sel_point)) || line.is_first_point (*(*sel_point))) {
4412 al->erase ((*sel_point)->model ());
4416 /* Thaw the lists and add undo records for them */
4417 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
4418 boost::shared_ptr<AutomationList> al = i->first;
4420 _session->add_command (new MementoCommand<AutomationList> (*al.get(), i->second.state, &(al->get_state ())));
4425 /** Cut, copy or clear selected automation points.
4426 * @param op Operation (Cut, Copy or Clear)
4429 Editor::cut_copy_midi (CutCopyOp op)
4431 Evoral::Beats earliest = Evoral::Beats::max();
4432 for (MidiRegionSelection::iterator i = selection->midi_regions.begin(); i != selection->midi_regions.end(); ++i) {
4433 MidiRegionView* mrv = dynamic_cast<MidiRegionView*>(*i);
4435 if (!mrv->selection().empty()) {
4436 earliest = std::min(earliest, (*mrv->selection().begin())->note()->time());
4438 mrv->cut_copy_clear (op);
4440 /* XXX: not ideal, as there may be more than one track involved in the selection */
4441 _last_cut_copy_source_track = &mrv->get_time_axis_view();
4445 if (!selection->points.empty()) {
4446 cut_copy_points (op, earliest, true);
4447 if (op == Cut || op == Delete) {
4448 selection->clear_points ();
4453 struct lt_playlist {
4454 bool operator () (const PlaylistState& a, const PlaylistState& b) {
4455 return a.playlist < b.playlist;
4459 struct PlaylistMapping {
4461 boost::shared_ptr<Playlist> pl;
4463 PlaylistMapping (TimeAxisView* tvp) : tv (tvp) {}
4466 /** Remove `clicked_regionview' */
4468 Editor::remove_clicked_region ()
4470 if (clicked_routeview == 0 || clicked_regionview == 0) {
4474 begin_reversible_command (_("remove region"));
4476 boost::shared_ptr<Playlist> playlist = clicked_routeview->playlist();
4478 playlist->clear_changes ();
4479 playlist->clear_owned_changes ();
4480 playlist->remove_region (clicked_regionview->region());
4481 if (Config->get_edit_mode() == Ripple)
4482 playlist->ripple (clicked_regionview->region()->position(), -clicked_regionview->region()->length(), boost::shared_ptr<Region>());
4484 /* We might have removed regions, which alters other regions' layering_index,
4485 so we need to do a recursive diff here.
4487 vector<Command*> cmds;
4488 playlist->rdiff (cmds);
4489 _session->add_commands (cmds);
4491 _session->add_command(new StatefulDiffCommand (playlist));
4492 commit_reversible_command ();
4496 /** Remove the selected regions */
4498 Editor::remove_selected_regions ()
4500 RegionSelection rs = get_regions_from_selection_and_entered ();
4502 if (!_session || rs.empty()) {
4506 list<boost::shared_ptr<Region> > regions_to_remove;
4508 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
4509 // we can't just remove the region(s) in this loop because
4510 // this removes them from the RegionSelection, and they thus
4511 // disappear from underneath the iterator, and the ++i above
4512 // SEGVs in a puzzling fashion.
4514 // so, first iterate over the regions to be removed from rs and
4515 // add them to the regions_to_remove list, and then
4516 // iterate over the list to actually remove them.
4518 regions_to_remove.push_back ((*i)->region());
4521 vector<boost::shared_ptr<Playlist> > playlists;
4523 for (list<boost::shared_ptr<Region> >::iterator rl = regions_to_remove.begin(); rl != regions_to_remove.end(); ++rl) {
4525 boost::shared_ptr<Playlist> playlist = (*rl)->playlist();
4528 // is this check necessary?
4532 /* get_regions_from_selection_and_entered() guarantees that
4533 the playlists involved are unique, so there is no need
4537 playlists.push_back (playlist);
4539 playlist->clear_changes ();
4540 playlist->clear_owned_changes ();
4541 playlist->freeze ();
4542 playlist->remove_region (*rl);
4543 if (Config->get_edit_mode() == Ripple)
4544 playlist->ripple ((*rl)->position(), -(*rl)->length(), boost::shared_ptr<Region>());
4548 vector<boost::shared_ptr<Playlist> >::iterator pl;
4549 bool in_command = false;
4551 for (pl = playlists.begin(); pl != playlists.end(); ++pl) {
4554 /* We might have removed regions, which alters other regions' layering_index,
4555 so we need to do a recursive diff here.
4559 begin_reversible_command (_("remove region"));
4562 vector<Command*> cmds;
4563 (*pl)->rdiff (cmds);
4564 _session->add_commands (cmds);
4566 _session->add_command(new StatefulDiffCommand (*pl));
4570 commit_reversible_command ();
4574 /** Cut, copy or clear selected regions.
4575 * @param op Operation (Cut, Copy or Clear)
4578 Editor::cut_copy_regions (CutCopyOp op, RegionSelection& rs)
4580 /* we can't use a std::map here because the ordering is important, and we can't trivially sort
4581 a map when we want ordered access to both elements. i think.
4584 vector<PlaylistMapping> pmap;
4586 framepos_t first_position = max_framepos;
4588 typedef set<boost::shared_ptr<Playlist> > FreezeList;
4589 FreezeList freezelist;
4591 /* get ordering correct before we cut/copy */
4593 rs.sort_by_position_and_track ();
4595 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
4597 first_position = min ((framepos_t) (*x)->region()->position(), first_position);
4599 if (op == Cut || op == Clear || op == Delete) {
4600 boost::shared_ptr<Playlist> pl = (*x)->region()->playlist();
4603 FreezeList::iterator fl;
4605 // only take state if this is a new playlist.
4606 for (fl = freezelist.begin(); fl != freezelist.end(); ++fl) {
4612 if (fl == freezelist.end()) {
4613 pl->clear_changes();
4614 pl->clear_owned_changes ();
4616 freezelist.insert (pl);
4621 TimeAxisView* tv = &(*x)->get_time_axis_view();
4622 vector<PlaylistMapping>::iterator z;
4624 for (z = pmap.begin(); z != pmap.end(); ++z) {
4625 if ((*z).tv == tv) {
4630 if (z == pmap.end()) {
4631 pmap.push_back (PlaylistMapping (tv));
4635 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ) {
4637 boost::shared_ptr<Playlist> pl = (*x)->region()->playlist();
4640 /* region not yet associated with a playlist (e.g. unfinished
4647 TimeAxisView& tv = (*x)->get_time_axis_view();
4648 boost::shared_ptr<Playlist> npl;
4649 RegionSelection::iterator tmp;
4656 vector<PlaylistMapping>::iterator z;
4658 for (z = pmap.begin(); z != pmap.end(); ++z) {
4659 if ((*z).tv == &tv) {
4664 assert (z != pmap.end());
4667 npl = PlaylistFactory::create (pl->data_type(), *_session, "cutlist", true);
4675 boost::shared_ptr<Region> r = (*x)->region();
4676 boost::shared_ptr<Region> _xx;
4682 pl->remove_region (r);
4683 if (Config->get_edit_mode() == Ripple)
4684 pl->ripple (r->position(), -r->length(), boost::shared_ptr<Region>());
4688 _xx = RegionFactory::create (r);
4689 npl->add_region (_xx, r->position() - first_position);
4690 pl->remove_region (r);
4691 if (Config->get_edit_mode() == Ripple)
4692 pl->ripple (r->position(), -r->length(), boost::shared_ptr<Region>());
4696 /* copy region before adding, so we're not putting same object into two different playlists */
4697 npl->add_region (RegionFactory::create (r), r->position() - first_position);
4701 pl->remove_region (r);
4702 if (Config->get_edit_mode() == Ripple)
4703 pl->ripple (r->position(), -r->length(), boost::shared_ptr<Region>());
4712 list<boost::shared_ptr<Playlist> > foo;
4714 /* the pmap is in the same order as the tracks in which selected regions occurred */
4716 for (vector<PlaylistMapping>::iterator i = pmap.begin(); i != pmap.end(); ++i) {
4719 foo.push_back ((*i).pl);
4724 cut_buffer->set (foo);
4728 _last_cut_copy_source_track = 0;
4730 _last_cut_copy_source_track = pmap.front().tv;
4734 for (FreezeList::iterator pl = freezelist.begin(); pl != freezelist.end(); ++pl) {
4737 /* We might have removed regions, which alters other regions' layering_index,
4738 so we need to do a recursive diff here.
4740 vector<Command*> cmds;
4741 (*pl)->rdiff (cmds);
4742 _session->add_commands (cmds);
4744 _session->add_command (new StatefulDiffCommand (*pl));
4749 Editor::cut_copy_ranges (CutCopyOp op)
4751 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4753 /* Sort the track selection now, so that it if is used, the playlists
4754 selected by the calls below to cut_copy_clear are in the order that
4755 their tracks appear in the editor. This makes things like paste
4756 of ranges work properly.
4759 sort_track_selection (ts);
4762 if (!entered_track) {
4765 ts.push_back (entered_track);
4768 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4769 (*i)->cut_copy_clear (*selection, op);
4774 Editor::paste (float times, bool from_context)
4776 DEBUG_TRACE (DEBUG::CutNPaste, "paste to preferred edit pos\n");
4777 MusicFrame where (get_preferred_edit_position (EDIT_IGNORE_NONE, from_context), 0);
4778 paste_internal (where.frame, times, 0);
4782 Editor::mouse_paste ()
4784 MusicFrame where (0, 0);
4786 if (!mouse_frame (where.frame, ignored)) {
4791 paste_internal (where.frame, 1, where.division);
4795 Editor::paste_internal (framepos_t position, float times, const int32_t sub_num)
4797 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("apparent paste position is %1\n", position));
4799 if (cut_buffer->empty(internal_editing())) {
4803 if (position == max_framepos) {
4804 position = get_preferred_edit_position();
4805 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("preferred edit position is %1\n", position));
4808 if (position == last_paste_pos) {
4809 /* repeated paste in the same position */
4812 /* paste in new location, reset repeated paste state */
4814 last_paste_pos = position;
4817 /* get everything in the correct order */
4820 if (!selection->tracks.empty()) {
4821 /* If there is a track selection, paste into exactly those tracks and
4822 * only those tracks. This allows the user to be explicit and override
4823 * the below "do the reasonable thing" logic. */
4824 ts = selection->tracks.filter_to_unique_playlists ();
4825 sort_track_selection (ts);
4827 /* Figure out which track to base the paste at. */
4828 TimeAxisView* base_track = NULL;
4829 if (_edit_point == Editing::EditAtMouse && entered_track) {
4830 /* With the mouse edit point, paste onto the track under the mouse. */
4831 base_track = entered_track;
4832 } else if (_edit_point == Editing::EditAtMouse && entered_regionview) {
4833 /* With the mouse edit point, paste onto the track of the region under the mouse. */
4834 base_track = &entered_regionview->get_time_axis_view();
4835 } else if (_last_cut_copy_source_track) {
4836 /* Paste to the track that the cut/copy came from (see mantis #333). */
4837 base_track = _last_cut_copy_source_track;
4839 /* This is "impossible" since we've copied... well, do nothing. */
4843 /* Walk up to parent if necessary, so base track is a route. */
4844 while (base_track->get_parent()) {
4845 base_track = base_track->get_parent();
4848 /* Add base track and all tracks below it. The paste logic will select
4849 the appropriate object types from the cut buffer in relative order. */
4850 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4851 if ((*i)->order() >= base_track->order()) {
4856 /* Sort tracks so the nth track of type T will pick the nth object of type T. */
4857 sort_track_selection (ts);
4859 /* Add automation children of each track in order, for pasting several lines. */
4860 for (TrackViewList::iterator i = ts.begin(); i != ts.end();) {
4861 /* Add any automation children for pasting several lines */
4862 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*i++);
4867 typedef RouteTimeAxisView::AutomationTracks ATracks;
4868 const ATracks& atracks = rtv->automation_tracks();
4869 for (ATracks::const_iterator a = atracks.begin(); a != atracks.end(); ++a) {
4870 i = ts.insert(i, a->second.get());
4875 /* We now have a list of trackviews starting at base_track, including
4876 automation children, in the order shown in the editor, e.g. R1,
4877 R1.A1, R1.A2, R2, R2.A1, ... */
4880 begin_reversible_command (Operations::paste);
4882 if (ts.size() == 1 && cut_buffer->lines.size() == 1 &&
4883 dynamic_cast<AutomationTimeAxisView*>(ts.front())) {
4884 /* Only one line copied, and one automation track selected. Do a
4885 "greedy" paste from one automation type to another. */
4887 PasteContext ctx(paste_count, times, ItemCounts(), true);
4888 ts.front()->paste (position, *cut_buffer, ctx, sub_num);
4892 /* Paste into tracks */
4894 PasteContext ctx(paste_count, times, ItemCounts(), false);
4895 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4896 (*i)->paste (position, *cut_buffer, ctx, sub_num);
4900 commit_reversible_command ();
4904 Editor::duplicate_regions (float times)
4906 RegionSelection rs (get_regions_from_selection_and_entered());
4907 duplicate_some_regions (rs, times);
4911 Editor::duplicate_some_regions (RegionSelection& regions, float times)
4913 if (regions.empty ()) {
4917 boost::shared_ptr<Playlist> playlist;
4918 RegionSelection sel = regions; // clear (below) may clear the argument list if its the current region selection
4919 RegionSelection foo;
4921 framepos_t const start_frame = regions.start ();
4922 framepos_t const end_frame = regions.end_frame ();
4923 framecnt_t const gap = end_frame - start_frame + 1;
4925 begin_reversible_command (Operations::duplicate_region);
4927 selection->clear_regions ();
4929 for (RegionSelection::iterator i = sel.begin(); i != sel.end(); ++i) {
4931 boost::shared_ptr<Region> r ((*i)->region());
4933 TimeAxisView& tv = (*i)->get_time_axis_view();
4934 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (&tv);
4935 latest_regionviews.clear ();
4936 sigc::connection c = rtv->view()->RegionViewAdded.connect (sigc::mem_fun(*this, &Editor::collect_new_region_view));
4938 framepos_t const position = end_frame + (r->first_frame() - start_frame + 1);
4939 playlist = (*i)->region()->playlist();
4940 playlist->clear_changes ();
4941 playlist->duplicate (r, position, gap, times);
4942 _session->add_command(new StatefulDiffCommand (playlist));
4946 foo.insert (foo.end(), latest_regionviews.begin(), latest_regionviews.end());
4950 selection->set (foo);
4953 commit_reversible_command ();
4957 Editor::duplicate_selection (float times)
4959 if (selection->time.empty() || selection->tracks.empty()) {
4963 boost::shared_ptr<Playlist> playlist;
4965 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4967 bool in_command = false;
4969 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4970 if ((playlist = (*i)->playlist()) == 0) {
4973 playlist->clear_changes ();
4975 if (clicked_selection) {
4976 playlist->duplicate_range (selection->time[clicked_selection], times);
4978 playlist->duplicate_ranges (selection->time, times);
4982 begin_reversible_command (_("duplicate range selection"));
4985 _session->add_command (new StatefulDiffCommand (playlist));
4990 if (times == 1.0f) {
4991 // now "move" range selection to after the current range selection
4992 framecnt_t distance = 0;
4994 if (clicked_selection) {
4996 selection->time[clicked_selection].end - selection->time[clicked_selection].start;
4998 distance = selection->time.end_frame () - selection->time.start ();
5001 selection->move_time (distance);
5003 commit_reversible_command ();
5007 /** Reset all selected points to the relevant default value */
5009 Editor::reset_point_selection ()
5011 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
5012 ARDOUR::AutomationList::iterator j = (*i)->model ();
5013 (*j)->value = (*i)->line().the_list()->descriptor ().normal;
5018 Editor::center_playhead ()
5020 float const page = _visible_canvas_width * samples_per_pixel;
5021 center_screen_internal (playhead_cursor->current_frame (), page);
5025 Editor::center_edit_point ()
5027 float const page = _visible_canvas_width * samples_per_pixel;
5028 center_screen_internal (get_preferred_edit_position(), page);
5031 /** Caller must begin and commit a reversible command */
5033 Editor::clear_playlist (boost::shared_ptr<Playlist> playlist)
5035 playlist->clear_changes ();
5037 _session->add_command (new StatefulDiffCommand (playlist));
5041 Editor::nudge_track (bool use_edit, bool forwards)
5043 boost::shared_ptr<Playlist> playlist;
5044 framepos_t distance;
5045 framepos_t next_distance;
5049 start = get_preferred_edit_position();
5054 if ((distance = get_nudge_distance (start, next_distance)) == 0) {
5058 if (selection->tracks.empty()) {
5062 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
5063 bool in_command = false;
5065 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
5067 if ((playlist = (*i)->playlist()) == 0) {
5071 playlist->clear_changes ();
5072 playlist->clear_owned_changes ();
5074 playlist->nudge_after (start, distance, forwards);
5077 begin_reversible_command (_("nudge track"));
5080 vector<Command*> cmds;
5082 playlist->rdiff (cmds);
5083 _session->add_commands (cmds);
5085 _session->add_command (new StatefulDiffCommand (playlist));
5089 commit_reversible_command ();
5094 Editor::remove_last_capture ()
5096 vector<string> choices;
5103 if (Config->get_verify_remove_last_capture()) {
5104 prompt = _("Do you really want to destroy the last capture?"
5105 "\n(This is destructive and cannot be undone)");
5107 choices.push_back (_("No, do nothing."));
5108 choices.push_back (_("Yes, destroy it."));
5110 Choice prompter (_("Destroy last capture"), prompt, choices);
5112 if (prompter.run () == 1) {
5113 _session->remove_last_capture ();
5114 _regions->redisplay ();
5118 _session->remove_last_capture();
5119 _regions->redisplay ();
5124 Editor::normalize_region ()
5130 RegionSelection rs = get_regions_from_selection_and_entered ();
5136 NormalizeDialog dialog (rs.size() > 1);
5138 if (dialog.run () != RESPONSE_ACCEPT) {
5142 CursorContext::Handle cursor_ctx = CursorContext::create(*this, _cursors->wait);
5145 /* XXX: should really only count audio regions here */
5146 int const regions = rs.size ();
5148 /* Make a list of the selected audio regions' maximum amplitudes, and also
5149 obtain the maximum amplitude of them all.
5151 list<double> max_amps;
5152 list<double> rms_vals;
5155 bool use_rms = dialog.constrain_rms ();
5157 for (RegionSelection::const_iterator i = rs.begin(); i != rs.end(); ++i) {
5158 AudioRegionView const * arv = dynamic_cast<AudioRegionView const *> (*i);
5162 dialog.descend (1.0 / regions);
5163 double const a = arv->audio_region()->maximum_amplitude (&dialog);
5165 double r = arv->audio_region()->rms (&dialog);
5166 max_rms = max (max_rms, r);
5167 rms_vals.push_back (r);
5171 /* the user cancelled the operation */
5175 max_amps.push_back (a);
5176 max_amp = max (max_amp, a);
5180 list<double>::const_iterator a = max_amps.begin ();
5181 list<double>::const_iterator l = rms_vals.begin ();
5182 bool in_command = false;
5184 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
5185 AudioRegionView* const arv = dynamic_cast<AudioRegionView*> (*r);
5190 arv->region()->clear_changes ();
5192 double amp = dialog.normalize_individually() ? *a : max_amp;
5193 double target = dialog.target_peak (); // dB
5196 double const amp_rms = dialog.normalize_individually() ? *l : max_rms;
5197 const double t_rms = dialog.target_rms ();
5198 const gain_t c_peak = dB_to_coefficient (target);
5199 const gain_t c_rms = dB_to_coefficient (t_rms);
5200 if ((amp_rms / c_rms) > (amp / c_peak)) {
5206 arv->audio_region()->normalize (amp, target);
5209 begin_reversible_command (_("normalize"));
5212 _session->add_command (new StatefulDiffCommand (arv->region()));
5219 commit_reversible_command ();
5225 Editor::reset_region_scale_amplitude ()
5231 RegionSelection rs = get_regions_from_selection_and_entered ();
5237 bool in_command = false;
5239 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
5240 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
5243 arv->region()->clear_changes ();
5244 arv->audio_region()->set_scale_amplitude (1.0f);
5247 begin_reversible_command ("reset gain");
5250 _session->add_command (new StatefulDiffCommand (arv->region()));
5254 commit_reversible_command ();
5259 Editor::adjust_region_gain (bool up)
5261 RegionSelection rs = get_regions_from_selection_and_entered ();
5263 if (!_session || rs.empty()) {
5267 bool in_command = false;
5269 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
5270 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
5275 arv->region()->clear_changes ();
5277 double dB = accurate_coefficient_to_dB (arv->audio_region()->scale_amplitude ());
5285 arv->audio_region()->set_scale_amplitude (dB_to_coefficient (dB));
5288 begin_reversible_command ("adjust region gain");
5291 _session->add_command (new StatefulDiffCommand (arv->region()));
5295 commit_reversible_command ();
5300 Editor::reset_region_gain ()
5302 RegionSelection rs = get_regions_from_selection_and_entered ();
5304 if (!_session || rs.empty()) {
5308 bool in_command = false;
5310 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
5311 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
5316 arv->region()->clear_changes ();
5318 arv->audio_region()->set_scale_amplitude (1.0f);
5321 begin_reversible_command ("reset region gain");
5324 _session->add_command (new StatefulDiffCommand (arv->region()));
5328 commit_reversible_command ();
5333 Editor::reverse_region ()
5339 Reverse rev (*_session);
5340 apply_filter (rev, _("reverse regions"));
5344 Editor::strip_region_silence ()
5350 RegionSelection rs = get_regions_from_selection_and_entered ();
5356 std::list<RegionView*> audio_only;
5358 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5359 AudioRegionView* const arv = dynamic_cast<AudioRegionView*> (*i);
5361 audio_only.push_back (arv);
5365 assert (!audio_only.empty());
5367 StripSilenceDialog d (_session, audio_only);
5368 int const r = d.run ();
5372 if (r == Gtk::RESPONSE_OK) {
5373 ARDOUR::AudioIntervalMap silences;
5374 d.silences (silences);
5375 StripSilence s (*_session, silences, d.fade_length());
5377 apply_filter (s, _("strip silence"), &d);
5382 Editor::apply_midi_note_edit_op_to_region (MidiOperator& op, MidiRegionView& mrv)
5384 Evoral::Sequence<Evoral::Beats>::Notes selected;
5385 mrv.selection_as_notelist (selected, true);
5387 vector<Evoral::Sequence<Evoral::Beats>::Notes> v;
5388 v.push_back (selected);
5390 Evoral::Beats pos_beats = Evoral::Beats (mrv.midi_region()->beat()) - mrv.midi_region()->start_beats();
5392 return op (mrv.midi_region()->model(), pos_beats, v);
5396 Editor::apply_midi_note_edit_op (MidiOperator& op, const RegionSelection& rs)
5402 bool in_command = false;
5404 for (RegionSelection::const_iterator r = rs.begin(); r != rs.end(); ) {
5405 RegionSelection::const_iterator tmp = r;
5408 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*r);
5411 Command* cmd = apply_midi_note_edit_op_to_region (op, *mrv);
5414 begin_reversible_command (op.name ());
5418 _session->add_command (cmd);
5426 commit_reversible_command ();
5427 _session->set_dirty ();
5432 Editor::fork_region ()
5434 RegionSelection rs = get_regions_from_selection_and_entered ();
5440 CursorContext::Handle cursor_ctx = CursorContext::create(*this, _cursors->wait);
5441 bool in_command = false;
5445 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
5446 RegionSelection::iterator tmp = r;
5449 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*>(*r);
5453 boost::shared_ptr<Playlist> playlist = mrv->region()->playlist();
5454 boost::shared_ptr<MidiSource> new_source = _session->create_midi_source_by_stealing_name (mrv->midi_view()->track());
5455 boost::shared_ptr<MidiRegion> newregion = mrv->midi_region()->clone (new_source);
5458 begin_reversible_command (_("Fork Region(s)"));
5461 playlist->clear_changes ();
5462 playlist->replace_region (mrv->region(), newregion, mrv->region()->position());
5463 _session->add_command(new StatefulDiffCommand (playlist));
5465 error << string_compose (_("Could not unlink %1"), mrv->region()->name()) << endmsg;
5473 commit_reversible_command ();
5478 Editor::quantize_region ()
5481 quantize_regions(get_regions_from_selection_and_entered ());
5486 Editor::quantize_regions (const RegionSelection& rs)
5488 if (rs.n_midi_regions() == 0) {
5492 if (!quantize_dialog) {
5493 quantize_dialog = new QuantizeDialog (*this);
5496 if (quantize_dialog->is_mapped()) {
5497 /* in progress already */
5501 quantize_dialog->present ();
5502 const int r = quantize_dialog->run ();
5503 quantize_dialog->hide ();
5505 if (r == Gtk::RESPONSE_OK) {
5506 Quantize quant (quantize_dialog->snap_start(),
5507 quantize_dialog->snap_end(),
5508 quantize_dialog->start_grid_size(),
5509 quantize_dialog->end_grid_size(),
5510 quantize_dialog->strength(),
5511 quantize_dialog->swing(),
5512 quantize_dialog->threshold());
5514 apply_midi_note_edit_op (quant, rs);
5519 Editor::legatize_region (bool shrink_only)
5522 legatize_regions(get_regions_from_selection_and_entered (), shrink_only);
5527 Editor::legatize_regions (const RegionSelection& rs, bool shrink_only)
5529 if (rs.n_midi_regions() == 0) {
5533 Legatize legatize(shrink_only);
5534 apply_midi_note_edit_op (legatize, rs);
5538 Editor::transform_region ()
5541 transform_regions(get_regions_from_selection_and_entered ());
5546 Editor::transform_regions (const RegionSelection& rs)
5548 if (rs.n_midi_regions() == 0) {
5555 const int r = td.run();
5558 if (r == Gtk::RESPONSE_OK) {
5559 Transform transform(td.get());
5560 apply_midi_note_edit_op(transform, rs);
5565 Editor::transpose_region ()
5568 transpose_regions(get_regions_from_selection_and_entered ());
5573 Editor::transpose_regions (const RegionSelection& rs)
5575 if (rs.n_midi_regions() == 0) {
5580 int const r = d.run ();
5582 if (r == RESPONSE_ACCEPT) {
5583 Transpose transpose(d.semitones ());
5584 apply_midi_note_edit_op (transpose, rs);
5589 Editor::insert_patch_change (bool from_context)
5591 RegionSelection rs = get_regions_from_selection_and_entered ();
5597 const framepos_t p = get_preferred_edit_position (EDIT_IGNORE_NONE, from_context);
5599 /* XXX: bit of a hack; use the MIDNAM from the first selected region;
5600 there may be more than one, but the PatchChangeDialog can only offer
5601 one set of patch menus.
5603 MidiRegionView* first = dynamic_cast<MidiRegionView*> (rs.front ());
5605 Evoral::PatchChange<Evoral::Beats> empty (Evoral::Beats(), 0, 0, 0);
5606 PatchChangeDialog d (0, _session, empty, first->instrument_info(), Gtk::Stock::ADD);
5608 if (d.run() == RESPONSE_CANCEL) {
5612 for (RegionSelection::iterator i = rs.begin (); i != rs.end(); ++i) {
5613 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*i);
5615 if (p >= mrv->region()->first_frame() && p <= mrv->region()->last_frame()) {
5616 mrv->add_patch_change (p - mrv->region()->position(), d.patch ());
5623 Editor::apply_filter (Filter& filter, string command, ProgressReporter* progress)
5625 RegionSelection rs = get_regions_from_selection_and_entered ();
5631 CursorContext::Handle cursor_ctx = CursorContext::create(*this, _cursors->wait);
5632 bool in_command = false;
5637 int const N = rs.size ();
5639 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
5640 RegionSelection::iterator tmp = r;
5643 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
5645 boost::shared_ptr<Playlist> playlist = arv->region()->playlist();
5648 progress->descend (1.0 / N);
5651 if (arv->audio_region()->apply (filter, progress) == 0) {
5653 playlist->clear_changes ();
5654 playlist->clear_owned_changes ();
5657 begin_reversible_command (command);
5661 if (filter.results.empty ()) {
5663 /* no regions returned; remove the old one */
5664 playlist->remove_region (arv->region ());
5668 std::vector<boost::shared_ptr<Region> >::iterator res = filter.results.begin ();
5670 /* first region replaces the old one */
5671 playlist->replace_region (arv->region(), *res, (*res)->position());
5675 while (res != filter.results.end()) {
5676 playlist->add_region (*res, (*res)->position());
5682 /* We might have removed regions, which alters other regions' layering_index,
5683 so we need to do a recursive diff here.
5685 vector<Command*> cmds;
5686 playlist->rdiff (cmds);
5687 _session->add_commands (cmds);
5689 _session->add_command(new StatefulDiffCommand (playlist));
5693 progress->ascend ();
5702 commit_reversible_command ();
5707 Editor::external_edit_region ()
5713 Editor::reset_region_gain_envelopes ()
5715 RegionSelection rs = get_regions_from_selection_and_entered ();
5717 if (!_session || rs.empty()) {
5721 bool in_command = false;
5723 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5724 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
5726 boost::shared_ptr<AutomationList> alist (arv->audio_region()->envelope());
5727 XMLNode& before (alist->get_state());
5729 arv->audio_region()->set_default_envelope ();
5732 begin_reversible_command (_("reset region gain"));
5735 _session->add_command (new MementoCommand<AutomationList>(*arv->audio_region()->envelope().get(), &before, &alist->get_state()));
5740 commit_reversible_command ();
5745 Editor::set_region_gain_visibility (RegionView* rv)
5747 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (rv);
5749 arv->update_envelope_visibility();
5754 Editor::set_gain_envelope_visibility ()
5760 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5761 AudioTimeAxisView* v = dynamic_cast<AudioTimeAxisView*>(*i);
5763 v->audio_view()->foreach_regionview (sigc::mem_fun (this, &Editor::set_region_gain_visibility));
5769 Editor::toggle_gain_envelope_active ()
5771 if (_ignore_region_action) {
5775 RegionSelection rs = get_regions_from_selection_and_entered ();
5777 if (!_session || rs.empty()) {
5781 bool in_command = false;
5783 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5784 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
5786 arv->region()->clear_changes ();
5787 arv->audio_region()->set_envelope_active (!arv->audio_region()->envelope_active());
5790 begin_reversible_command (_("region gain envelope active"));
5793 _session->add_command (new StatefulDiffCommand (arv->region()));
5798 commit_reversible_command ();
5803 Editor::toggle_region_lock ()
5805 if (_ignore_region_action) {
5809 RegionSelection rs = get_regions_from_selection_and_entered ();
5811 if (!_session || rs.empty()) {
5815 begin_reversible_command (_("toggle region lock"));
5817 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5818 (*i)->region()->clear_changes ();
5819 (*i)->region()->set_locked (!(*i)->region()->locked());
5820 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5823 commit_reversible_command ();
5827 Editor::toggle_region_video_lock ()
5829 if (_ignore_region_action) {
5833 RegionSelection rs = get_regions_from_selection_and_entered ();
5835 if (!_session || rs.empty()) {
5839 begin_reversible_command (_("Toggle Video Lock"));
5841 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5842 (*i)->region()->clear_changes ();
5843 (*i)->region()->set_video_locked (!(*i)->region()->video_locked());
5844 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5847 commit_reversible_command ();
5851 Editor::toggle_region_lock_style ()
5853 if (_ignore_region_action) {
5857 RegionSelection rs = get_regions_from_selection_and_entered ();
5859 if (!_session || rs.empty()) {
5863 Glib::RefPtr<ToggleAction> a = Glib::RefPtr<ToggleAction>::cast_dynamic (_region_actions->get_action("toggle-region-lock-style"));
5864 vector<Widget*> proxies = a->get_proxies();
5865 Gtk::CheckMenuItem* cmi = dynamic_cast<Gtk::CheckMenuItem*> (proxies.front());
5869 begin_reversible_command (_("toggle region lock style"));
5871 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5872 (*i)->region()->clear_changes ();
5873 PositionLockStyle const ns = ((*i)->region()->position_lock_style() == AudioTime && !cmi->get_inconsistent()) ? MusicTime : AudioTime;
5874 (*i)->region()->set_position_lock_style (ns);
5875 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5878 commit_reversible_command ();
5882 Editor::toggle_opaque_region ()
5884 if (_ignore_region_action) {
5888 RegionSelection rs = get_regions_from_selection_and_entered ();
5890 if (!_session || rs.empty()) {
5894 begin_reversible_command (_("change region opacity"));
5896 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5897 (*i)->region()->clear_changes ();
5898 (*i)->region()->set_opaque (!(*i)->region()->opaque());
5899 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5902 commit_reversible_command ();
5906 Editor::toggle_record_enable ()
5908 bool new_state = false;
5910 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5911 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5914 if (!rtav->is_track())
5918 new_state = !rtav->track()->rec_enable_control()->get_value();
5922 rtav->track()->rec_enable_control()->set_value (new_state, Controllable::UseGroup);
5927 Editor::toggle_solo ()
5929 bool new_state = false;
5931 boost::shared_ptr<ControlList> cl (new ControlList);
5933 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5934 StripableTimeAxisView *stav = dynamic_cast<StripableTimeAxisView *>(*i);
5936 if (!stav || !stav->stripable()->solo_control()) {
5941 new_state = !stav->stripable()->solo_control()->soloed ();
5945 cl->push_back (stav->stripable()->solo_control());
5948 _session->set_controls (cl, new_state ? 1.0 : 0.0, Controllable::UseGroup);
5952 Editor::toggle_mute ()
5954 bool new_state = false;
5956 boost::shared_ptr<ControlList> cl (new ControlList);
5958 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5959 StripableTimeAxisView *stav = dynamic_cast<StripableTimeAxisView *>(*i);
5961 if (!stav || !stav->stripable()->mute_control()) {
5966 new_state = !stav->stripable()->mute_control()->muted();
5970 cl->push_back (stav->stripable()->mute_control());
5973 _session->set_controls (cl, new_state, Controllable::UseGroup);
5977 Editor::toggle_solo_isolate ()
5983 Editor::fade_range ()
5985 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
5987 begin_reversible_command (_("fade range"));
5989 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
5990 (*i)->fade_range (selection->time);
5993 commit_reversible_command ();
5998 Editor::set_fade_length (bool in)
6000 RegionSelection rs = get_regions_from_selection_and_entered ();
6006 /* we need a region to measure the offset from the start */
6008 RegionView* rv = rs.front ();
6010 framepos_t pos = get_preferred_edit_position();
6014 if (pos > rv->region()->last_frame() || pos < rv->region()->first_frame()) {
6015 /* edit point is outside the relevant region */
6020 if (pos <= rv->region()->position()) {
6024 len = pos - rv->region()->position();
6025 cmd = _("set fade in length");
6027 if (pos >= rv->region()->last_frame()) {
6031 len = rv->region()->last_frame() - pos;
6032 cmd = _("set fade out length");
6035 bool in_command = false;
6037 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
6038 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
6044 boost::shared_ptr<AutomationList> alist;
6046 alist = tmp->audio_region()->fade_in();
6048 alist = tmp->audio_region()->fade_out();
6051 XMLNode &before = alist->get_state();
6054 tmp->audio_region()->set_fade_in_length (len);
6055 tmp->audio_region()->set_fade_in_active (true);
6057 tmp->audio_region()->set_fade_out_length (len);
6058 tmp->audio_region()->set_fade_out_active (true);
6062 begin_reversible_command (cmd);
6065 XMLNode &after = alist->get_state();
6066 _session->add_command(new MementoCommand<AutomationList>(*alist, &before, &after));
6070 commit_reversible_command ();
6075 Editor::set_fade_in_shape (FadeShape shape)
6077 RegionSelection rs = get_regions_from_selection_and_entered ();
6082 bool in_command = false;
6084 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
6085 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
6091 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_in();
6092 XMLNode &before = alist->get_state();
6094 tmp->audio_region()->set_fade_in_shape (shape);
6097 begin_reversible_command (_("set fade in shape"));
6100 XMLNode &after = alist->get_state();
6101 _session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
6105 commit_reversible_command ();
6110 Editor::set_fade_out_shape (FadeShape shape)
6112 RegionSelection rs = get_regions_from_selection_and_entered ();
6117 bool in_command = false;
6119 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
6120 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
6126 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_out();
6127 XMLNode &before = alist->get_state();
6129 tmp->audio_region()->set_fade_out_shape (shape);
6132 begin_reversible_command (_("set fade out shape"));
6135 XMLNode &after = alist->get_state();
6136 _session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
6140 commit_reversible_command ();
6145 Editor::set_fade_in_active (bool yn)
6147 RegionSelection rs = get_regions_from_selection_and_entered ();
6152 bool in_command = false;
6154 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
6155 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
6162 boost::shared_ptr<AudioRegion> ar (tmp->audio_region());
6164 ar->clear_changes ();
6165 ar->set_fade_in_active (yn);
6168 begin_reversible_command (_("set fade in active"));
6171 _session->add_command (new StatefulDiffCommand (ar));
6175 commit_reversible_command ();
6180 Editor::set_fade_out_active (bool yn)
6182 RegionSelection rs = get_regions_from_selection_and_entered ();
6187 bool in_command = false;
6189 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
6190 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
6196 boost::shared_ptr<AudioRegion> ar (tmp->audio_region());
6198 ar->clear_changes ();
6199 ar->set_fade_out_active (yn);
6202 begin_reversible_command (_("set fade out active"));
6205 _session->add_command(new StatefulDiffCommand (ar));
6209 commit_reversible_command ();
6214 Editor::toggle_region_fades (int dir)
6216 if (_ignore_region_action) {
6220 boost::shared_ptr<AudioRegion> ar;
6223 RegionSelection rs = get_regions_from_selection_and_entered ();
6229 RegionSelection::iterator i;
6230 for (i = rs.begin(); i != rs.end(); ++i) {
6231 if ((ar = boost::dynamic_pointer_cast<AudioRegion>((*i)->region())) != 0) {
6233 yn = ar->fade_out_active ();
6235 yn = ar->fade_in_active ();
6241 if (i == rs.end()) {
6245 /* XXX should this undo-able? */
6246 bool in_command = false;
6248 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
6249 if ((ar = boost::dynamic_pointer_cast<AudioRegion>((*i)->region())) == 0) {
6252 ar->clear_changes ();
6254 if (dir == 1 || dir == 0) {
6255 ar->set_fade_in_active (!yn);
6258 if (dir == -1 || dir == 0) {
6259 ar->set_fade_out_active (!yn);
6262 begin_reversible_command (_("toggle fade active"));
6265 _session->add_command(new StatefulDiffCommand (ar));
6269 commit_reversible_command ();
6274 /** Update region fade visibility after its configuration has been changed */
6276 Editor::update_region_fade_visibility ()
6278 bool _fade_visibility = _session->config.get_show_region_fades ();
6280 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
6281 AudioTimeAxisView* v = dynamic_cast<AudioTimeAxisView*>(*i);
6283 if (_fade_visibility) {
6284 v->audio_view()->show_all_fades ();
6286 v->audio_view()->hide_all_fades ();
6293 Editor::set_edit_point ()
6296 MusicFrame where (0, 0);
6298 if (!mouse_frame (where.frame, ignored)) {
6304 if (selection->markers.empty()) {
6306 mouse_add_new_marker (where.frame);
6311 Location* loc = find_location_from_marker (selection->markers.front(), ignored);
6314 loc->move_to (where.frame, where.division);
6320 Editor::set_playhead_cursor ()
6322 if (entered_marker) {
6323 _session->request_locate (entered_marker->position(), _session->transport_rolling());
6325 MusicFrame where (0, 0);
6328 if (!mouse_frame (where.frame, ignored)) {
6335 _session->request_locate (where.frame, _session->transport_rolling());
6339 //not sure what this was for; remove it for now.
6340 // if (UIConfiguration::instance().get_follow_edits() && (!_session || !_session->config.get_external_sync())) {
6341 // cancel_time_selection();
6347 Editor::split_region ()
6349 if (_drags->active ()) {
6353 //if a range is selected, separate it
6354 if ( !selection->time.empty()) {
6355 separate_regions_between (selection->time);
6359 //if no range was selected, try to find some regions to split
6360 if (current_mouse_mode() == MouseObject) { //don't try this for Internal Edit, Stretch, Draw, etc.
6362 RegionSelection rs = get_regions_from_selection_and_edit_point ();
6363 const framepos_t pos = get_preferred_edit_position();
6364 const int32_t division = get_grid_music_divisions (0);
6365 MusicFrame where (pos, division);
6371 split_regions_at (where, rs);
6377 Editor::select_next_stripable (bool routes_only)
6379 if (selection->tracks.empty()) {
6380 selection->set (track_views.front());
6384 TimeAxisView* current = selection->tracks.front();
6388 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
6390 if (*i == current) {
6392 if (i != track_views.end()) {
6395 current = (*(track_views.begin()));
6396 //selection->set (*(track_views.begin()));
6403 RouteUI* rui = dynamic_cast<RouteUI *>(current);
6404 valid = rui && rui->route()->active();
6406 valid = 0 != current->stripable ().get();
6409 } while (current->hidden() || !valid);
6411 selection->set (current);
6413 ensure_time_axis_view_is_visible (*current, false);
6417 Editor::select_prev_stripable (bool routes_only)
6419 if (selection->tracks.empty()) {
6420 selection->set (track_views.front());
6424 TimeAxisView* current = selection->tracks.front();
6428 for (TrackViewList::reverse_iterator i = track_views.rbegin(); i != track_views.rend(); ++i) {
6430 if (*i == current) {
6432 if (i != track_views.rend()) {
6435 current = *(track_views.rbegin());
6441 RouteUI* rui = dynamic_cast<RouteUI *>(current);
6442 valid = rui && rui->route()->active();
6444 valid = 0 != current->stripable ().get();
6447 } while (current->hidden() || !valid);
6449 selection->set (current);
6451 ensure_time_axis_view_is_visible (*current, false);
6455 Editor::set_loop_from_selection (bool play)
6457 if (_session == 0) {
6461 framepos_t start, end;
6462 if (!get_selection_extents ( start, end))
6465 set_loop_range (start, end, _("set loop range from selection"));
6468 _session->request_play_loop (true, true);
6473 Editor::set_loop_from_region (bool play)
6475 framepos_t start, end;
6476 if (!get_selection_extents ( start, end))
6479 set_loop_range (start, end, _("set loop range from region"));
6482 _session->request_locate (start, true);
6483 _session->request_play_loop (true);
6488 Editor::set_punch_from_selection ()
6490 if (_session == 0) {
6494 framepos_t start, end;
6495 if (!get_selection_extents ( start, end))
6498 set_punch_range (start, end, _("set punch range from selection"));
6502 Editor::set_auto_punch_range ()
6504 // auto punch in/out button from a single button
6505 // If Punch In is unset, set punch range from playhead to end, enable punch in
6506 // If Punch In is set, the next punch sets Punch Out, unless the playhead has been
6507 // rewound beyond the Punch In marker, in which case that marker will be moved back
6508 // to the current playhead position.
6509 // If punch out is set, it clears the punch range and Punch In/Out buttons
6511 if (_session == 0) {
6515 Location* tpl = transport_punch_location();
6516 framepos_t now = playhead_cursor->current_frame();
6517 framepos_t begin = now;
6518 framepos_t end = _session->current_end_frame();
6520 if (!_session->config.get_punch_in()) {
6521 // First Press - set punch in and create range from here to eternity
6522 set_punch_range (begin, end, _("Auto Punch In"));
6523 _session->config.set_punch_in(true);
6524 } else if (tpl && !_session->config.get_punch_out()) {
6525 // Second press - update end range marker and set punch_out
6526 if (now < tpl->start()) {
6527 // playhead has been rewound - move start back and pretend nothing happened
6529 set_punch_range (begin, end, _("Auto Punch In/Out"));
6531 // normal case for 2nd press - set the punch out
6532 end = playhead_cursor->current_frame ();
6533 set_punch_range (tpl->start(), now, _("Auto Punch In/Out"));
6534 _session->config.set_punch_out(true);
6537 if (_session->config.get_punch_out()) {
6538 _session->config.set_punch_out(false);
6541 if (_session->config.get_punch_in()) {
6542 _session->config.set_punch_in(false);
6547 // third press - unset punch in/out and remove range
6548 _session->locations()->remove(tpl);
6555 Editor::set_session_extents_from_selection ()
6557 if (_session == 0) {
6561 framepos_t start, end;
6562 if (!get_selection_extents ( start, end))
6566 if ((loc = _session->locations()->session_range_location()) == 0) {
6567 _session->set_session_extents (start, end); // this will create a new session range; no need for UNDO
6569 XMLNode &before = loc->get_state();
6571 _session->set_session_extents (start, end);
6573 XMLNode &after = loc->get_state();
6575 begin_reversible_command (_("set session start/end from selection"));
6577 _session->add_command (new MementoCommand<Location>(*loc, &before, &after));
6579 commit_reversible_command ();
6582 _session->set_end_is_free (false);
6586 Editor::set_punch_start_from_edit_point ()
6590 MusicFrame start (0, 0);
6591 framepos_t end = max_framepos;
6593 //use the existing punch end, if any
6594 Location* tpl = transport_punch_location();
6599 if ((_edit_point == EditAtPlayhead) && _session->transport_rolling()) {
6600 start.frame = _session->audible_frame();
6602 start.frame = get_preferred_edit_position();
6605 //snap the selection start/end
6608 //if there's not already a sensible selection endpoint, go "forever"
6609 if (start.frame > end ) {
6613 set_punch_range (start.frame, end, _("set punch start from EP"));
6619 Editor::set_punch_end_from_edit_point ()
6623 framepos_t start = 0;
6624 MusicFrame end (max_framepos, 0);
6626 //use the existing punch start, if any
6627 Location* tpl = transport_punch_location();
6629 start = tpl->start();
6632 if ((_edit_point == EditAtPlayhead) && _session->transport_rolling()) {
6633 end.frame = _session->audible_frame();
6635 end.frame = get_preferred_edit_position();
6638 //snap the selection start/end
6641 set_punch_range (start, end.frame, _("set punch end from EP"));
6647 Editor::set_loop_start_from_edit_point ()
6651 MusicFrame start (0, 0);
6652 framepos_t end = max_framepos;
6654 //use the existing loop end, if any
6655 Location* tpl = transport_loop_location();
6660 if ((_edit_point == EditAtPlayhead) && _session->transport_rolling()) {
6661 start.frame = _session->audible_frame();
6663 start.frame = get_preferred_edit_position();
6666 //snap the selection start/end
6669 //if there's not already a sensible selection endpoint, go "forever"
6670 if (start.frame > end ) {
6674 set_loop_range (start.frame, end, _("set loop start from EP"));
6680 Editor::set_loop_end_from_edit_point ()
6684 framepos_t start = 0;
6685 MusicFrame end (max_framepos, 0);
6687 //use the existing loop start, if any
6688 Location* tpl = transport_loop_location();
6690 start = tpl->start();
6693 if ((_edit_point == EditAtPlayhead) && _session->transport_rolling()) {
6694 end.frame = _session->audible_frame();
6696 end.frame = get_preferred_edit_position();
6699 //snap the selection start/end
6702 set_loop_range (start, end.frame, _("set loop end from EP"));
6707 Editor::set_punch_from_region ()
6709 framepos_t start, end;
6710 if (!get_selection_extents ( start, end))
6713 set_punch_range (start, end, _("set punch range from region"));
6717 Editor::pitch_shift_region ()
6719 RegionSelection rs = get_regions_from_selection_and_entered ();
6721 RegionSelection audio_rs;
6722 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
6723 if (dynamic_cast<AudioRegionView*> (*i)) {
6724 audio_rs.push_back (*i);
6728 if (audio_rs.empty()) {
6732 pitch_shift (audio_rs, 1.2);
6736 Editor::set_tempo_from_region ()
6738 RegionSelection rs = get_regions_from_selection_and_entered ();
6740 if (!_session || rs.empty()) {
6744 RegionView* rv = rs.front();
6746 define_one_bar (rv->region()->position(), rv->region()->last_frame() + 1);
6750 Editor::use_range_as_bar ()
6752 framepos_t start, end;
6753 if (get_edit_op_range (start, end)) {
6754 define_one_bar (start, end);
6759 Editor::define_one_bar (framepos_t start, framepos_t end)
6761 framepos_t length = end - start;
6763 const Meter& m (_session->tempo_map().meter_at_frame (start));
6765 /* length = 1 bar */
6767 /* We're going to deliver a constant tempo here,
6768 so we can use frames per beat to determine length.
6769 now we want frames per beat.
6770 we have frames per bar, and beats per bar, so ...
6773 /* XXXX METER MATH */
6775 double frames_per_beat = length / m.divisions_per_bar();
6777 /* beats per minute = */
6779 double beats_per_minute = (_session->frame_rate() * 60.0) / frames_per_beat;
6781 /* now decide whether to:
6783 (a) set global tempo
6784 (b) add a new tempo marker
6788 const TempoSection& t (_session->tempo_map().tempo_section_at_frame (start));
6790 bool do_global = false;
6792 if ((_session->tempo_map().n_tempos() == 1) && (_session->tempo_map().n_meters() == 1)) {
6794 /* only 1 tempo & 1 meter: ask if the user wants to set the tempo
6795 at the start, or create a new marker
6798 vector<string> options;
6799 options.push_back (_("Cancel"));
6800 options.push_back (_("Add new marker"));
6801 options.push_back (_("Set global tempo"));
6804 _("Define one bar"),
6805 _("Do you want to set the global tempo or add a new tempo marker?"),
6809 c.set_default_response (2);
6825 /* more than 1 tempo and/or meter section already, go ahead do the "usual":
6826 if the marker is at the region starter, change it, otherwise add
6831 begin_reversible_command (_("set tempo from region"));
6832 XMLNode& before (_session->tempo_map().get_state());
6835 _session->tempo_map().change_initial_tempo (beats_per_minute, t.note_type(), t.end_note_types_per_minute());
6836 } else if (t.frame() == start) {
6837 _session->tempo_map().change_existing_tempo_at (start, beats_per_minute, t.note_type(), t.end_note_types_per_minute());
6839 /* constant tempo */
6840 const Tempo tempo (beats_per_minute, t.note_type());
6841 _session->tempo_map().add_tempo (tempo, 0.0, start, AudioTime);
6844 XMLNode& after (_session->tempo_map().get_state());
6846 _session->add_command (new MementoCommand<TempoMap>(_session->tempo_map(), &before, &after));
6847 commit_reversible_command ();
6851 Editor::split_region_at_transients ()
6853 AnalysisFeatureList positions;
6855 RegionSelection rs = get_regions_from_selection_and_entered ();
6857 if (!_session || rs.empty()) {
6861 begin_reversible_command (_("split regions"));
6863 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ) {
6865 RegionSelection::iterator tmp;
6870 boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion> ((*i)->region());
6873 ar->transients (positions);
6874 split_region_at_points ((*i)->region(), positions, true);
6881 commit_reversible_command ();
6886 Editor::split_region_at_points (boost::shared_ptr<Region> r, AnalysisFeatureList& positions, bool can_ferret, bool select_new)
6888 bool use_rhythmic_rodent = false;
6890 boost::shared_ptr<Playlist> pl = r->playlist();
6892 list<boost::shared_ptr<Region> > new_regions;
6898 if (positions.empty()) {
6902 if (positions.size() > 20 && can_ferret) {
6903 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);
6904 MessageDialog msg (msgstr,
6907 Gtk::BUTTONS_OK_CANCEL);
6910 msg.add_button (_("Call for the Ferret!"), RESPONSE_APPLY);
6911 msg.set_secondary_text (_("Press OK to continue with this split operation\nor ask the Ferret dialog to tune the analysis"));
6913 msg.set_secondary_text (_("Press OK to continue with this split operation"));
6916 msg.set_title (_("Excessive split?"));
6919 int response = msg.run();
6925 case RESPONSE_APPLY:
6926 use_rhythmic_rodent = true;
6933 if (use_rhythmic_rodent) {
6934 show_rhythm_ferret ();
6938 AnalysisFeatureList::const_iterator x;
6940 pl->clear_changes ();
6941 pl->clear_owned_changes ();
6943 x = positions.begin();
6945 if (x == positions.end()) {
6950 pl->remove_region (r);
6954 framepos_t rstart = r->first_frame ();
6955 framepos_t rend = r->last_frame ();
6957 while (x != positions.end()) {
6959 /* deal with positons that are out of scope of present region bounds */
6960 if (*x <= rstart || *x > rend) {
6965 /* file start = original start + how far we from the initial position ? */
6967 framepos_t file_start = r->start() + pos;
6969 /* length = next position - current position */
6971 framepos_t len = (*x) - pos - rstart;
6973 /* XXX we do we really want to allow even single-sample regions?
6974 * shouldn't we have some kind of lower limit on region size?
6983 if (RegionFactory::region_name (new_name, r->name())) {
6987 /* do NOT announce new regions 1 by one, just wait till they are all done */
6991 plist.add (ARDOUR::Properties::start, file_start);
6992 plist.add (ARDOUR::Properties::length, len);
6993 plist.add (ARDOUR::Properties::name, new_name);
6994 plist.add (ARDOUR::Properties::layer, 0);
6995 // TODO set transients_offset
6997 boost::shared_ptr<Region> nr = RegionFactory::create (r->sources(), plist, false);
6998 /* because we set annouce to false, manually add the new region to the
7001 RegionFactory::map_add (nr);
7003 pl->add_region (nr, rstart + pos);
7006 new_regions.push_front(nr);
7015 RegionFactory::region_name (new_name, r->name());
7017 /* Add the final region */
7020 plist.add (ARDOUR::Properties::start, r->start() + pos);
7021 plist.add (ARDOUR::Properties::length, r->last_frame() - (r->position() + pos) + 1);
7022 plist.add (ARDOUR::Properties::name, new_name);
7023 plist.add (ARDOUR::Properties::layer, 0);
7025 boost::shared_ptr<Region> nr = RegionFactory::create (r->sources(), plist, false);
7026 /* because we set annouce to false, manually add the new region to the
7029 RegionFactory::map_add (nr);
7030 pl->add_region (nr, r->position() + pos);
7033 new_regions.push_front(nr);
7038 /* We might have removed regions, which alters other regions' layering_index,
7039 so we need to do a recursive diff here.
7041 vector<Command*> cmds;
7043 _session->add_commands (cmds);
7045 _session->add_command (new StatefulDiffCommand (pl));
7049 for (list<boost::shared_ptr<Region> >::iterator i = new_regions.begin(); i != new_regions.end(); ++i){
7050 set_selected_regionview_from_region_list ((*i), Selection::Add);
7056 Editor::place_transient()
7062 RegionSelection rs = get_regions_from_selection_and_edit_point ();
7068 framepos_t where = get_preferred_edit_position();
7070 begin_reversible_command (_("place transient"));
7072 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
7073 (*r)->region()->add_transient(where);
7076 commit_reversible_command ();
7080 Editor::remove_transient(ArdourCanvas::Item* item)
7086 ArdourCanvas::Line* _line = reinterpret_cast<ArdourCanvas::Line*> (item);
7089 AudioRegionView* _arv = reinterpret_cast<AudioRegionView*> (item->get_data ("regionview"));
7090 _arv->remove_transient (*(float*) _line->get_data ("position"));
7094 Editor::snap_regions_to_grid ()
7096 list <boost::shared_ptr<Playlist > > used_playlists;
7098 RegionSelection rs = get_regions_from_selection_and_entered ();
7100 if (!_session || rs.empty()) {
7104 begin_reversible_command (_("snap regions to grid"));
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);
7117 (*r)->region()->clear_changes ();
7119 MusicFrame start ((*r)->region()->first_frame (), 0);
7121 (*r)->region()->set_position (start.frame, start.division);
7122 _session->add_command(new StatefulDiffCommand ((*r)->region()));
7125 while (used_playlists.size() > 0) {
7126 list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
7128 used_playlists.pop_front();
7131 commit_reversible_command ();
7135 Editor::close_region_gaps ()
7137 list <boost::shared_ptr<Playlist > > used_playlists;
7139 RegionSelection rs = get_regions_from_selection_and_entered ();
7141 if (!_session || rs.empty()) {
7145 Dialog dialog (_("Close Region Gaps"));
7148 table.set_spacings (12);
7149 table.set_border_width (12);
7150 Label* l = manage (left_aligned_label (_("Crossfade length")));
7151 table.attach (*l, 0, 1, 0, 1);
7153 SpinButton spin_crossfade (1, 0);
7154 spin_crossfade.set_range (0, 15);
7155 spin_crossfade.set_increments (1, 1);
7156 spin_crossfade.set_value (5);
7157 table.attach (spin_crossfade, 1, 2, 0, 1);
7159 table.attach (*manage (new Label (_("ms"))), 2, 3, 0, 1);
7161 l = manage (left_aligned_label (_("Pull-back length")));
7162 table.attach (*l, 0, 1, 1, 2);
7164 SpinButton spin_pullback (1, 0);
7165 spin_pullback.set_range (0, 100);
7166 spin_pullback.set_increments (1, 1);
7167 spin_pullback.set_value(30);
7168 table.attach (spin_pullback, 1, 2, 1, 2);
7170 table.attach (*manage (new Label (_("ms"))), 2, 3, 1, 2);
7172 dialog.get_vbox()->pack_start (table);
7173 dialog.add_button (Stock::CANCEL, RESPONSE_CANCEL);
7174 dialog.add_button (_("Ok"), RESPONSE_ACCEPT);
7177 if (dialog.run () == RESPONSE_CANCEL) {
7181 framepos_t crossfade_len = spin_crossfade.get_value();
7182 framepos_t pull_back_frames = spin_pullback.get_value();
7184 crossfade_len = lrintf (crossfade_len * _session->frame_rate()/1000);
7185 pull_back_frames = lrintf (pull_back_frames * _session->frame_rate()/1000);
7187 /* Iterate over the region list and make adjacent regions overlap by crossfade_len_ms */
7189 begin_reversible_command (_("close region gaps"));
7192 boost::shared_ptr<Region> last_region;
7194 rs.sort_by_position_and_track();
7196 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
7198 boost::shared_ptr<Playlist> pl = (*r)->region()->playlist();
7200 if (!pl->frozen()) {
7201 /* we haven't seen this playlist before */
7203 /* remember used playlists so we can thaw them later */
7204 used_playlists.push_back(pl);
7208 framepos_t position = (*r)->region()->position();
7210 if (idx == 0 || position < last_region->position()){
7211 last_region = (*r)->region();
7216 (*r)->region()->clear_changes ();
7217 (*r)->region()->trim_front( (position - pull_back_frames));
7219 last_region->clear_changes ();
7220 last_region->trim_end( (position - pull_back_frames + crossfade_len));
7222 _session->add_command (new StatefulDiffCommand ((*r)->region()));
7223 _session->add_command (new StatefulDiffCommand (last_region));
7225 last_region = (*r)->region();
7229 while (used_playlists.size() > 0) {
7230 list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
7232 used_playlists.pop_front();
7235 commit_reversible_command ();
7239 Editor::tab_to_transient (bool forward)
7241 AnalysisFeatureList positions;
7243 RegionSelection rs = get_regions_from_selection_and_entered ();
7249 framepos_t pos = _session->audible_frame ();
7251 if (!selection->tracks.empty()) {
7253 /* don't waste time searching for transients in duplicate playlists.
7256 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
7258 for (TrackViewList::iterator t = ts.begin(); t != ts.end(); ++t) {
7260 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*t);
7263 boost::shared_ptr<Track> tr = rtv->track();
7265 boost::shared_ptr<Playlist> pl = tr->playlist ();
7267 framepos_t result = pl->find_next_transient (pos, forward ? 1 : -1);
7270 positions.push_back (result);
7283 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
7284 (*r)->region()->get_transients (positions);
7288 TransientDetector::cleanup_transients (positions, _session->frame_rate(), 3.0);
7291 AnalysisFeatureList::iterator x;
7293 for (x = positions.begin(); x != positions.end(); ++x) {
7299 if (x != positions.end ()) {
7300 _session->request_locate (*x);
7304 AnalysisFeatureList::reverse_iterator x;
7306 for (x = positions.rbegin(); x != positions.rend(); ++x) {
7312 if (x != positions.rend ()) {
7313 _session->request_locate (*x);
7319 Editor::playhead_forward_to_grid ()
7325 MusicFrame pos (playhead_cursor->current_frame (), 0);
7327 if (pos.frame < max_framepos - 1) {
7329 snap_to_internal (pos, RoundUpAlways, false, true);
7330 _session->request_locate (pos.frame);
7336 Editor::playhead_backward_to_grid ()
7342 MusicFrame pos (playhead_cursor->current_frame (), 0);
7344 if (pos.frame > 2) {
7346 snap_to_internal (pos, RoundDownAlways, false, true);
7347 _session->request_locate (pos.frame);
7352 Editor::set_track_height (Height h)
7354 TrackSelection& ts (selection->tracks);
7356 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
7357 (*x)->set_height_enum (h);
7362 Editor::toggle_tracks_active ()
7364 TrackSelection& ts (selection->tracks);
7366 bool target = false;
7372 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
7373 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*x);
7377 target = !rtv->_route->active();
7380 rtv->_route->set_active (target, this);
7386 Editor::remove_tracks ()
7388 /* this will delete GUI objects that may be the subject of an event
7389 handler in which this method is called. Defer actual deletion to the
7390 next idle callback, when all event handling is finished.
7392 Glib::signal_idle().connect (sigc::mem_fun (*this, &Editor::idle_remove_tracks));
7396 Editor::idle_remove_tracks ()
7398 Session::StateProtector sp (_session);
7400 return false; /* do not call again */
7404 Editor::_remove_tracks ()
7406 TrackSelection& ts (selection->tracks);
7412 vector<string> choices;
7417 const char* trackstr;
7420 vector<boost::shared_ptr<Route> > routes;
7421 vector<boost::shared_ptr<VCA> > vcas;
7422 bool special_bus = false;
7424 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
7425 VCATimeAxisView* vtv = dynamic_cast<VCATimeAxisView*> (*x);
7427 vcas.push_back (vtv->vca());
7431 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*x);
7435 if (rtv->is_track()) {
7440 routes.push_back (rtv->_route);
7442 if (rtv->route()->is_master() || rtv->route()->is_monitor()) {
7447 if (special_bus && !Config->get_allow_special_bus_removal()) {
7448 MessageDialog msg (_("That would be bad news ...."),
7452 msg.set_secondary_text (string_compose (_(
7453 "Removing the master or monitor bus is such a bad idea\n\
7454 that %1 is not going to allow it.\n\
7456 If you really want to do this sort of thing\n\
7457 edit your ardour.rc file to set the\n\
7458 \"allow-special-bus-removal\" option to be \"yes\""), PROGRAM_NAME));
7465 if (ntracks + nbusses + nvcas == 0) {
7471 trackstr = P_("track", "tracks", ntracks);
7472 busstr = P_("bus", "busses", nbusses);
7473 vcastr = P_("VCA", "VCAs", nvcas);
7475 if (ntracks > 0 && nbusses > 0 && nvcas > 0) {
7476 title = _("Remove various strips");
7477 prompt = string_compose (_("Do you really want to remove %1 %2, %3 %4 and %5 %6?"),
7478 ntracks, trackstr, nbusses, busstr, nvcas, vcastr);
7480 else if (ntracks > 0 && nbusses > 0) {
7481 title = string_compose (_("Remove %1 and %2"), trackstr, busstr);
7482 prompt = string_compose (_("Do you really want to remove %1 %2 and %3 %4?"),
7483 ntracks, trackstr, nbusses, busstr);
7485 else if (ntracks > 0 && nvcas > 0) {
7486 title = string_compose (_("Remove %1 and %2"), trackstr, vcastr);
7487 prompt = string_compose (_("Do you really want to remove %1 %2 and %3 %4?"),
7488 ntracks, trackstr, nvcas, vcastr);
7490 else if (nbusses > 0 && nvcas > 0) {
7491 title = string_compose (_("Remove %1 and %2"), busstr, vcastr);
7492 prompt = string_compose (_("Do you really want to remove %1 %2 and %3 %4?"),
7493 nbusses, busstr, nvcas, vcastr);
7495 else if (ntracks > 0) {
7496 title = string_compose (_("Remove %1"), trackstr);
7497 prompt = string_compose (_("Do you really want to remove %1 %2?"),
7500 else if (nbusses > 0) {
7501 title = string_compose (_("Remove %1"), busstr);
7502 prompt = string_compose (_("Do you really want to remove %1 %2?"),
7505 else if (nvcas > 0) {
7506 title = string_compose (_("Remove %1"), vcastr);
7507 prompt = string_compose (_("Do you really want to remove %1 %2?"),
7515 prompt += "\n" + string_compose ("(You may also lose the playlists associated with the %1)", trackstr) + "\n";
7518 prompt += "\n" + string(_("This action cannot be undone, and the session file will be overwritten!"));
7520 choices.push_back (_("No, do nothing."));
7521 if (ntracks + nbusses + nvcas > 1) {
7522 choices.push_back (_("Yes, remove them."));
7524 choices.push_back (_("Yes, remove it."));
7527 Choice prompter (title, prompt, choices);
7529 if (prompter.run () != 1) {
7533 if (current_mixer_strip && routes.size () > 1 && std::find (routes.begin(), routes.end(), current_mixer_strip->route()) != routes.end ()) {
7534 /* Route deletion calls Editor::timeaxisview_deleted() iteratively (for each deleted
7535 * route). If the deleted route is currently displayed in the Editor-Mixer (highly
7536 * likely because deletion requires selection) this will call
7537 * Editor::set_selected_mixer_strip () which is expensive ( MixerStrip::set_route() ).
7538 * It's likewise likely that the route that has just been displayed in the
7539 * Editor-Mixer will be next in line for deletion.
7541 * So simply switch to the master-bus (if present)
7543 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
7544 if ((*i)->stripable ()->is_master ()) {
7545 set_selected_mixer_strip (*(*i));
7552 PresentationInfo::ChangeSuspender cs;
7553 DisplaySuspender ds;
7555 boost::shared_ptr<RouteList> rl (new RouteList);
7556 for (vector<boost::shared_ptr<Route> >::iterator x = routes.begin(); x != routes.end(); ++x) {
7559 _session->remove_routes (rl);
7561 for (vector<boost::shared_ptr<VCA> >::iterator x = vcas.begin(); x != vcas.end(); ++x) {
7562 _session->vca_manager().remove_vca (*x);
7566 /* TrackSelection and RouteList leave scope,
7567 * destructors are called,
7568 * diskstream drops references, save_state is called (again for every track)
7573 Editor::do_insert_time ()
7575 if (selection->tracks.empty()) {
7579 InsertRemoveTimeDialog d (*this);
7580 int response = d.run ();
7582 if (response != RESPONSE_OK) {
7586 if (d.distance() == 0) {
7593 d.intersected_region_action (),
7597 d.move_glued_markers(),
7598 d.move_locked_markers(),
7604 Editor::insert_time (
7605 framepos_t pos, framecnt_t frames, InsertTimeOption opt,
7606 bool all_playlists, bool ignore_music_glue, bool markers_too, bool glued_markers_too, bool locked_markers_too, bool tempo_too
7610 if (Config->get_edit_mode() == Lock) {
7613 bool in_command = false;
7615 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
7617 for (TrackViewList::iterator x = ts.begin(); x != ts.end(); ++x) {
7621 /* don't operate on any playlist more than once, which could
7622 * happen if "all playlists" is enabled, but there is more
7623 * than 1 track using playlists "from" a given track.
7626 set<boost::shared_ptr<Playlist> > pl;
7628 if (all_playlists) {
7629 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*x);
7630 if (rtav && rtav->track ()) {
7631 vector<boost::shared_ptr<Playlist> > all = _session->playlists->playlists_for_track (rtav->track ());
7632 for (vector<boost::shared_ptr<Playlist> >::iterator p = all.begin(); p != all.end(); ++p) {
7637 if ((*x)->playlist ()) {
7638 pl.insert ((*x)->playlist ());
7642 for (set<boost::shared_ptr<Playlist> >::iterator i = pl.begin(); i != pl.end(); ++i) {
7644 (*i)->clear_changes ();
7645 (*i)->clear_owned_changes ();
7648 begin_reversible_command (_("insert time"));
7652 if (opt == SplitIntersected) {
7653 /* non musical split */
7654 (*i)->split (MusicFrame (pos, 0));
7657 (*i)->shift (pos, frames, (opt == MoveIntersected), ignore_music_glue);
7659 vector<Command*> cmds;
7661 _session->add_commands (cmds);
7663 _session->add_command (new StatefulDiffCommand (*i));
7667 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*x);
7670 begin_reversible_command (_("insert time"));
7673 rtav->route ()->shift (pos, frames);
7680 const int32_t divisions = get_grid_music_divisions (0);
7681 XMLNode& before (_session->locations()->get_state());
7682 Locations::LocationList copy (_session->locations()->list());
7684 for (Locations::LocationList::iterator i = copy.begin(); i != copy.end(); ++i) {
7686 Locations::LocationList::const_iterator tmp;
7688 if ((*i)->position_lock_style() == AudioTime || glued_markers_too) {
7689 bool const was_locked = (*i)->locked ();
7690 if (locked_markers_too) {
7694 if ((*i)->start() >= pos) {
7695 // move end first, in case we're moving by more than the length of the range
7696 if (!(*i)->is_mark()) {
7697 (*i)->set_end ((*i)->end() + frames, false, true, divisions);
7699 (*i)->set_start ((*i)->start() + frames, false, true, divisions);
7711 begin_reversible_command (_("insert time"));
7714 XMLNode& after (_session->locations()->get_state());
7715 _session->add_command (new MementoCommand<Locations>(*_session->locations(), &before, &after));
7721 begin_reversible_command (_("insert time"));
7724 XMLNode& before (_session->tempo_map().get_state());
7725 _session->tempo_map().insert_time (pos, frames);
7726 XMLNode& after (_session->tempo_map().get_state());
7727 _session->add_command (new MementoCommand<TempoMap>(_session->tempo_map(), &before, &after));
7731 commit_reversible_command ();
7736 Editor::do_remove_time ()
7738 if (selection->tracks.empty()) {
7742 InsertRemoveTimeDialog d (*this, true);
7744 int response = d.run ();
7746 if (response != RESPONSE_OK) {
7750 framecnt_t distance = d.distance();
7752 if (distance == 0) {
7762 d.move_glued_markers(),
7763 d.move_locked_markers(),
7769 Editor::remove_time (framepos_t pos, framecnt_t frames, InsertTimeOption opt,
7770 bool ignore_music_glue, bool markers_too, bool glued_markers_too, bool locked_markers_too, bool tempo_too)
7772 if (Config->get_edit_mode() == Lock) {
7773 error << (_("Cannot insert or delete time when in Lock edit.")) << endmsg;
7776 bool in_command = false;
7778 for (TrackSelection::iterator x = selection->tracks.begin(); x != selection->tracks.end(); ++x) {
7780 boost::shared_ptr<Playlist> pl = (*x)->playlist();
7784 XMLNode &before = pl->get_state();
7787 begin_reversible_command (_("remove time"));
7791 std::list<AudioRange> rl;
7792 AudioRange ar(pos, pos+frames, 0);
7795 pl->shift (pos, -frames, true, ignore_music_glue);
7797 XMLNode &after = pl->get_state();
7799 _session->add_command (new MementoCommand<Playlist> (*pl, &before, &after));
7803 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*x);
7806 begin_reversible_command (_("remove time"));
7809 rtav->route ()->shift (pos, -frames);
7813 const int32_t divisions = get_grid_music_divisions (0);
7814 std::list<Location*> loc_kill_list;
7819 XMLNode& before (_session->locations()->get_state());
7820 Locations::LocationList copy (_session->locations()->list());
7822 for (Locations::LocationList::iterator i = copy.begin(); i != copy.end(); ++i) {
7823 if ((*i)->position_lock_style() == AudioTime || glued_markers_too) {
7825 bool const was_locked = (*i)->locked ();
7826 if (locked_markers_too) {
7830 if (!(*i)->is_mark()) { // it's a range; have to handle both start and end
7831 if ((*i)->end() >= pos
7832 && (*i)->end() < pos+frames
7833 && (*i)->start() >= pos
7834 && (*i)->end() < pos+frames) { // range is completely enclosed; kill it
7836 loc_kill_list.push_back(*i);
7837 } else { // only start or end is included, try to do the right thing
7838 // move start before moving end, to avoid trying to move the end to before the start
7839 // if we're removing more time than the length of the range
7840 if ((*i)->start() >= pos && (*i)->start() < pos+frames) {
7841 // start is within cut
7842 (*i)->set_start (pos, false, true,divisions); // bring the start marker to the beginning of the cut
7844 } else if ((*i)->start() >= pos+frames) {
7845 // start (and thus entire range) lies beyond end of cut
7846 (*i)->set_start ((*i)->start() - frames, false, true, divisions); // slip the start marker back
7849 if ((*i)->end() >= pos && (*i)->end() < pos+frames) {
7850 // end is inside cut
7851 (*i)->set_end (pos, false, true, divisions); // bring the end to the cut
7853 } else if ((*i)->end() >= pos+frames) {
7854 // end is beyond end of cut
7855 (*i)->set_end ((*i)->end() - frames, false, true, divisions); // slip the end marker back
7860 } else if ((*i)->start() >= pos && (*i)->start() < pos+frames ) {
7861 loc_kill_list.push_back(*i);
7863 } else if ((*i)->start() >= pos) {
7864 (*i)->set_start ((*i)->start() -frames, false, true, divisions);
7874 for (list<Location*>::iterator i = loc_kill_list.begin(); i != loc_kill_list.end(); ++i) {
7875 _session->locations()->remove( *i );
7880 begin_reversible_command (_("remove time"));
7883 XMLNode& after (_session->locations()->get_state());
7884 _session->add_command (new MementoCommand<Locations>(*_session->locations(), &before, &after));
7889 XMLNode& before (_session->tempo_map().get_state());
7891 if (_session->tempo_map().remove_time (pos, frames) ) {
7893 begin_reversible_command (_("remove time"));
7896 XMLNode& after (_session->tempo_map().get_state());
7897 _session->add_command (new MementoCommand<TempoMap>(_session->tempo_map(), &before, &after));
7902 commit_reversible_command ();
7907 Editor::fit_selection ()
7909 if (!selection->tracks.empty()) {
7910 fit_tracks (selection->tracks);
7914 /* no selected tracks - use tracks with selected regions */
7916 if (!selection->regions.empty()) {
7917 for (RegionSelection::iterator r = selection->regions.begin(); r != selection->regions.end(); ++r) {
7918 tvl.push_back (&(*r)->get_time_axis_view ());
7924 } else if (internal_editing()) {
7925 /* no selected tracks, or regions, but in internal edit mode, so follow the mouse and use
7928 if (entered_track) {
7929 tvl.push_back (entered_track);
7937 Editor::fit_tracks (TrackViewList & tracks)
7939 if (tracks.empty()) {
7943 uint32_t child_heights = 0;
7944 int visible_tracks = 0;
7946 for (TrackSelection::iterator t = tracks.begin(); t != tracks.end(); ++t) {
7948 if (!(*t)->marked_for_display()) {
7952 child_heights += (*t)->effective_height() - (*t)->current_height();
7956 /* compute the per-track height from:
7958 * total canvas visible height
7959 * - height that will be taken by visible children of selected tracks
7960 * - height of the ruler/hscroll area
7962 uint32_t h = (uint32_t) floor ((trackviews_height() - child_heights) / visible_tracks);
7963 double first_y_pos = DBL_MAX;
7965 if (h < TimeAxisView::preset_height (HeightSmall)) {
7966 MessageDialog msg (_("There are too many tracks to fit in the current window"));
7967 /* too small to be displayed */
7971 undo_visual_stack.push_back (current_visual_state (true));
7972 PBD::Unwinder<bool> nsv (no_save_visual, true);
7974 /* build a list of all tracks, including children */
7977 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
7979 TimeAxisView::Children c = (*i)->get_child_list ();
7980 for (TimeAxisView::Children::iterator j = c.begin(); j != c.end(); ++j) {
7981 all.push_back (j->get());
7986 // find selection range.
7987 // if someone knows how to user TrackViewList::iterator for this
7989 int selected_top = -1;
7990 int selected_bottom = -1;
7992 for (TrackViewList::iterator t = all.begin(); t != all.end(); ++t, ++i) {
7993 if ((*t)->marked_for_display ()) {
7994 if (tracks.contains(*t)) {
7995 if (selected_top == -1) {
7998 selected_bottom = i;
8004 for (TrackViewList::iterator t = all.begin(); t != all.end(); ++t, ++i) {
8005 if ((*t)->marked_for_display ()) {
8006 if (tracks.contains(*t)) {
8007 (*t)->set_height (h);
8008 first_y_pos = std::min ((*t)->y_position (), first_y_pos);
8010 if (i > selected_top && i < selected_bottom) {
8011 hide_track_in_display (*t);
8018 set the controls_layout height now, because waiting for its size
8019 request signal handler will cause the vertical adjustment setting to fail
8022 controls_layout.property_height () = _full_canvas_height;
8023 vertical_adjustment.set_value (first_y_pos);
8025 redo_visual_stack.push_back (current_visual_state (true));
8027 visible_tracks_selector.set_text (_("Sel"));
8031 Editor::save_visual_state (uint32_t n)
8033 while (visual_states.size() <= n) {
8034 visual_states.push_back (0);
8037 if (visual_states[n] != 0) {
8038 delete visual_states[n];
8041 visual_states[n] = current_visual_state (true);
8046 Editor::goto_visual_state (uint32_t n)
8048 if (visual_states.size() <= n) {
8052 if (visual_states[n] == 0) {
8056 use_visual_state (*visual_states[n]);
8060 Editor::start_visual_state_op (uint32_t n)
8062 save_visual_state (n);
8064 PopUp* pup = new PopUp (WIN_POS_MOUSE, 1000, true);
8066 snprintf (buf, sizeof (buf), _("Saved view %u"), n+1);
8067 pup->set_text (buf);
8072 Editor::cancel_visual_state_op (uint32_t n)
8074 goto_visual_state (n);
8078 Editor::toggle_region_mute ()
8080 if (_ignore_region_action) {
8084 RegionSelection rs = get_regions_from_selection_and_entered ();
8090 if (rs.size() > 1) {
8091 begin_reversible_command (_("mute regions"));
8093 begin_reversible_command (_("mute region"));
8096 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
8098 (*i)->region()->playlist()->clear_changes ();
8099 (*i)->region()->set_muted (!(*i)->region()->muted ());
8100 _session->add_command (new StatefulDiffCommand ((*i)->region()));
8104 commit_reversible_command ();
8108 Editor::combine_regions ()
8110 /* foreach track with selected regions, take all selected regions
8111 and join them into a new region containing the subregions (as a
8115 typedef set<RouteTimeAxisView*> RTVS;
8118 if (selection->regions.empty()) {
8122 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
8123 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(&(*i)->get_time_axis_view());
8126 tracks.insert (rtv);
8130 begin_reversible_command (_("combine regions"));
8132 vector<RegionView*> new_selection;
8134 for (RTVS::iterator i = tracks.begin(); i != tracks.end(); ++i) {
8137 if ((rv = (*i)->combine_regions ()) != 0) {
8138 new_selection.push_back (rv);
8142 selection->clear_regions ();
8143 for (vector<RegionView*>::iterator i = new_selection.begin(); i != new_selection.end(); ++i) {
8144 selection->add (*i);
8147 commit_reversible_command ();
8151 Editor::uncombine_regions ()
8153 typedef set<RouteTimeAxisView*> RTVS;
8156 if (selection->regions.empty()) {
8160 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
8161 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(&(*i)->get_time_axis_view());
8164 tracks.insert (rtv);
8168 begin_reversible_command (_("uncombine regions"));
8170 for (RTVS::iterator i = tracks.begin(); i != tracks.end(); ++i) {
8171 (*i)->uncombine_regions ();
8174 commit_reversible_command ();
8178 Editor::toggle_midi_input_active (bool flip_others)
8181 boost::shared_ptr<RouteList> rl (new RouteList);
8183 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
8184 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
8190 boost::shared_ptr<MidiTrack> mt = rtav->midi_track();
8193 rl->push_back (rtav->route());
8194 onoff = !mt->input_active();
8198 _session->set_exclusive_input_active (rl, onoff, flip_others);
8201 static bool ok_fine (GdkEventAny*) { return true; }
8207 lock_dialog = new Gtk::Dialog (string_compose (_("%1: Locked"), PROGRAM_NAME), true);
8209 Gtk::Image* padlock = manage (new Gtk::Image (ARDOUR_UI_UTILS::get_icon ("padlock_closed")));
8210 lock_dialog->get_vbox()->pack_start (*padlock);
8211 lock_dialog->signal_delete_event ().connect (sigc::ptr_fun (ok_fine));
8213 ArdourButton* b = manage (new ArdourButton);
8214 b->set_name ("lock button");
8215 b->set_text (_("Click to unlock"));
8216 b->signal_clicked.connect (sigc::mem_fun (*this, &Editor::unlock));
8217 lock_dialog->get_vbox()->pack_start (*b);
8219 lock_dialog->get_vbox()->show_all ();
8220 lock_dialog->set_size_request (200, 200);
8223 delete _main_menu_disabler;
8224 _main_menu_disabler = new MainMenuDisabler;
8226 lock_dialog->present ();
8228 lock_dialog->get_window()->set_decorations (Gdk::WMDecoration (0));
8234 lock_dialog->hide ();
8236 delete _main_menu_disabler;
8237 _main_menu_disabler = 0;
8239 if (UIConfiguration::instance().get_lock_gui_after_seconds()) {
8240 start_lock_event_timing ();
8245 Editor::bring_in_callback (Gtk::Label* label, uint32_t n, uint32_t total, string name)
8247 Gtkmm2ext::UI::instance()->call_slot (invalidator (*this), boost::bind (&Editor::update_bring_in_message, this, label, n, total, name));
8251 Editor::update_bring_in_message (Gtk::Label* label, uint32_t n, uint32_t total, string name)
8253 Timers::TimerSuspender t;
8254 label->set_text (string_compose ("Copying %1, %2 of %3", name, n, total));
8255 Gtkmm2ext::UI::instance()->flush_pending (1);
8259 Editor::bring_all_sources_into_session ()
8266 ArdourDialog w (_("Moving embedded files into session folder"));
8267 w.get_vbox()->pack_start (msg);
8270 /* flush all pending GUI events because we're about to start copying
8274 Timers::TimerSuspender t;
8275 Gtkmm2ext::UI::instance()->flush_pending (3);
8279 _session->bring_all_sources_into_session (boost::bind (&Editor::bring_in_callback, this, &msg, _1, _2, _3));