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 // ToDo: encapsulate all of this into something like editor::get_session_extents() or editor::leftmost(), rightmost()
1794 //ToDo: also incorporate automation regions (in case the session has no audio/midi but is just used for automating plugins or the like)
1796 //calculate the extents of all regions in every playlist
1797 framecnt_t session_extent_start = 0;
1798 framecnt_t session_extent_end = 0;
1800 boost::shared_ptr<RouteList> rl = _session->get_routes();
1801 for (RouteList::iterator r = rl->begin(); r != rl->end(); ++r) {
1802 boost::shared_ptr<Track> tr = boost::dynamic_pointer_cast<Track> (*r);
1804 boost::shared_ptr<Playlist> pl = tr->playlist();
1806 pair<framepos_t, framepos_t> e;
1807 e = pl->get_extent();
1808 if (e.first < session_extent_start) {
1809 session_extent_start = e.first;
1811 if (e.second > session_extent_end) {
1812 session_extent_end = e.second;
1818 framecnt_t session_extents = session_extent_end - session_extent_start;
1820 //in a session with no regions, use the start/end markers to set max zoom
1821 framecnt_t const session_length = _session->current_end_frame() - _session->current_start_frame ();
1822 if ( session_length > session_extents )
1823 session_extents = session_length;
1825 //in a session with no regions or start/end markers, use 2 minutes to set max zoom
1826 framecnt_t const min_length = _session->nominal_frame_rate()*60*2;
1827 if ( min_length > session_extents )
1828 session_extents = min_length;
1830 //convert to samples-per-pixel and limit our zoom to this value
1831 framecnt_t session_extents_pp = session_extents / _visible_canvas_width;
1832 if (nspp > session_extents_pp)
1833 nspp = session_extents_pp;
1836 temporal_zoom (nspp);
1840 Editor::temporal_zoom (framecnt_t fpp)
1846 framepos_t current_page = current_page_samples();
1847 framepos_t current_leftmost = leftmost_frame;
1848 framepos_t current_rightmost;
1849 framepos_t current_center;
1850 framepos_t new_page_size;
1851 framepos_t half_page_size;
1852 framepos_t leftmost_after_zoom = 0;
1854 bool in_track_canvas;
1855 bool use_mouse_frame = true;
1859 if (fpp == samples_per_pixel) {
1863 // Imposing an arbitrary limit to zoom out as too much zoom out produces
1864 // segfaults for lack of memory. If somebody decides this is not high enough I
1865 // believe it can be raisen to higher values but some limit must be in place.
1867 // This constant represents 1 day @ 48kHz on a 1600 pixel wide display
1868 // all of which is used for the editor track displays. The whole day
1869 // would be 4147200000 samples, so 2592000 samples per pixel.
1871 nfpp = min (fpp, (framecnt_t) 2592000);
1872 nfpp = max ((framecnt_t) 1, nfpp);
1874 new_page_size = (framepos_t) floor (_visible_canvas_width * nfpp);
1875 half_page_size = new_page_size / 2;
1877 switch (zoom_focus) {
1879 leftmost_after_zoom = current_leftmost;
1882 case ZoomFocusRight:
1883 current_rightmost = leftmost_frame + current_page;
1884 if (current_rightmost < new_page_size) {
1885 leftmost_after_zoom = 0;
1887 leftmost_after_zoom = current_rightmost - new_page_size;
1891 case ZoomFocusCenter:
1892 current_center = current_leftmost + (current_page/2);
1893 if (current_center < half_page_size) {
1894 leftmost_after_zoom = 0;
1896 leftmost_after_zoom = current_center - half_page_size;
1900 case ZoomFocusPlayhead:
1901 /* centre playhead */
1902 l = playhead_cursor->current_frame () - (new_page_size * 0.5);
1905 leftmost_after_zoom = 0;
1906 } else if (l > max_framepos) {
1907 leftmost_after_zoom = max_framepos - new_page_size;
1909 leftmost_after_zoom = (framepos_t) l;
1913 case ZoomFocusMouse:
1914 /* try to keep the mouse over the same point in the display */
1916 if (_drags->active()) {
1917 where = _drags->current_pointer_frame ();
1918 } else if (!mouse_frame (where, in_track_canvas)) {
1919 use_mouse_frame = false;
1922 if (use_mouse_frame) {
1923 l = - ((new_page_size * ((where - current_leftmost)/(double)current_page)) - where);
1926 leftmost_after_zoom = 0;
1927 } else if (l > max_framepos) {
1928 leftmost_after_zoom = max_framepos - new_page_size;
1930 leftmost_after_zoom = (framepos_t) l;
1933 /* use playhead instead */
1934 where = playhead_cursor->current_frame ();
1936 if (where < half_page_size) {
1937 leftmost_after_zoom = 0;
1939 leftmost_after_zoom = where - half_page_size;
1945 /* try to keep the edit point in the same place */
1946 where = get_preferred_edit_position ();
1950 double l = - ((new_page_size * ((where - current_leftmost)/(double)current_page)) - where);
1953 leftmost_after_zoom = 0;
1954 } else if (l > max_framepos) {
1955 leftmost_after_zoom = max_framepos - new_page_size;
1957 leftmost_after_zoom = (framepos_t) l;
1961 /* edit point not defined */
1968 // leftmost_after_zoom = min (leftmost_after_zoom, _session->current_end_frame());
1970 reposition_and_zoom (leftmost_after_zoom, nfpp);
1974 Editor::calc_extra_zoom_edges(framepos_t &start, framepos_t &end)
1976 /* this func helps make sure we leave a little space
1977 at each end of the editor so that the zoom doesn't fit the region
1978 precisely to the screen.
1981 GdkScreen* screen = gdk_screen_get_default ();
1982 const gint pixwidth = gdk_screen_get_width (screen);
1983 const gint mmwidth = gdk_screen_get_width_mm (screen);
1984 const double pix_per_mm = (double) pixwidth/ (double) mmwidth;
1985 const double one_centimeter_in_pixels = pix_per_mm * 10.0;
1987 const framepos_t range = end - start;
1988 const framecnt_t new_fpp = (framecnt_t) ceil ((double) range / (double) _visible_canvas_width);
1989 const framepos_t extra_samples = (framepos_t) floor (one_centimeter_in_pixels * new_fpp);
1991 if (start > extra_samples) {
1992 start -= extra_samples;
1997 if (max_framepos - extra_samples > end) {
1998 end += extra_samples;
2005 Editor::get_selection_extents (framepos_t &start, framepos_t &end) const
2007 start = max_framepos;
2011 //ToDo: if notes are selected, set extents to that selection
2013 //ToDo: if control points are selected, set extents to that selection
2015 if ( !selection->regions.empty() ) {
2016 RegionSelection rs = get_regions_from_selection_and_entered ();
2018 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
2020 if ((*i)->region()->position() < start) {
2021 start = (*i)->region()->position();
2024 if ((*i)->region()->last_frame() + 1 > end) {
2025 end = (*i)->region()->last_frame() + 1;
2029 } else if (!selection->time.empty()) {
2030 start = selection->time.start();
2031 end = selection->time.end_frame();
2033 ret = false; //no selection found
2036 if ((start == 0 && end == 0) || end < start) {
2045 Editor::temporal_zoom_selection (Editing::ZoomAxis axes)
2047 if (!selection) return;
2049 //ToDo: if notes are selected, zoom to that
2051 //ToDo: if control points are selected, zoom to that
2053 if (axes == Horizontal || axes == Both) {
2055 framepos_t start, end;
2056 if (get_selection_extents (start, end)) {
2057 calc_extra_zoom_edges (start, end);
2058 temporal_zoom_by_frame (start, end);
2062 if (axes == Vertical || axes == Both) {
2068 Editor::temporal_zoom_session ()
2070 ENSURE_GUI_THREAD (*this, &Editor::temporal_zoom_session)
2073 framecnt_t start = _session->current_start_frame();
2074 framecnt_t end = _session->current_end_frame();
2076 if (_session->actively_recording () ) {
2077 framepos_t cur = playhead_cursor->current_frame ();
2079 /* recording beyond the end marker; zoom out
2080 * by 5 seconds more so that if 'follow
2081 * playhead' is active we don't immediately
2084 end = cur + _session->frame_rate() * 5;
2088 if ((start == 0 && end == 0) || end < start) {
2092 calc_extra_zoom_edges(start, end);
2094 temporal_zoom_by_frame (start, end);
2099 Editor::temporal_zoom_by_frame (framepos_t start, framepos_t end)
2101 if (!_session) return;
2103 if ((start == 0 && end == 0) || end < start) {
2107 framepos_t range = end - start;
2109 const framecnt_t new_fpp = (framecnt_t) ceil ((double) range / (double) _visible_canvas_width);
2111 framepos_t new_page = range;
2112 framepos_t middle = (framepos_t) floor ((double) start + ((double) range / 2.0f));
2113 framepos_t new_leftmost = (framepos_t) floor ((double) middle - ((double) new_page / 2.0f));
2115 if (new_leftmost > middle) {
2119 if (new_leftmost < 0) {
2123 reposition_and_zoom (new_leftmost, new_fpp);
2127 Editor::temporal_zoom_to_frame (bool coarser, framepos_t frame)
2133 framecnt_t range_before = frame - leftmost_frame;
2137 if (samples_per_pixel <= 1) {
2140 new_spp = samples_per_pixel + (samples_per_pixel/2);
2142 range_before += range_before/2;
2144 if (samples_per_pixel >= 1) {
2145 new_spp = samples_per_pixel - (samples_per_pixel/2);
2147 /* could bail out here since we cannot zoom any finer,
2148 but leave that to the equality test below
2150 new_spp = samples_per_pixel;
2153 range_before -= range_before/2;
2156 if (new_spp == samples_per_pixel) {
2160 /* zoom focus is automatically taken as @param frame when this
2164 framepos_t new_leftmost = frame - (framepos_t)range_before;
2166 if (new_leftmost > frame) {
2170 if (new_leftmost < 0) {
2174 reposition_and_zoom (new_leftmost, new_spp);
2179 Editor::choose_new_marker_name(string &name) {
2181 if (!UIConfiguration::instance().get_name_new_markers()) {
2182 /* don't prompt user for a new name */
2186 Prompter dialog (true);
2188 dialog.set_prompt (_("New Name:"));
2190 dialog.set_title (_("New Location Marker"));
2192 dialog.set_name ("MarkNameWindow");
2193 dialog.set_size_request (250, -1);
2194 dialog.set_position (Gtk::WIN_POS_MOUSE);
2196 dialog.add_button (Stock::OK, RESPONSE_ACCEPT);
2197 dialog.set_initial_text (name);
2201 switch (dialog.run ()) {
2202 case RESPONSE_ACCEPT:
2208 dialog.get_result(name);
2215 Editor::add_location_from_selection ()
2219 if (selection->time.empty()) {
2223 if (_session == 0 || clicked_axisview == 0) {
2227 framepos_t start = selection->time[clicked_selection].start;
2228 framepos_t end = selection->time[clicked_selection].end;
2230 _session->locations()->next_available_name(rangename,"selection");
2231 Location *location = new Location (*_session, start, end, rangename, Location::IsRangeMarker, get_grid_music_divisions(0));
2233 begin_reversible_command (_("add marker"));
2235 XMLNode &before = _session->locations()->get_state();
2236 _session->locations()->add (location, true);
2237 XMLNode &after = _session->locations()->get_state();
2238 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2240 commit_reversible_command ();
2244 Editor::add_location_mark (framepos_t where)
2248 select_new_marker = true;
2250 _session->locations()->next_available_name(markername,"mark");
2251 if (!choose_new_marker_name(markername)) {
2254 Location *location = new Location (*_session, where, where, markername, Location::IsMark, get_grid_music_divisions (0));
2255 begin_reversible_command (_("add marker"));
2257 XMLNode &before = _session->locations()->get_state();
2258 _session->locations()->add (location, true);
2259 XMLNode &after = _session->locations()->get_state();
2260 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2262 commit_reversible_command ();
2266 Editor::set_session_start_from_playhead ()
2272 if ((loc = _session->locations()->session_range_location()) == 0) { //should never happen
2273 _session->set_session_extents ( _session->audible_frame(), _session->audible_frame() );
2275 XMLNode &before = loc->get_state();
2277 _session->set_session_extents ( _session->audible_frame(), loc->end() );
2279 XMLNode &after = loc->get_state();
2281 begin_reversible_command (_("Set session start"));
2283 _session->add_command (new MementoCommand<Location>(*loc, &before, &after));
2285 commit_reversible_command ();
2290 Editor::set_session_end_from_playhead ()
2296 if ((loc = _session->locations()->session_range_location()) == 0) { //should never happen
2297 _session->set_session_extents ( _session->audible_frame(), _session->audible_frame() );
2299 XMLNode &before = loc->get_state();
2301 _session->set_session_extents ( loc->start(), _session->audible_frame() );
2303 XMLNode &after = loc->get_state();
2305 begin_reversible_command (_("Set session start"));
2307 _session->add_command (new MementoCommand<Location>(*loc, &before, &after));
2309 commit_reversible_command ();
2312 _session->set_end_is_free (false);
2317 Editor::toggle_location_at_playhead_cursor ()
2319 if (!do_remove_location_at_playhead_cursor())
2321 add_location_from_playhead_cursor();
2326 Editor::add_location_from_playhead_cursor ()
2328 add_location_mark (_session->audible_frame());
2332 Editor::do_remove_location_at_playhead_cursor ()
2334 bool removed = false;
2337 XMLNode &before = _session->locations()->get_state();
2339 //find location(s) at this time
2340 Locations::LocationList locs;
2341 _session->locations()->find_all_between (_session->audible_frame(), _session->audible_frame()+1, locs, Location::Flags(0));
2342 for (Locations::LocationList::iterator i = locs.begin(); i != locs.end(); ++i) {
2343 if ((*i)->is_mark()) {
2344 _session->locations()->remove (*i);
2351 begin_reversible_command (_("remove marker"));
2352 XMLNode &after = _session->locations()->get_state();
2353 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2354 commit_reversible_command ();
2361 Editor::remove_location_at_playhead_cursor ()
2363 do_remove_location_at_playhead_cursor ();
2366 /** Add a range marker around each selected region */
2368 Editor::add_locations_from_region ()
2370 RegionSelection rs = get_regions_from_selection_and_entered ();
2375 bool commit = false;
2377 XMLNode &before = _session->locations()->get_state();
2379 for (RegionSelection::iterator i = rs.begin (); i != rs.end (); ++i) {
2381 boost::shared_ptr<Region> region = (*i)->region ();
2383 Location *location = new Location (*_session, region->position(), region->last_frame(), region->name(), Location::IsRangeMarker, 0);
2385 _session->locations()->add (location, true);
2390 begin_reversible_command (selection->regions.size () > 1 ? _("add markers") : _("add marker"));
2391 XMLNode &after = _session->locations()->get_state();
2392 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2393 commit_reversible_command ();
2397 /** Add a single range marker around all selected regions */
2399 Editor::add_location_from_region ()
2401 RegionSelection rs = get_regions_from_selection_and_entered ();
2407 XMLNode &before = _session->locations()->get_state();
2411 if (rs.size() > 1) {
2412 _session->locations()->next_available_name(markername, "regions");
2414 RegionView* rv = *(rs.begin());
2415 boost::shared_ptr<Region> region = rv->region();
2416 markername = region->name();
2419 if (!choose_new_marker_name(markername)) {
2423 // single range spanning all selected
2424 Location *location = new Location (*_session, selection->regions.start(), selection->regions.end_frame(), markername, Location::IsRangeMarker, 0);
2425 _session->locations()->add (location, true);
2427 begin_reversible_command (_("add marker"));
2428 XMLNode &after = _session->locations()->get_state();
2429 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2430 commit_reversible_command ();
2436 Editor::jump_forward_to_mark ()
2442 framepos_t pos = _session->locations()->first_mark_after (playhead_cursor->current_frame());
2448 _session->request_locate (pos, _session->transport_rolling());
2452 Editor::jump_backward_to_mark ()
2458 framepos_t pos = _session->locations()->first_mark_before (playhead_cursor->current_frame());
2460 //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...
2461 if ( _session->transport_rolling() ) {
2462 if ( (playhead_cursor->current_frame() - pos) < _session->frame_rate()/2 ) {
2463 framepos_t prior = _session->locations()->first_mark_before ( pos );
2472 _session->request_locate (pos, _session->transport_rolling());
2478 framepos_t const pos = _session->audible_frame ();
2481 _session->locations()->next_available_name (markername, "mark");
2483 if (!choose_new_marker_name (markername)) {
2487 _session->locations()->add (new Location (*_session, pos, 0, markername, Location::IsMark, 0), true);
2491 Editor::clear_markers ()
2494 begin_reversible_command (_("clear markers"));
2496 XMLNode &before = _session->locations()->get_state();
2497 _session->locations()->clear_markers ();
2498 XMLNode &after = _session->locations()->get_state();
2499 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2501 commit_reversible_command ();
2506 Editor::clear_ranges ()
2509 begin_reversible_command (_("clear ranges"));
2511 XMLNode &before = _session->locations()->get_state();
2513 _session->locations()->clear_ranges ();
2515 XMLNode &after = _session->locations()->get_state();
2516 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2518 commit_reversible_command ();
2523 Editor::clear_locations ()
2525 begin_reversible_command (_("clear locations"));
2527 XMLNode &before = _session->locations()->get_state();
2528 _session->locations()->clear ();
2529 XMLNode &after = _session->locations()->get_state();
2530 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2532 commit_reversible_command ();
2536 Editor::unhide_markers ()
2538 for (LocationMarkerMap::iterator i = location_markers.begin(); i != location_markers.end(); ++i) {
2539 Location *l = (*i).first;
2540 if (l->is_hidden() && l->is_mark()) {
2541 l->set_hidden(false, this);
2547 Editor::unhide_ranges ()
2549 for (LocationMarkerMap::iterator i = location_markers.begin(); i != location_markers.end(); ++i) {
2550 Location *l = (*i).first;
2551 if (l->is_hidden() && l->is_range_marker()) {
2552 l->set_hidden(false, this);
2557 /* INSERT/REPLACE */
2560 Editor::insert_region_list_selection (float times)
2562 RouteTimeAxisView *tv = 0;
2563 boost::shared_ptr<Playlist> playlist;
2565 if (clicked_routeview != 0) {
2566 tv = clicked_routeview;
2567 } else if (!selection->tracks.empty()) {
2568 if ((tv = dynamic_cast<RouteTimeAxisView*>(selection->tracks.front())) == 0) {
2571 } else if (entered_track != 0) {
2572 if ((tv = dynamic_cast<RouteTimeAxisView*>(entered_track)) == 0) {
2579 if ((playlist = tv->playlist()) == 0) {
2583 boost::shared_ptr<Region> region = _regions->get_single_selection ();
2588 begin_reversible_command (_("insert region"));
2589 playlist->clear_changes ();
2590 playlist->add_region ((RegionFactory::create (region, true)), get_preferred_edit_position(), times);
2591 if (Config->get_edit_mode() == Ripple)
2592 playlist->ripple (get_preferred_edit_position(), region->length() * times, boost::shared_ptr<Region>());
2594 _session->add_command(new StatefulDiffCommand (playlist));
2595 commit_reversible_command ();
2598 /* BUILT-IN EFFECTS */
2601 Editor::reverse_selection ()
2606 /* GAIN ENVELOPE EDITING */
2609 Editor::edit_envelope ()
2616 Editor::transition_to_rolling (bool fwd)
2622 if (_session->config.get_external_sync()) {
2623 switch (Config->get_sync_source()) {
2627 /* transport controlled by the master */
2632 if (_session->is_auditioning()) {
2633 _session->cancel_audition ();
2637 _session->request_transport_speed (fwd ? 1.0f : -1.0f);
2641 Editor::play_from_start ()
2643 _session->request_locate (_session->current_start_frame(), true);
2647 Editor::play_from_edit_point ()
2649 _session->request_locate (get_preferred_edit_position(), true);
2653 Editor::play_from_edit_point_and_return ()
2655 framepos_t start_frame;
2656 framepos_t return_frame;
2658 start_frame = get_preferred_edit_position ( EDIT_IGNORE_PHEAD );
2660 if (_session->transport_rolling()) {
2661 _session->request_locate (start_frame, false);
2665 /* don't reset the return frame if its already set */
2667 if ((return_frame = _session->requested_return_frame()) < 0) {
2668 return_frame = _session->audible_frame();
2671 if (start_frame >= 0) {
2672 _session->request_roll_at_and_return (start_frame, return_frame);
2677 Editor::play_selection ()
2679 framepos_t start, end;
2680 if (!get_selection_extents ( start, end))
2683 AudioRange ar (start, end, 0);
2684 list<AudioRange> lar;
2687 _session->request_play_range (&lar, true);
2692 Editor::maybe_locate_with_edit_preroll (framepos_t location)
2694 if ( _session->transport_rolling() || !UIConfiguration::instance().get_follow_edits() || _session->config.get_external_sync() )
2697 location -= _session->preroll_samples (location);
2699 //don't try to locate before the beginning of time
2704 //if follow_playhead is on, keep the playhead on the screen
2705 if ( _follow_playhead )
2706 if ( location < leftmost_frame )
2707 location = leftmost_frame;
2709 _session->request_locate( location );
2713 Editor::play_with_preroll ()
2715 framepos_t start, end;
2716 if ( UIConfiguration::instance().get_follow_edits() && get_selection_extents ( start, end) ) {
2717 const framepos_t preroll = _session->preroll_samples (start);
2719 framepos_t ret = start;
2721 if (start > preroll) {
2722 start = start - preroll;
2725 end = end + preroll; //"post-roll"
2727 AudioRange ar (start, end, 0);
2728 list<AudioRange> lar;
2731 _session->request_play_range (&lar, true);
2732 _session->set_requested_return_frame (ret); //force auto-return to return to range start, without the preroll
2734 framepos_t ph = playhead_cursor->current_frame ();
2735 const framepos_t preroll = _session->preroll_samples (ph);
2738 start = ph - preroll;
2742 _session->request_locate (start, true);
2743 _session->set_requested_return_frame (ph); //force auto-return to return to playhead location, without the preroll
2748 Editor::rec_with_preroll ()
2750 framepos_t ph = playhead_cursor->current_frame ();
2751 framepos_t preroll = _session->preroll_samples (ph);
2752 _session->request_preroll_record_trim (ph, preroll);
2756 Editor::rec_with_count_in ()
2758 _session->request_count_in_record ();
2762 Editor::play_location (Location& location)
2764 if (location.start() <= location.end()) {
2768 _session->request_bounded_roll (location.start(), location.end());
2772 Editor::loop_location (Location& location)
2774 if (location.start() <= location.end()) {
2780 if ((tll = transport_loop_location()) != 0) {
2781 tll->set (location.start(), location.end());
2783 // enable looping, reposition and start rolling
2784 _session->request_locate (tll->start(), true);
2785 _session->request_play_loop (true);
2790 Editor::do_layer_operation (LayerOperation op)
2792 if (selection->regions.empty ()) {
2796 bool const multiple = selection->regions.size() > 1;
2800 begin_reversible_command (_("raise regions"));
2802 begin_reversible_command (_("raise region"));
2808 begin_reversible_command (_("raise regions to top"));
2810 begin_reversible_command (_("raise region to top"));
2816 begin_reversible_command (_("lower regions"));
2818 begin_reversible_command (_("lower region"));
2824 begin_reversible_command (_("lower regions to bottom"));
2826 begin_reversible_command (_("lower region"));
2831 set<boost::shared_ptr<Playlist> > playlists = selection->regions.playlists ();
2832 for (set<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
2833 (*i)->clear_owned_changes ();
2836 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
2837 boost::shared_ptr<Region> r = (*i)->region ();
2849 r->lower_to_bottom ();
2853 for (set<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
2854 vector<Command*> cmds;
2856 _session->add_commands (cmds);
2859 commit_reversible_command ();
2863 Editor::raise_region ()
2865 do_layer_operation (Raise);
2869 Editor::raise_region_to_top ()
2871 do_layer_operation (RaiseToTop);
2875 Editor::lower_region ()
2877 do_layer_operation (Lower);
2881 Editor::lower_region_to_bottom ()
2883 do_layer_operation (LowerToBottom);
2886 /** Show the region editor for the selected regions */
2888 Editor::show_region_properties ()
2890 selection->foreach_regionview (&RegionView::show_region_editor);
2893 /** Show the midi list editor for the selected MIDI regions */
2895 Editor::show_midi_list_editor ()
2897 selection->foreach_midi_regionview (&MidiRegionView::show_list_editor);
2901 Editor::rename_region ()
2903 RegionSelection rs = get_regions_from_selection_and_entered ();
2909 ArdourDialog d (_("Rename Region"), true, false);
2911 Label label (_("New name:"));
2914 hbox.set_spacing (6);
2915 hbox.pack_start (label, false, false);
2916 hbox.pack_start (entry, true, true);
2918 d.get_vbox()->set_border_width (12);
2919 d.get_vbox()->pack_start (hbox, false, false);
2921 d.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
2922 d.add_button(Gtk::Stock::OK, Gtk::RESPONSE_OK);
2924 d.set_size_request (300, -1);
2926 entry.set_text (rs.front()->region()->name());
2927 entry.select_region (0, -1);
2929 entry.signal_activate().connect (sigc::bind (sigc::mem_fun (d, &Dialog::response), RESPONSE_OK));
2935 int const ret = d.run();
2939 if (ret != RESPONSE_OK) {
2943 std::string str = entry.get_text();
2944 strip_whitespace_edges (str);
2946 rs.front()->region()->set_name (str);
2947 _regions->redisplay ();
2951 /** Start an audition of the first selected region */
2953 Editor::play_edit_range ()
2955 framepos_t start, end;
2957 if (get_edit_op_range (start, end)) {
2958 _session->request_bounded_roll (start, end);
2963 Editor::play_selected_region ()
2965 framepos_t start = max_framepos;
2968 RegionSelection rs = get_regions_from_selection_and_entered ();
2974 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
2975 if ((*i)->region()->position() < start) {
2976 start = (*i)->region()->position();
2978 if ((*i)->region()->last_frame() + 1 > end) {
2979 end = (*i)->region()->last_frame() + 1;
2983 _session->request_bounded_roll (start, end);
2987 Editor::audition_playlist_region_standalone (boost::shared_ptr<Region> region)
2989 _session->audition_region (region);
2993 Editor::region_from_selection ()
2995 if (clicked_axisview == 0) {
2999 if (selection->time.empty()) {
3003 framepos_t start = selection->time[clicked_selection].start;
3004 framepos_t end = selection->time[clicked_selection].end;
3006 TrackViewList tracks = get_tracks_for_range_action ();
3008 framepos_t selection_cnt = end - start + 1;
3010 for (TrackSelection::iterator i = tracks.begin(); i != tracks.end(); ++i) {
3011 boost::shared_ptr<Region> current;
3012 boost::shared_ptr<Playlist> pl;
3013 framepos_t internal_start;
3016 if ((pl = (*i)->playlist()) == 0) {
3020 if ((current = pl->top_region_at (start)) == 0) {
3024 internal_start = start - current->position();
3025 RegionFactory::region_name (new_name, current->name(), true);
3029 plist.add (ARDOUR::Properties::start, current->start() + internal_start);
3030 plist.add (ARDOUR::Properties::length, selection_cnt);
3031 plist.add (ARDOUR::Properties::name, new_name);
3032 plist.add (ARDOUR::Properties::layer, 0);
3034 boost::shared_ptr<Region> region (RegionFactory::create (current, plist));
3039 Editor::create_region_from_selection (vector<boost::shared_ptr<Region> >& new_regions)
3041 if (selection->time.empty() || selection->tracks.empty()) {
3045 framepos_t start, end;
3046 if (clicked_selection) {
3047 start = selection->time[clicked_selection].start;
3048 end = selection->time[clicked_selection].end;
3050 start = selection->time.start();
3051 end = selection->time.end_frame();
3054 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
3055 sort_track_selection (ts);
3057 for (TrackSelection::iterator i = ts.begin(); i != ts.end(); ++i) {
3058 boost::shared_ptr<Region> current;
3059 boost::shared_ptr<Playlist> playlist;
3060 framepos_t internal_start;
3063 if ((playlist = (*i)->playlist()) == 0) {
3067 if ((current = playlist->top_region_at(start)) == 0) {
3071 internal_start = start - current->position();
3072 RegionFactory::region_name (new_name, current->name(), true);
3076 plist.add (ARDOUR::Properties::start, current->start() + internal_start);
3077 plist.add (ARDOUR::Properties::length, end - start + 1);
3078 plist.add (ARDOUR::Properties::name, new_name);
3080 new_regions.push_back (RegionFactory::create (current, plist));
3085 Editor::split_multichannel_region ()
3087 RegionSelection rs = get_regions_from_selection_and_entered ();
3093 vector< boost::shared_ptr<Region> > v;
3095 for (list<RegionView*>::iterator x = rs.begin(); x != rs.end(); ++x) {
3096 (*x)->region()->separate_by_channel (*_session, v);
3101 Editor::new_region_from_selection ()
3103 region_from_selection ();
3104 cancel_selection ();
3108 add_if_covered (RegionView* rv, const AudioRange* ar, RegionSelection* rs)
3110 switch (rv->region()->coverage (ar->start, ar->end - 1)) {
3111 // n.b. -1 because AudioRange::end is one past the end, but coverage expects inclusive ranges
3112 case Evoral::OverlapNone:
3120 * - selected tracks, or if there are none...
3121 * - tracks containing selected regions, or if there are none...
3126 Editor::get_tracks_for_range_action () const
3130 if (selection->tracks.empty()) {
3132 /* use tracks with selected regions */
3134 RegionSelection rs = selection->regions;
3136 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3137 TimeAxisView* tv = &(*i)->get_time_axis_view();
3139 if (!t.contains (tv)) {
3145 /* no regions and no tracks: use all tracks */
3151 t = selection->tracks;
3154 return t.filter_to_unique_playlists();
3158 Editor::separate_regions_between (const TimeSelection& ts)
3160 bool in_command = false;
3161 boost::shared_ptr<Playlist> playlist;
3162 RegionSelection new_selection;
3164 TrackViewList tmptracks = get_tracks_for_range_action ();
3165 sort_track_selection (tmptracks);
3167 for (TrackSelection::iterator i = tmptracks.begin(); i != tmptracks.end(); ++i) {
3169 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> ((*i));
3175 if (!rtv->is_track()) {
3179 /* no edits to destructive tracks */
3181 if (rtv->track()->destructive()) {
3185 if ((playlist = rtv->playlist()) != 0) {
3187 playlist->clear_changes ();
3189 /* XXX need to consider musical time selections here at some point */
3191 double speed = rtv->track()->speed();
3193 for (list<AudioRange>::const_iterator t = ts.begin(); t != ts.end(); ++t) {
3195 sigc::connection c = rtv->view()->RegionViewAdded.connect (
3196 sigc::mem_fun(*this, &Editor::collect_new_region_view));
3198 latest_regionviews.clear ();
3200 playlist->partition ((framepos_t)((*t).start * speed),
3201 (framepos_t)((*t).end * speed), false);
3205 if (!latest_regionviews.empty()) {
3207 rtv->view()->foreach_regionview (sigc::bind (
3208 sigc::ptr_fun (add_if_covered),
3209 &(*t), &new_selection));
3212 begin_reversible_command (_("separate"));
3216 /* pick up changes to existing regions */
3218 vector<Command*> cmds;
3219 playlist->rdiff (cmds);
3220 _session->add_commands (cmds);
3222 /* pick up changes to the playlist itself (adds/removes)
3225 _session->add_command(new StatefulDiffCommand (playlist));
3232 // selection->set (new_selection);
3234 commit_reversible_command ();
3238 struct PlaylistState {
3239 boost::shared_ptr<Playlist> playlist;
3243 /** Take tracks from get_tracks_for_range_action and cut any regions
3244 * on those tracks so that the tracks are empty over the time
3248 Editor::separate_region_from_selection ()
3250 /* preferentially use *all* ranges in the time selection if we're in range mode
3251 to allow discontiguous operation, since get_edit_op_range() currently
3252 returns a single range.
3255 if (!selection->time.empty()) {
3257 separate_regions_between (selection->time);
3264 if (get_edit_op_range (start, end)) {
3266 AudioRange ar (start, end, 1);
3270 separate_regions_between (ts);
3276 Editor::separate_region_from_punch ()
3278 Location* loc = _session->locations()->auto_punch_location();
3280 separate_regions_using_location (*loc);
3285 Editor::separate_region_from_loop ()
3287 Location* loc = _session->locations()->auto_loop_location();
3289 separate_regions_using_location (*loc);
3294 Editor::separate_regions_using_location (Location& loc)
3296 if (loc.is_mark()) {
3300 AudioRange ar (loc.start(), loc.end(), 1);
3305 separate_regions_between (ts);
3308 /** Separate regions under the selected region */
3310 Editor::separate_under_selected_regions ()
3312 vector<PlaylistState> playlists;
3316 rs = get_regions_from_selection_and_entered();
3318 if (!_session || rs.empty()) {
3322 begin_reversible_command (_("separate region under"));
3324 list<boost::shared_ptr<Region> > regions_to_remove;
3326 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3327 // we can't just remove the region(s) in this loop because
3328 // this removes them from the RegionSelection, and they thus
3329 // disappear from underneath the iterator, and the ++i above
3330 // SEGVs in a puzzling fashion.
3332 // so, first iterate over the regions to be removed from rs and
3333 // add them to the regions_to_remove list, and then
3334 // iterate over the list to actually remove them.
3336 regions_to_remove.push_back ((*i)->region());
3339 for (list<boost::shared_ptr<Region> >::iterator rl = regions_to_remove.begin(); rl != regions_to_remove.end(); ++rl) {
3341 boost::shared_ptr<Playlist> playlist = (*rl)->playlist();
3344 // is this check necessary?
3348 vector<PlaylistState>::iterator i;
3350 //only take state if this is a new playlist.
3351 for (i = playlists.begin(); i != playlists.end(); ++i) {
3352 if ((*i).playlist == playlist) {
3357 if (i == playlists.end()) {
3359 PlaylistState before;
3360 before.playlist = playlist;
3361 before.before = &playlist->get_state();
3362 playlist->clear_changes ();
3363 playlist->freeze ();
3364 playlists.push_back(before);
3367 //Partition on the region bounds
3368 playlist->partition ((*rl)->first_frame() - 1, (*rl)->last_frame() + 1, true);
3370 //Re-add region that was just removed due to the partition operation
3371 playlist->add_region( (*rl), (*rl)->first_frame() );
3374 vector<PlaylistState>::iterator pl;
3376 for (pl = playlists.begin(); pl != playlists.end(); ++pl) {
3377 (*pl).playlist->thaw ();
3378 _session->add_command(new MementoCommand<Playlist>(*(*pl).playlist, (*pl).before, &(*pl).playlist->get_state()));
3381 commit_reversible_command ();
3385 Editor::crop_region_to_selection ()
3387 if (!selection->time.empty()) {
3389 begin_reversible_command (_("Crop Regions to Time Selection"));
3390 for (std::list<AudioRange>::iterator i = selection->time.begin(); i != selection->time.end(); ++i) {
3391 crop_region_to ((*i).start, (*i).end);
3393 commit_reversible_command();
3399 if (get_edit_op_range (start, end)) {
3400 begin_reversible_command (_("Crop Regions to Edit Range"));
3402 crop_region_to (start, end);
3404 commit_reversible_command();
3411 Editor::crop_region_to (framepos_t start, framepos_t end)
3413 vector<boost::shared_ptr<Playlist> > playlists;
3414 boost::shared_ptr<Playlist> playlist;
3417 if (selection->tracks.empty()) {
3418 ts = track_views.filter_to_unique_playlists();
3420 ts = selection->tracks.filter_to_unique_playlists ();
3423 sort_track_selection (ts);
3425 for (TrackSelection::iterator i = ts.begin(); i != ts.end(); ++i) {
3427 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> ((*i));
3433 boost::shared_ptr<Track> t = rtv->track();
3435 if (t != 0 && ! t->destructive()) {
3437 if ((playlist = rtv->playlist()) != 0) {
3438 playlists.push_back (playlist);
3443 if (playlists.empty()) {
3448 framepos_t new_start;
3450 framecnt_t new_length;
3452 for (vector<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
3454 /* Only the top regions at start and end have to be cropped */
3455 boost::shared_ptr<Region> region_at_start = (*i)->top_region_at(start);
3456 boost::shared_ptr<Region> region_at_end = (*i)->top_region_at(end);
3458 vector<boost::shared_ptr<Region> > regions;
3460 if (region_at_start != 0) {
3461 regions.push_back (region_at_start);
3463 if (region_at_end != 0) {
3464 regions.push_back (region_at_end);
3467 /* now adjust lengths */
3468 for (vector<boost::shared_ptr<Region> >::iterator i = regions.begin(); i != regions.end(); ++i) {
3470 pos = (*i)->position();
3471 new_start = max (start, pos);
3472 if (max_framepos - pos > (*i)->length()) {
3473 new_end = pos + (*i)->length() - 1;
3475 new_end = max_framepos;
3477 new_end = min (end, new_end);
3478 new_length = new_end - new_start + 1;
3480 (*i)->clear_changes ();
3481 (*i)->trim_to (new_start, new_length);
3482 _session->add_command (new StatefulDiffCommand (*i));
3488 Editor::region_fill_track ()
3490 boost::shared_ptr<Playlist> playlist;
3491 RegionSelection regions = get_regions_from_selection_and_entered ();
3492 RegionSelection foo;
3494 framepos_t const end = _session->current_end_frame ();
3496 if (regions.empty () || regions.end_frame () + 1 >= end) {
3500 framepos_t const start_frame = regions.start ();
3501 framepos_t const end_frame = regions.end_frame ();
3502 framecnt_t const gap = end_frame - start_frame + 1;
3504 begin_reversible_command (Operations::region_fill);
3506 selection->clear_regions ();
3508 for (RegionSelection::iterator i = regions.begin(); i != regions.end(); ++i) {
3510 boost::shared_ptr<Region> r ((*i)->region());
3512 TimeAxisView& tv = (*i)->get_time_axis_view();
3513 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (&tv);
3514 latest_regionviews.clear ();
3515 sigc::connection c = rtv->view()->RegionViewAdded.connect (sigc::mem_fun(*this, &Editor::collect_new_region_view));
3517 framepos_t const position = end_frame + (r->first_frame() - start_frame + 1);
3518 playlist = (*i)->region()->playlist();
3519 playlist->clear_changes ();
3520 playlist->duplicate_until (r, position, gap, end);
3521 _session->add_command(new StatefulDiffCommand (playlist));
3525 foo.insert (foo.end(), latest_regionviews.begin(), latest_regionviews.end());
3529 selection->set (foo);
3532 commit_reversible_command ();
3536 Editor::set_region_sync_position ()
3538 set_sync_point (get_preferred_edit_position (), get_regions_from_selection_and_edit_point ());
3542 Editor::set_sync_point (framepos_t where, const RegionSelection& rs)
3544 bool in_command = false;
3546 for (RegionSelection::const_iterator r = rs.begin(); r != rs.end(); ++r) {
3548 if (!(*r)->region()->covers (where)) {
3552 boost::shared_ptr<Region> region ((*r)->region());
3555 begin_reversible_command (_("set sync point"));
3559 region->clear_changes ();
3560 region->set_sync_position (where);
3561 _session->add_command(new StatefulDiffCommand (region));
3565 commit_reversible_command ();
3569 /** Remove the sync positions of the selection */
3571 Editor::remove_region_sync ()
3573 RegionSelection rs = get_regions_from_selection_and_entered ();
3579 begin_reversible_command (_("remove region sync"));
3581 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3583 (*i)->region()->clear_changes ();
3584 (*i)->region()->clear_sync_position ();
3585 _session->add_command(new StatefulDiffCommand ((*i)->region()));
3588 commit_reversible_command ();
3592 Editor::naturalize_region ()
3594 RegionSelection rs = get_regions_from_selection_and_entered ();
3600 if (rs.size() > 1) {
3601 begin_reversible_command (_("move regions to original position"));
3603 begin_reversible_command (_("move region to original position"));
3606 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3607 (*i)->region()->clear_changes ();
3608 (*i)->region()->move_to_natural_position ();
3609 _session->add_command (new StatefulDiffCommand ((*i)->region()));
3612 commit_reversible_command ();
3616 Editor::align_regions (RegionPoint what)
3618 RegionSelection const rs = get_regions_from_selection_and_edit_point ();
3624 begin_reversible_command (_("align selection"));
3626 framepos_t const position = get_preferred_edit_position ();
3628 for (RegionSelection::const_iterator i = rs.begin(); i != rs.end(); ++i) {
3629 align_region_internal ((*i)->region(), what, position);
3632 commit_reversible_command ();
3635 struct RegionSortByTime {
3636 bool operator() (const RegionView* a, const RegionView* b) {
3637 return a->region()->position() < b->region()->position();
3642 Editor::align_regions_relative (RegionPoint point)
3644 RegionSelection const rs = get_regions_from_selection_and_edit_point ();
3650 framepos_t const position = get_preferred_edit_position ();
3652 framepos_t distance = 0;
3656 list<RegionView*> sorted;
3657 rs.by_position (sorted);
3659 boost::shared_ptr<Region> r ((*sorted.begin())->region());
3664 if (position > r->position()) {
3665 distance = position - r->position();
3667 distance = r->position() - position;
3673 if (position > r->last_frame()) {
3674 distance = position - r->last_frame();
3675 pos = r->position() + distance;
3677 distance = r->last_frame() - position;
3678 pos = r->position() - distance;
3684 pos = r->adjust_to_sync (position);
3685 if (pos > r->position()) {
3686 distance = pos - r->position();
3688 distance = r->position() - pos;
3694 if (pos == r->position()) {
3698 begin_reversible_command (_("align selection (relative)"));
3700 /* move first one specially */
3702 r->clear_changes ();
3703 r->set_position (pos);
3704 _session->add_command(new StatefulDiffCommand (r));
3706 /* move rest by the same amount */
3710 for (list<RegionView*>::iterator i = sorted.begin(); i != sorted.end(); ++i) {
3712 boost::shared_ptr<Region> region ((*i)->region());
3714 region->clear_changes ();
3717 region->set_position (region->position() + distance);
3719 region->set_position (region->position() - distance);
3722 _session->add_command(new StatefulDiffCommand (region));
3726 commit_reversible_command ();
3730 Editor::align_region (boost::shared_ptr<Region> region, RegionPoint point, framepos_t position)
3732 begin_reversible_command (_("align region"));
3733 align_region_internal (region, point, position);
3734 commit_reversible_command ();
3738 Editor::align_region_internal (boost::shared_ptr<Region> region, RegionPoint point, framepos_t position)
3740 region->clear_changes ();
3744 region->set_position (region->adjust_to_sync (position));
3748 if (position > region->length()) {
3749 region->set_position (position - region->length());
3754 region->set_position (position);
3758 _session->add_command(new StatefulDiffCommand (region));
3762 Editor::trim_region_front ()
3768 Editor::trim_region_back ()
3770 trim_region (false);
3774 Editor::trim_region (bool front)
3776 framepos_t where = get_preferred_edit_position();
3777 RegionSelection rs = get_regions_from_selection_and_edit_point ();
3783 begin_reversible_command (front ? _("trim front") : _("trim back"));
3785 for (list<RegionView*>::const_iterator i = rs.by_layer().begin(); i != rs.by_layer().end(); ++i) {
3786 if (!(*i)->region()->locked()) {
3788 (*i)->region()->clear_changes ();
3791 (*i)->region()->trim_front (where);
3793 (*i)->region()->trim_end (where);
3796 _session->add_command (new StatefulDiffCommand ((*i)->region()));
3800 commit_reversible_command ();
3803 /** Trim the end of the selected regions to the position of the edit cursor */
3805 Editor::trim_region_to_loop ()
3807 Location* loc = _session->locations()->auto_loop_location();
3811 trim_region_to_location (*loc, _("trim to loop"));
3815 Editor::trim_region_to_punch ()
3817 Location* loc = _session->locations()->auto_punch_location();
3821 trim_region_to_location (*loc, _("trim to punch"));
3825 Editor::trim_region_to_location (const Location& loc, const char* str)
3827 RegionSelection rs = get_regions_from_selection_and_entered ();
3828 bool in_command = false;
3830 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
3831 RegionView* rv = (*x);
3833 /* require region to span proposed trim */
3834 switch (rv->region()->coverage (loc.start(), loc.end())) {
3835 case Evoral::OverlapInternal:
3841 RouteTimeAxisView* tav = dynamic_cast<RouteTimeAxisView*> (&rv->get_time_axis_view());
3850 if (tav->track() != 0) {
3851 speed = tav->track()->speed();
3854 start = session_frame_to_track_frame (loc.start(), speed);
3855 end = session_frame_to_track_frame (loc.end(), speed);
3857 rv->region()->clear_changes ();
3858 rv->region()->trim_to (start, (end - start));
3861 begin_reversible_command (str);
3864 _session->add_command(new StatefulDiffCommand (rv->region()));
3868 commit_reversible_command ();
3873 Editor::trim_region_to_previous_region_end ()
3875 return trim_to_region(false);
3879 Editor::trim_region_to_next_region_start ()
3881 return trim_to_region(true);
3885 Editor::trim_to_region(bool forward)
3887 RegionSelection rs = get_regions_from_selection_and_entered ();
3888 bool in_command = false;
3890 boost::shared_ptr<Region> next_region;
3892 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
3894 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*x);
3900 AudioTimeAxisView* atav = dynamic_cast<AudioTimeAxisView*> (&arv->get_time_axis_view());
3908 if (atav->track() != 0) {
3909 speed = atav->track()->speed();
3913 boost::shared_ptr<Region> region = arv->region();
3914 boost::shared_ptr<Playlist> playlist (region->playlist());
3916 region->clear_changes ();
3920 next_region = playlist->find_next_region (region->first_frame(), Start, 1);
3926 region->trim_end((framepos_t) ( (next_region->first_frame() - 1) * speed));
3927 arv->region_changed (PropertyChange (ARDOUR::Properties::length));
3931 next_region = playlist->find_next_region (region->first_frame(), Start, 0);
3937 region->trim_front((framepos_t) ((next_region->last_frame() + 1) * speed));
3939 arv->region_changed (ARDOUR::bounds_change);
3943 begin_reversible_command (_("trim to region"));
3946 _session->add_command(new StatefulDiffCommand (region));
3950 commit_reversible_command ();
3955 Editor::unfreeze_route ()
3957 if (clicked_routeview == 0 || !clicked_routeview->is_track()) {
3961 clicked_routeview->track()->unfreeze ();
3965 Editor::_freeze_thread (void* arg)
3967 return static_cast<Editor*>(arg)->freeze_thread ();
3971 Editor::freeze_thread ()
3973 /* create event pool because we may need to talk to the session */
3974 SessionEvent::create_per_thread_pool ("freeze events", 64);
3975 /* create per-thread buffers for process() tree to use */
3976 clicked_routeview->audio_track()->freeze_me (*current_interthread_info);
3977 current_interthread_info->done = true;
3982 Editor::freeze_route ()
3988 /* stop transport before we start. this is important */
3990 _session->request_transport_speed (0.0);
3992 /* wait for just a little while, because the above call is asynchronous */
3994 Glib::usleep (250000);
3996 if (clicked_routeview == 0 || !clicked_routeview->is_audio_track()) {
4000 if (!clicked_routeview->track()->bounceable (clicked_routeview->track()->main_outs(), true)) {
4002 _("This track/bus cannot be frozen because the signal adds or loses channels before reaching the outputs.\n"
4003 "This is typically caused by plugins that generate stereo output from mono input or vice versa.")
4005 d.set_title (_("Cannot freeze"));
4010 if (clicked_routeview->track()->has_external_redirects()) {
4011 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"
4012 "Freezing will only process the signal as far as the first send/insert/return."),
4013 clicked_routeview->track()->name()), true, MESSAGE_INFO, BUTTONS_NONE, true);
4015 d.add_button (_("Freeze anyway"), Gtk::RESPONSE_OK);
4016 d.add_button (_("Don't freeze"), Gtk::RESPONSE_CANCEL);
4017 d.set_title (_("Freeze Limits"));
4019 int response = d.run ();
4022 case Gtk::RESPONSE_CANCEL:
4029 InterThreadInfo itt;
4030 current_interthread_info = &itt;
4032 InterthreadProgressWindow ipw (current_interthread_info, _("Freeze"), _("Cancel Freeze"));
4034 pthread_create_and_store (X_("freezer"), &itt.thread, _freeze_thread, this);
4036 CursorContext::Handle cursor_ctx = CursorContext::create(*this, _cursors->wait);
4038 while (!itt.done && !itt.cancel) {
4039 gtk_main_iteration ();
4042 pthread_join (itt.thread, 0);
4043 current_interthread_info = 0;
4047 Editor::bounce_range_selection (bool replace, bool enable_processing)
4049 if (selection->time.empty()) {
4053 TrackSelection views = selection->tracks;
4055 for (TrackViewList::iterator i = views.begin(); i != views.end(); ++i) {
4057 if (enable_processing) {
4059 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*i);
4061 if (rtv && rtv->track() && replace && enable_processing && !rtv->track()->bounceable (rtv->track()->main_outs(), false)) {
4063 _("You can't perform this operation because the processing of the signal "
4064 "will cause one or more of the tracks to end up with a region with more channels than this track has inputs.\n\n"
4065 "You can do this without processing, which is a different operation.")
4067 d.set_title (_("Cannot bounce"));
4074 framepos_t start = selection->time[clicked_selection].start;
4075 framepos_t end = selection->time[clicked_selection].end;
4076 framepos_t cnt = end - start + 1;
4077 bool in_command = false;
4079 for (TrackViewList::iterator i = views.begin(); i != views.end(); ++i) {
4081 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*i);
4087 boost::shared_ptr<Playlist> playlist;
4089 if ((playlist = rtv->playlist()) == 0) {
4093 InterThreadInfo itt;
4095 playlist->clear_changes ();
4096 playlist->clear_owned_changes ();
4098 boost::shared_ptr<Region> r;
4100 if (enable_processing) {
4101 r = rtv->track()->bounce_range (start, start+cnt, itt, rtv->track()->main_outs(), false);
4103 r = rtv->track()->bounce_range (start, start+cnt, itt, boost::shared_ptr<Processor>(), false);
4111 list<AudioRange> ranges;
4112 ranges.push_back (AudioRange (start, start+cnt, 0));
4113 playlist->cut (ranges); // discard result
4114 playlist->add_region (r, start);
4118 begin_reversible_command (_("bounce range"));
4121 vector<Command*> cmds;
4122 playlist->rdiff (cmds);
4123 _session->add_commands (cmds);
4125 _session->add_command (new StatefulDiffCommand (playlist));
4129 commit_reversible_command ();
4133 /** Delete selected regions, automation points or a time range */
4137 //special case: if the user is pointing in the editor/mixer strip, they may be trying to delete a plugin.
4138 //we need this because the editor-mixer strip is in the editor window, so it doesn't get the bindings from the mix window
4139 bool deleted = false;
4140 if ( current_mixer_strip && current_mixer_strip == MixerStrip::entered_mixer_strip() )
4141 deleted = current_mixer_strip->delete_processors ();
4147 /** Cut selected regions, automation points or a time range */
4154 /** Copy selected regions, automation points or a time range */
4162 /** @return true if a Cut, Copy or Clear is possible */
4164 Editor::can_cut_copy () const
4166 if (!selection->time.empty() || !selection->regions.empty() || !selection->points.empty())
4173 /** Cut, copy or clear selected regions, automation points or a time range.
4174 * @param op Operation (Delete, Cut, Copy or Clear)
4177 Editor::cut_copy (CutCopyOp op)
4179 /* only cancel selection if cut/copy is successful.*/
4185 opname = _("delete");
4194 opname = _("clear");
4198 /* if we're deleting something, and the mouse is still pressed,
4199 the thing we started a drag for will be gone when we release
4200 the mouse button(s). avoid this. see part 2 at the end of
4204 if (op == Delete || op == Cut || op == Clear) {
4205 if (_drags->active ()) {
4210 if ( op != Delete ) { //"Delete" doesn't change copy/paste buf
4211 cut_buffer->clear ();
4214 if (entered_marker) {
4216 /* cut/delete op while pointing at a marker */
4219 Location* loc = find_location_from_marker (entered_marker, ignored);
4221 if (_session && loc) {
4222 entered_marker = NULL;
4223 Glib::signal_idle().connect (sigc::bind (sigc::mem_fun(*this, &Editor::really_remove_marker), loc));
4230 switch (mouse_mode) {
4233 begin_reversible_command (opname + ' ' + X_("MIDI"));
4235 commit_reversible_command ();
4241 bool did_edit = false;
4243 if (!selection->regions.empty() || !selection->points.empty()) {
4244 begin_reversible_command (opname + ' ' + _("objects"));
4247 if (!selection->regions.empty()) {
4248 cut_copy_regions (op, selection->regions);
4250 if (op == Cut || op == Delete) {
4251 selection->clear_regions ();
4255 if (!selection->points.empty()) {
4256 cut_copy_points (op);
4258 if (op == Cut || op == Delete) {
4259 selection->clear_points ();
4262 } else if (selection->time.empty()) {
4263 framepos_t start, end;
4264 /* no time selection, see if we can get an edit range
4267 if (get_edit_op_range (start, end)) {
4268 selection->set (start, end);
4270 } else if (!selection->time.empty()) {
4271 begin_reversible_command (opname + ' ' + _("range"));
4274 cut_copy_ranges (op);
4276 if (op == Cut || op == Delete) {
4277 selection->clear_time ();
4282 /* reset repeated paste state */
4284 last_paste_pos = -1;
4285 commit_reversible_command ();
4288 if (op == Delete || op == Cut || op == Clear) {
4294 struct AutomationRecord {
4295 AutomationRecord () : state (0) , line(NULL) {}
4296 AutomationRecord (XMLNode* s, const AutomationLine* l) : state (s) , line (l) {}
4298 XMLNode* state; ///< state before any operation
4299 const AutomationLine* line; ///< line this came from
4300 boost::shared_ptr<Evoral::ControlList> copy; ///< copied events for the cut buffer
4303 struct PointsSelectionPositionSorter {
4304 bool operator() (ControlPoint* a, ControlPoint* b) {
4305 return (*(a->model()))->when < (*(b->model()))->when;
4309 /** Cut, copy or clear selected automation points.
4310 * @param op Operation (Cut, Copy or Clear)
4313 Editor::cut_copy_points (Editing::CutCopyOp op, Evoral::Beats earliest, bool midi)
4315 if (selection->points.empty ()) {
4319 /* XXX: not ideal, as there may be more than one track involved in the point selection */
4320 _last_cut_copy_source_track = &selection->points.front()->line().trackview;
4322 /* Keep a record of the AutomationLists that we end up using in this operation */
4323 typedef std::map<boost::shared_ptr<AutomationList>, AutomationRecord> Lists;
4326 /* user could select points in any order */
4327 selection->points.sort(PointsSelectionPositionSorter ());
4329 /* Go through all selected points, making an AutomationRecord for each distinct AutomationList */
4330 for (PointSelection::iterator sel_point = selection->points.begin(); sel_point != selection->points.end(); ++sel_point) {
4331 const AutomationLine& line = (*sel_point)->line();
4332 const boost::shared_ptr<AutomationList> al = line.the_list();
4333 if (lists.find (al) == lists.end ()) {
4334 /* We haven't seen this list yet, so make a record for it. This includes
4335 taking a copy of its current state, in case this is needed for undo later.
4337 lists[al] = AutomationRecord (&al->get_state (), &line);
4341 if (op == Cut || op == Copy) {
4342 /* This operation will involve putting things in the cut buffer, so create an empty
4343 ControlList for each of our source lists to put the cut buffer data in.
4345 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
4346 i->second.copy = i->first->create (i->first->parameter (), i->first->descriptor());
4349 /* Add all selected points to the relevant copy ControlLists */
4350 MusicFrame start (std::numeric_limits<framepos_t>::max(), 0);
4351 for (PointSelection::iterator sel_point = selection->points.begin(); sel_point != selection->points.end(); ++sel_point) {
4352 boost::shared_ptr<AutomationList> al = (*sel_point)->line().the_list();
4353 AutomationList::const_iterator ctrl_evt = (*sel_point)->model ();
4355 lists[al].copy->fast_simple_add ((*ctrl_evt)->when, (*ctrl_evt)->value);
4357 /* Update earliest MIDI start time in beats */
4358 earliest = std::min(earliest, Evoral::Beats((*ctrl_evt)->when));
4360 /* Update earliest session start time in frames */
4361 start.frame = std::min(start.frame, (*sel_point)->line().session_position(ctrl_evt));
4365 /* Snap start time backwards, so copy/paste is snap aligned. */
4367 if (earliest == Evoral::Beats::max()) {
4368 earliest = Evoral::Beats(); // Weird... don't offset
4370 earliest.round_down_to_beat();
4372 if (start.frame == std::numeric_limits<double>::max()) {
4373 start.frame = 0; // Weird... don't offset
4375 snap_to(start, RoundDownMaybe);
4378 const double line_offset = midi ? earliest.to_double() : start.frame;
4379 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
4380 /* Correct this copy list so that it is relative to the earliest
4381 start time, so relative ordering between points is preserved
4382 when copying from several lists and the paste starts at the
4383 earliest copied piece of data. */
4384 boost::shared_ptr<Evoral::ControlList> &al_cpy = i->second.copy;
4385 for (AutomationList::iterator ctrl_evt = al_cpy->begin(); ctrl_evt != al_cpy->end(); ++ctrl_evt) {
4386 (*ctrl_evt)->when -= line_offset;
4389 /* And add it to the cut buffer */
4390 cut_buffer->add (al_cpy);
4394 if (op == Delete || op == Cut) {
4395 /* This operation needs to remove things from the main AutomationList, so do that now */
4397 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
4398 i->first->freeze ();
4401 /* Remove each selected point from its AutomationList */
4402 for (PointSelection::iterator sel_point = selection->points.begin(); sel_point != selection->points.end(); ++sel_point) {
4403 AutomationLine& line = (*sel_point)->line ();
4404 boost::shared_ptr<AutomationList> al = line.the_list();
4408 if (dynamic_cast<AudioRegionGainLine*> (&line)) {
4409 /* removing of first and last gain point in region gain lines is prohibited*/
4410 if (line.is_last_point (*(*sel_point)) || line.is_first_point (*(*sel_point))) {
4416 al->erase ((*sel_point)->model ());
4420 /* Thaw the lists and add undo records for them */
4421 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
4422 boost::shared_ptr<AutomationList> al = i->first;
4424 _session->add_command (new MementoCommand<AutomationList> (*al.get(), i->second.state, &(al->get_state ())));
4429 /** Cut, copy or clear selected automation points.
4430 * @param op Operation (Cut, Copy or Clear)
4433 Editor::cut_copy_midi (CutCopyOp op)
4435 Evoral::Beats earliest = Evoral::Beats::max();
4436 for (MidiRegionSelection::iterator i = selection->midi_regions.begin(); i != selection->midi_regions.end(); ++i) {
4437 MidiRegionView* mrv = dynamic_cast<MidiRegionView*>(*i);
4439 if (!mrv->selection().empty()) {
4440 earliest = std::min(earliest, (*mrv->selection().begin())->note()->time());
4442 mrv->cut_copy_clear (op);
4444 /* XXX: not ideal, as there may be more than one track involved in the selection */
4445 _last_cut_copy_source_track = &mrv->get_time_axis_view();
4449 if (!selection->points.empty()) {
4450 cut_copy_points (op, earliest, true);
4451 if (op == Cut || op == Delete) {
4452 selection->clear_points ();
4457 struct lt_playlist {
4458 bool operator () (const PlaylistState& a, const PlaylistState& b) {
4459 return a.playlist < b.playlist;
4463 struct PlaylistMapping {
4465 boost::shared_ptr<Playlist> pl;
4467 PlaylistMapping (TimeAxisView* tvp) : tv (tvp) {}
4470 /** Remove `clicked_regionview' */
4472 Editor::remove_clicked_region ()
4474 if (clicked_routeview == 0 || clicked_regionview == 0) {
4478 begin_reversible_command (_("remove region"));
4480 boost::shared_ptr<Playlist> playlist = clicked_routeview->playlist();
4482 playlist->clear_changes ();
4483 playlist->clear_owned_changes ();
4484 playlist->remove_region (clicked_regionview->region());
4485 if (Config->get_edit_mode() == Ripple)
4486 playlist->ripple (clicked_regionview->region()->position(), -clicked_regionview->region()->length(), boost::shared_ptr<Region>());
4488 /* We might have removed regions, which alters other regions' layering_index,
4489 so we need to do a recursive diff here.
4491 vector<Command*> cmds;
4492 playlist->rdiff (cmds);
4493 _session->add_commands (cmds);
4495 _session->add_command(new StatefulDiffCommand (playlist));
4496 commit_reversible_command ();
4500 /** Remove the selected regions */
4502 Editor::remove_selected_regions ()
4504 RegionSelection rs = get_regions_from_selection_and_entered ();
4506 if (!_session || rs.empty()) {
4510 list<boost::shared_ptr<Region> > regions_to_remove;
4512 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
4513 // we can't just remove the region(s) in this loop because
4514 // this removes them from the RegionSelection, and they thus
4515 // disappear from underneath the iterator, and the ++i above
4516 // SEGVs in a puzzling fashion.
4518 // so, first iterate over the regions to be removed from rs and
4519 // add them to the regions_to_remove list, and then
4520 // iterate over the list to actually remove them.
4522 regions_to_remove.push_back ((*i)->region());
4525 vector<boost::shared_ptr<Playlist> > playlists;
4527 for (list<boost::shared_ptr<Region> >::iterator rl = regions_to_remove.begin(); rl != regions_to_remove.end(); ++rl) {
4529 boost::shared_ptr<Playlist> playlist = (*rl)->playlist();
4532 // is this check necessary?
4536 /* get_regions_from_selection_and_entered() guarantees that
4537 the playlists involved are unique, so there is no need
4541 playlists.push_back (playlist);
4543 playlist->clear_changes ();
4544 playlist->clear_owned_changes ();
4545 playlist->freeze ();
4546 playlist->remove_region (*rl);
4547 if (Config->get_edit_mode() == Ripple)
4548 playlist->ripple ((*rl)->position(), -(*rl)->length(), boost::shared_ptr<Region>());
4552 vector<boost::shared_ptr<Playlist> >::iterator pl;
4553 bool in_command = false;
4555 for (pl = playlists.begin(); pl != playlists.end(); ++pl) {
4558 /* We might have removed regions, which alters other regions' layering_index,
4559 so we need to do a recursive diff here.
4563 begin_reversible_command (_("remove region"));
4566 vector<Command*> cmds;
4567 (*pl)->rdiff (cmds);
4568 _session->add_commands (cmds);
4570 _session->add_command(new StatefulDiffCommand (*pl));
4574 commit_reversible_command ();
4578 /** Cut, copy or clear selected regions.
4579 * @param op Operation (Cut, Copy or Clear)
4582 Editor::cut_copy_regions (CutCopyOp op, RegionSelection& rs)
4584 /* we can't use a std::map here because the ordering is important, and we can't trivially sort
4585 a map when we want ordered access to both elements. i think.
4588 vector<PlaylistMapping> pmap;
4590 framepos_t first_position = max_framepos;
4592 typedef set<boost::shared_ptr<Playlist> > FreezeList;
4593 FreezeList freezelist;
4595 /* get ordering correct before we cut/copy */
4597 rs.sort_by_position_and_track ();
4599 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
4601 first_position = min ((framepos_t) (*x)->region()->position(), first_position);
4603 if (op == Cut || op == Clear || op == Delete) {
4604 boost::shared_ptr<Playlist> pl = (*x)->region()->playlist();
4607 FreezeList::iterator fl;
4609 // only take state if this is a new playlist.
4610 for (fl = freezelist.begin(); fl != freezelist.end(); ++fl) {
4616 if (fl == freezelist.end()) {
4617 pl->clear_changes();
4618 pl->clear_owned_changes ();
4620 freezelist.insert (pl);
4625 TimeAxisView* tv = &(*x)->get_time_axis_view();
4626 vector<PlaylistMapping>::iterator z;
4628 for (z = pmap.begin(); z != pmap.end(); ++z) {
4629 if ((*z).tv == tv) {
4634 if (z == pmap.end()) {
4635 pmap.push_back (PlaylistMapping (tv));
4639 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ) {
4641 boost::shared_ptr<Playlist> pl = (*x)->region()->playlist();
4644 /* region not yet associated with a playlist (e.g. unfinished
4651 TimeAxisView& tv = (*x)->get_time_axis_view();
4652 boost::shared_ptr<Playlist> npl;
4653 RegionSelection::iterator tmp;
4660 vector<PlaylistMapping>::iterator z;
4662 for (z = pmap.begin(); z != pmap.end(); ++z) {
4663 if ((*z).tv == &tv) {
4668 assert (z != pmap.end());
4671 npl = PlaylistFactory::create (pl->data_type(), *_session, "cutlist", true);
4679 boost::shared_ptr<Region> r = (*x)->region();
4680 boost::shared_ptr<Region> _xx;
4686 pl->remove_region (r);
4687 if (Config->get_edit_mode() == Ripple)
4688 pl->ripple (r->position(), -r->length(), boost::shared_ptr<Region>());
4692 _xx = RegionFactory::create (r);
4693 npl->add_region (_xx, r->position() - first_position);
4694 pl->remove_region (r);
4695 if (Config->get_edit_mode() == Ripple)
4696 pl->ripple (r->position(), -r->length(), boost::shared_ptr<Region>());
4700 /* copy region before adding, so we're not putting same object into two different playlists */
4701 npl->add_region (RegionFactory::create (r), r->position() - first_position);
4705 pl->remove_region (r);
4706 if (Config->get_edit_mode() == Ripple)
4707 pl->ripple (r->position(), -r->length(), boost::shared_ptr<Region>());
4716 list<boost::shared_ptr<Playlist> > foo;
4718 /* the pmap is in the same order as the tracks in which selected regions occurred */
4720 for (vector<PlaylistMapping>::iterator i = pmap.begin(); i != pmap.end(); ++i) {
4723 foo.push_back ((*i).pl);
4728 cut_buffer->set (foo);
4732 _last_cut_copy_source_track = 0;
4734 _last_cut_copy_source_track = pmap.front().tv;
4738 for (FreezeList::iterator pl = freezelist.begin(); pl != freezelist.end(); ++pl) {
4741 /* We might have removed regions, which alters other regions' layering_index,
4742 so we need to do a recursive diff here.
4744 vector<Command*> cmds;
4745 (*pl)->rdiff (cmds);
4746 _session->add_commands (cmds);
4748 _session->add_command (new StatefulDiffCommand (*pl));
4753 Editor::cut_copy_ranges (CutCopyOp op)
4755 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4757 /* Sort the track selection now, so that it if is used, the playlists
4758 selected by the calls below to cut_copy_clear are in the order that
4759 their tracks appear in the editor. This makes things like paste
4760 of ranges work properly.
4763 sort_track_selection (ts);
4766 if (!entered_track) {
4769 ts.push_back (entered_track);
4772 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4773 (*i)->cut_copy_clear (*selection, op);
4778 Editor::paste (float times, bool from_context)
4780 DEBUG_TRACE (DEBUG::CutNPaste, "paste to preferred edit pos\n");
4781 MusicFrame where (get_preferred_edit_position (EDIT_IGNORE_NONE, from_context), 0);
4782 paste_internal (where.frame, times, 0);
4786 Editor::mouse_paste ()
4788 MusicFrame where (0, 0);
4790 if (!mouse_frame (where.frame, ignored)) {
4795 paste_internal (where.frame, 1, where.division);
4799 Editor::paste_internal (framepos_t position, float times, const int32_t sub_num)
4801 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("apparent paste position is %1\n", position));
4803 if (cut_buffer->empty(internal_editing())) {
4807 if (position == max_framepos) {
4808 position = get_preferred_edit_position();
4809 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("preferred edit position is %1\n", position));
4812 if (position == last_paste_pos) {
4813 /* repeated paste in the same position */
4816 /* paste in new location, reset repeated paste state */
4818 last_paste_pos = position;
4821 /* get everything in the correct order */
4824 if (!selection->tracks.empty()) {
4825 /* If there is a track selection, paste into exactly those tracks and
4826 * only those tracks. This allows the user to be explicit and override
4827 * the below "do the reasonable thing" logic. */
4828 ts = selection->tracks.filter_to_unique_playlists ();
4829 sort_track_selection (ts);
4831 /* Figure out which track to base the paste at. */
4832 TimeAxisView* base_track = NULL;
4833 if (_edit_point == Editing::EditAtMouse && entered_track) {
4834 /* With the mouse edit point, paste onto the track under the mouse. */
4835 base_track = entered_track;
4836 } else if (_edit_point == Editing::EditAtMouse && entered_regionview) {
4837 /* With the mouse edit point, paste onto the track of the region under the mouse. */
4838 base_track = &entered_regionview->get_time_axis_view();
4839 } else if (_last_cut_copy_source_track) {
4840 /* Paste to the track that the cut/copy came from (see mantis #333). */
4841 base_track = _last_cut_copy_source_track;
4843 /* This is "impossible" since we've copied... well, do nothing. */
4847 /* Walk up to parent if necessary, so base track is a route. */
4848 while (base_track->get_parent()) {
4849 base_track = base_track->get_parent();
4852 /* Add base track and all tracks below it. The paste logic will select
4853 the appropriate object types from the cut buffer in relative order. */
4854 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4855 if ((*i)->order() >= base_track->order()) {
4860 /* Sort tracks so the nth track of type T will pick the nth object of type T. */
4861 sort_track_selection (ts);
4863 /* Add automation children of each track in order, for pasting several lines. */
4864 for (TrackViewList::iterator i = ts.begin(); i != ts.end();) {
4865 /* Add any automation children for pasting several lines */
4866 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*i++);
4871 typedef RouteTimeAxisView::AutomationTracks ATracks;
4872 const ATracks& atracks = rtv->automation_tracks();
4873 for (ATracks::const_iterator a = atracks.begin(); a != atracks.end(); ++a) {
4874 i = ts.insert(i, a->second.get());
4879 /* We now have a list of trackviews starting at base_track, including
4880 automation children, in the order shown in the editor, e.g. R1,
4881 R1.A1, R1.A2, R2, R2.A1, ... */
4884 begin_reversible_command (Operations::paste);
4886 if (ts.size() == 1 && cut_buffer->lines.size() == 1 &&
4887 dynamic_cast<AutomationTimeAxisView*>(ts.front())) {
4888 /* Only one line copied, and one automation track selected. Do a
4889 "greedy" paste from one automation type to another. */
4891 PasteContext ctx(paste_count, times, ItemCounts(), true);
4892 ts.front()->paste (position, *cut_buffer, ctx, sub_num);
4896 /* Paste into tracks */
4898 PasteContext ctx(paste_count, times, ItemCounts(), false);
4899 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4900 (*i)->paste (position, *cut_buffer, ctx, sub_num);
4904 commit_reversible_command ();
4908 Editor::duplicate_regions (float times)
4910 RegionSelection rs (get_regions_from_selection_and_entered());
4911 duplicate_some_regions (rs, times);
4915 Editor::duplicate_some_regions (RegionSelection& regions, float times)
4917 if (regions.empty ()) {
4921 boost::shared_ptr<Playlist> playlist;
4922 RegionSelection sel = regions; // clear (below) may clear the argument list if its the current region selection
4923 RegionSelection foo;
4925 framepos_t const start_frame = regions.start ();
4926 framepos_t const end_frame = regions.end_frame ();
4927 framecnt_t const gap = end_frame - start_frame + 1;
4929 begin_reversible_command (Operations::duplicate_region);
4931 selection->clear_regions ();
4933 for (RegionSelection::iterator i = sel.begin(); i != sel.end(); ++i) {
4935 boost::shared_ptr<Region> r ((*i)->region());
4937 TimeAxisView& tv = (*i)->get_time_axis_view();
4938 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (&tv);
4939 latest_regionviews.clear ();
4940 sigc::connection c = rtv->view()->RegionViewAdded.connect (sigc::mem_fun(*this, &Editor::collect_new_region_view));
4942 framepos_t const position = end_frame + (r->first_frame() - start_frame + 1);
4943 playlist = (*i)->region()->playlist();
4944 playlist->clear_changes ();
4945 playlist->duplicate (r, position, gap, times);
4946 _session->add_command(new StatefulDiffCommand (playlist));
4950 foo.insert (foo.end(), latest_regionviews.begin(), latest_regionviews.end());
4954 selection->set (foo);
4957 commit_reversible_command ();
4961 Editor::duplicate_selection (float times)
4963 if (selection->time.empty() || selection->tracks.empty()) {
4967 boost::shared_ptr<Playlist> playlist;
4969 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4971 bool in_command = false;
4973 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4974 if ((playlist = (*i)->playlist()) == 0) {
4977 playlist->clear_changes ();
4979 if (clicked_selection) {
4980 playlist->duplicate_range (selection->time[clicked_selection], times);
4982 playlist->duplicate_ranges (selection->time, times);
4986 begin_reversible_command (_("duplicate range selection"));
4989 _session->add_command (new StatefulDiffCommand (playlist));
4994 if (times == 1.0f) {
4995 // now "move" range selection to after the current range selection
4996 framecnt_t distance = 0;
4998 if (clicked_selection) {
5000 selection->time[clicked_selection].end - selection->time[clicked_selection].start;
5002 distance = selection->time.end_frame () - selection->time.start ();
5005 selection->move_time (distance);
5007 commit_reversible_command ();
5011 /** Reset all selected points to the relevant default value */
5013 Editor::reset_point_selection ()
5015 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
5016 ARDOUR::AutomationList::iterator j = (*i)->model ();
5017 (*j)->value = (*i)->line().the_list()->descriptor ().normal;
5022 Editor::center_playhead ()
5024 float const page = _visible_canvas_width * samples_per_pixel;
5025 center_screen_internal (playhead_cursor->current_frame (), page);
5029 Editor::center_edit_point ()
5031 float const page = _visible_canvas_width * samples_per_pixel;
5032 center_screen_internal (get_preferred_edit_position(), page);
5035 /** Caller must begin and commit a reversible command */
5037 Editor::clear_playlist (boost::shared_ptr<Playlist> playlist)
5039 playlist->clear_changes ();
5041 _session->add_command (new StatefulDiffCommand (playlist));
5045 Editor::nudge_track (bool use_edit, bool forwards)
5047 boost::shared_ptr<Playlist> playlist;
5048 framepos_t distance;
5049 framepos_t next_distance;
5053 start = get_preferred_edit_position();
5058 if ((distance = get_nudge_distance (start, next_distance)) == 0) {
5062 if (selection->tracks.empty()) {
5066 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
5067 bool in_command = false;
5069 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
5071 if ((playlist = (*i)->playlist()) == 0) {
5075 playlist->clear_changes ();
5076 playlist->clear_owned_changes ();
5078 playlist->nudge_after (start, distance, forwards);
5081 begin_reversible_command (_("nudge track"));
5084 vector<Command*> cmds;
5086 playlist->rdiff (cmds);
5087 _session->add_commands (cmds);
5089 _session->add_command (new StatefulDiffCommand (playlist));
5093 commit_reversible_command ();
5098 Editor::remove_last_capture ()
5100 vector<string> choices;
5107 if (Config->get_verify_remove_last_capture()) {
5108 prompt = _("Do you really want to destroy the last capture?"
5109 "\n(This is destructive and cannot be undone)");
5111 choices.push_back (_("No, do nothing."));
5112 choices.push_back (_("Yes, destroy it."));
5114 Choice prompter (_("Destroy last capture"), prompt, choices);
5116 if (prompter.run () == 1) {
5117 _session->remove_last_capture ();
5118 _regions->redisplay ();
5122 _session->remove_last_capture();
5123 _regions->redisplay ();
5128 Editor::normalize_region ()
5134 RegionSelection rs = get_regions_from_selection_and_entered ();
5140 NormalizeDialog dialog (rs.size() > 1);
5142 if (dialog.run () != RESPONSE_ACCEPT) {
5146 CursorContext::Handle cursor_ctx = CursorContext::create(*this, _cursors->wait);
5149 /* XXX: should really only count audio regions here */
5150 int const regions = rs.size ();
5152 /* Make a list of the selected audio regions' maximum amplitudes, and also
5153 obtain the maximum amplitude of them all.
5155 list<double> max_amps;
5156 list<double> rms_vals;
5159 bool use_rms = dialog.constrain_rms ();
5161 for (RegionSelection::const_iterator i = rs.begin(); i != rs.end(); ++i) {
5162 AudioRegionView const * arv = dynamic_cast<AudioRegionView const *> (*i);
5166 dialog.descend (1.0 / regions);
5167 double const a = arv->audio_region()->maximum_amplitude (&dialog);
5169 double r = arv->audio_region()->rms (&dialog);
5170 max_rms = max (max_rms, r);
5171 rms_vals.push_back (r);
5175 /* the user cancelled the operation */
5179 max_amps.push_back (a);
5180 max_amp = max (max_amp, a);
5184 list<double>::const_iterator a = max_amps.begin ();
5185 list<double>::const_iterator l = rms_vals.begin ();
5186 bool in_command = false;
5188 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
5189 AudioRegionView* const arv = dynamic_cast<AudioRegionView*> (*r);
5194 arv->region()->clear_changes ();
5196 double amp = dialog.normalize_individually() ? *a : max_amp;
5197 double target = dialog.target_peak (); // dB
5200 double const amp_rms = dialog.normalize_individually() ? *l : max_rms;
5201 const double t_rms = dialog.target_rms ();
5202 const gain_t c_peak = dB_to_coefficient (target);
5203 const gain_t c_rms = dB_to_coefficient (t_rms);
5204 if ((amp_rms / c_rms) > (amp / c_peak)) {
5210 arv->audio_region()->normalize (amp, target);
5213 begin_reversible_command (_("normalize"));
5216 _session->add_command (new StatefulDiffCommand (arv->region()));
5223 commit_reversible_command ();
5229 Editor::reset_region_scale_amplitude ()
5235 RegionSelection rs = get_regions_from_selection_and_entered ();
5241 bool in_command = false;
5243 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
5244 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
5247 arv->region()->clear_changes ();
5248 arv->audio_region()->set_scale_amplitude (1.0f);
5251 begin_reversible_command ("reset gain");
5254 _session->add_command (new StatefulDiffCommand (arv->region()));
5258 commit_reversible_command ();
5263 Editor::adjust_region_gain (bool up)
5265 RegionSelection rs = get_regions_from_selection_and_entered ();
5267 if (!_session || rs.empty()) {
5271 bool in_command = false;
5273 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
5274 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
5279 arv->region()->clear_changes ();
5281 double dB = accurate_coefficient_to_dB (arv->audio_region()->scale_amplitude ());
5289 arv->audio_region()->set_scale_amplitude (dB_to_coefficient (dB));
5292 begin_reversible_command ("adjust region gain");
5295 _session->add_command (new StatefulDiffCommand (arv->region()));
5299 commit_reversible_command ();
5304 Editor::reset_region_gain ()
5306 RegionSelection rs = get_regions_from_selection_and_entered ();
5308 if (!_session || rs.empty()) {
5312 bool in_command = false;
5314 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
5315 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
5320 arv->region()->clear_changes ();
5322 arv->audio_region()->set_scale_amplitude (1.0f);
5325 begin_reversible_command ("reset region gain");
5328 _session->add_command (new StatefulDiffCommand (arv->region()));
5332 commit_reversible_command ();
5337 Editor::reverse_region ()
5343 Reverse rev (*_session);
5344 apply_filter (rev, _("reverse regions"));
5348 Editor::strip_region_silence ()
5354 RegionSelection rs = get_regions_from_selection_and_entered ();
5360 std::list<RegionView*> audio_only;
5362 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5363 AudioRegionView* const arv = dynamic_cast<AudioRegionView*> (*i);
5365 audio_only.push_back (arv);
5369 assert (!audio_only.empty());
5371 StripSilenceDialog d (_session, audio_only);
5372 int const r = d.run ();
5376 if (r == Gtk::RESPONSE_OK) {
5377 ARDOUR::AudioIntervalMap silences;
5378 d.silences (silences);
5379 StripSilence s (*_session, silences, d.fade_length());
5381 apply_filter (s, _("strip silence"), &d);
5386 Editor::apply_midi_note_edit_op_to_region (MidiOperator& op, MidiRegionView& mrv)
5388 Evoral::Sequence<Evoral::Beats>::Notes selected;
5389 mrv.selection_as_notelist (selected, true);
5391 vector<Evoral::Sequence<Evoral::Beats>::Notes> v;
5392 v.push_back (selected);
5394 Evoral::Beats pos_beats = Evoral::Beats (mrv.midi_region()->beat()) - mrv.midi_region()->start_beats();
5396 return op (mrv.midi_region()->model(), pos_beats, v);
5400 Editor::apply_midi_note_edit_op (MidiOperator& op, const RegionSelection& rs)
5406 bool in_command = false;
5408 for (RegionSelection::const_iterator r = rs.begin(); r != rs.end(); ) {
5409 RegionSelection::const_iterator tmp = r;
5412 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*r);
5415 Command* cmd = apply_midi_note_edit_op_to_region (op, *mrv);
5418 begin_reversible_command (op.name ());
5422 _session->add_command (cmd);
5430 commit_reversible_command ();
5435 Editor::fork_region ()
5437 RegionSelection rs = get_regions_from_selection_and_entered ();
5443 CursorContext::Handle cursor_ctx = CursorContext::create(*this, _cursors->wait);
5444 bool in_command = false;
5448 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
5449 RegionSelection::iterator tmp = r;
5452 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*>(*r);
5456 boost::shared_ptr<Playlist> playlist = mrv->region()->playlist();
5457 boost::shared_ptr<MidiSource> new_source = _session->create_midi_source_by_stealing_name (mrv->midi_view()->track());
5458 boost::shared_ptr<MidiRegion> newregion = mrv->midi_region()->clone (new_source);
5461 begin_reversible_command (_("Fork Region(s)"));
5464 playlist->clear_changes ();
5465 playlist->replace_region (mrv->region(), newregion, mrv->region()->position());
5466 _session->add_command(new StatefulDiffCommand (playlist));
5468 error << string_compose (_("Could not unlink %1"), mrv->region()->name()) << endmsg;
5476 commit_reversible_command ();
5481 Editor::quantize_region ()
5484 quantize_regions(get_regions_from_selection_and_entered ());
5489 Editor::quantize_regions (const RegionSelection& rs)
5491 if (rs.n_midi_regions() == 0) {
5495 if (!quantize_dialog) {
5496 quantize_dialog = new QuantizeDialog (*this);
5499 if (quantize_dialog->is_mapped()) {
5500 /* in progress already */
5504 quantize_dialog->present ();
5505 const int r = quantize_dialog->run ();
5506 quantize_dialog->hide ();
5508 if (r == Gtk::RESPONSE_OK) {
5509 Quantize quant (quantize_dialog->snap_start(),
5510 quantize_dialog->snap_end(),
5511 quantize_dialog->start_grid_size(),
5512 quantize_dialog->end_grid_size(),
5513 quantize_dialog->strength(),
5514 quantize_dialog->swing(),
5515 quantize_dialog->threshold());
5517 apply_midi_note_edit_op (quant, rs);
5522 Editor::legatize_region (bool shrink_only)
5525 legatize_regions(get_regions_from_selection_and_entered (), shrink_only);
5530 Editor::legatize_regions (const RegionSelection& rs, bool shrink_only)
5532 if (rs.n_midi_regions() == 0) {
5536 Legatize legatize(shrink_only);
5537 apply_midi_note_edit_op (legatize, rs);
5541 Editor::transform_region ()
5544 transform_regions(get_regions_from_selection_and_entered ());
5549 Editor::transform_regions (const RegionSelection& rs)
5551 if (rs.n_midi_regions() == 0) {
5558 const int r = td.run();
5561 if (r == Gtk::RESPONSE_OK) {
5562 Transform transform(td.get());
5563 apply_midi_note_edit_op(transform, rs);
5568 Editor::transpose_region ()
5571 transpose_regions(get_regions_from_selection_and_entered ());
5576 Editor::transpose_regions (const RegionSelection& rs)
5578 if (rs.n_midi_regions() == 0) {
5583 int const r = d.run ();
5585 if (r == RESPONSE_ACCEPT) {
5586 Transpose transpose(d.semitones ());
5587 apply_midi_note_edit_op (transpose, rs);
5592 Editor::insert_patch_change (bool from_context)
5594 RegionSelection rs = get_regions_from_selection_and_entered ();
5600 const framepos_t p = get_preferred_edit_position (EDIT_IGNORE_NONE, from_context);
5602 /* XXX: bit of a hack; use the MIDNAM from the first selected region;
5603 there may be more than one, but the PatchChangeDialog can only offer
5604 one set of patch menus.
5606 MidiRegionView* first = dynamic_cast<MidiRegionView*> (rs.front ());
5608 Evoral::PatchChange<Evoral::Beats> empty (Evoral::Beats(), 0, 0, 0);
5609 PatchChangeDialog d (0, _session, empty, first->instrument_info(), Gtk::Stock::ADD);
5611 if (d.run() == RESPONSE_CANCEL) {
5615 for (RegionSelection::iterator i = rs.begin (); i != rs.end(); ++i) {
5616 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*i);
5618 if (p >= mrv->region()->first_frame() && p <= mrv->region()->last_frame()) {
5619 mrv->add_patch_change (p - mrv->region()->position(), d.patch ());
5626 Editor::apply_filter (Filter& filter, string command, ProgressReporter* progress)
5628 RegionSelection rs = get_regions_from_selection_and_entered ();
5634 CursorContext::Handle cursor_ctx = CursorContext::create(*this, _cursors->wait);
5635 bool in_command = false;
5640 int const N = rs.size ();
5642 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
5643 RegionSelection::iterator tmp = r;
5646 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
5648 boost::shared_ptr<Playlist> playlist = arv->region()->playlist();
5651 progress->descend (1.0 / N);
5654 if (arv->audio_region()->apply (filter, progress) == 0) {
5656 playlist->clear_changes ();
5657 playlist->clear_owned_changes ();
5660 begin_reversible_command (command);
5664 if (filter.results.empty ()) {
5666 /* no regions returned; remove the old one */
5667 playlist->remove_region (arv->region ());
5671 std::vector<boost::shared_ptr<Region> >::iterator res = filter.results.begin ();
5673 /* first region replaces the old one */
5674 playlist->replace_region (arv->region(), *res, (*res)->position());
5678 while (res != filter.results.end()) {
5679 playlist->add_region (*res, (*res)->position());
5685 /* We might have removed regions, which alters other regions' layering_index,
5686 so we need to do a recursive diff here.
5688 vector<Command*> cmds;
5689 playlist->rdiff (cmds);
5690 _session->add_commands (cmds);
5692 _session->add_command(new StatefulDiffCommand (playlist));
5696 progress->ascend ();
5705 commit_reversible_command ();
5710 Editor::external_edit_region ()
5716 Editor::reset_region_gain_envelopes ()
5718 RegionSelection rs = get_regions_from_selection_and_entered ();
5720 if (!_session || rs.empty()) {
5724 bool in_command = false;
5726 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5727 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
5729 boost::shared_ptr<AutomationList> alist (arv->audio_region()->envelope());
5730 XMLNode& before (alist->get_state());
5732 arv->audio_region()->set_default_envelope ();
5735 begin_reversible_command (_("reset region gain"));
5738 _session->add_command (new MementoCommand<AutomationList>(*arv->audio_region()->envelope().get(), &before, &alist->get_state()));
5743 commit_reversible_command ();
5748 Editor::set_region_gain_visibility (RegionView* rv)
5750 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (rv);
5752 arv->update_envelope_visibility();
5757 Editor::set_gain_envelope_visibility ()
5763 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5764 AudioTimeAxisView* v = dynamic_cast<AudioTimeAxisView*>(*i);
5766 v->audio_view()->foreach_regionview (sigc::mem_fun (this, &Editor::set_region_gain_visibility));
5772 Editor::toggle_gain_envelope_active ()
5774 if (_ignore_region_action) {
5778 RegionSelection rs = get_regions_from_selection_and_entered ();
5780 if (!_session || rs.empty()) {
5784 bool in_command = false;
5786 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5787 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
5789 arv->region()->clear_changes ();
5790 arv->audio_region()->set_envelope_active (!arv->audio_region()->envelope_active());
5793 begin_reversible_command (_("region gain envelope active"));
5796 _session->add_command (new StatefulDiffCommand (arv->region()));
5801 commit_reversible_command ();
5806 Editor::toggle_region_lock ()
5808 if (_ignore_region_action) {
5812 RegionSelection rs = get_regions_from_selection_and_entered ();
5814 if (!_session || rs.empty()) {
5818 begin_reversible_command (_("toggle region lock"));
5820 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5821 (*i)->region()->clear_changes ();
5822 (*i)->region()->set_locked (!(*i)->region()->locked());
5823 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5826 commit_reversible_command ();
5830 Editor::toggle_region_video_lock ()
5832 if (_ignore_region_action) {
5836 RegionSelection rs = get_regions_from_selection_and_entered ();
5838 if (!_session || rs.empty()) {
5842 begin_reversible_command (_("Toggle Video Lock"));
5844 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5845 (*i)->region()->clear_changes ();
5846 (*i)->region()->set_video_locked (!(*i)->region()->video_locked());
5847 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5850 commit_reversible_command ();
5854 Editor::toggle_region_lock_style ()
5856 if (_ignore_region_action) {
5860 RegionSelection rs = get_regions_from_selection_and_entered ();
5862 if (!_session || rs.empty()) {
5866 Glib::RefPtr<ToggleAction> a = Glib::RefPtr<ToggleAction>::cast_dynamic (_region_actions->get_action("toggle-region-lock-style"));
5867 vector<Widget*> proxies = a->get_proxies();
5868 Gtk::CheckMenuItem* cmi = dynamic_cast<Gtk::CheckMenuItem*> (proxies.front());
5872 begin_reversible_command (_("toggle region lock style"));
5874 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5875 (*i)->region()->clear_changes ();
5876 PositionLockStyle const ns = ((*i)->region()->position_lock_style() == AudioTime && !cmi->get_inconsistent()) ? MusicTime : AudioTime;
5877 (*i)->region()->set_position_lock_style (ns);
5878 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5881 commit_reversible_command ();
5885 Editor::toggle_opaque_region ()
5887 if (_ignore_region_action) {
5891 RegionSelection rs = get_regions_from_selection_and_entered ();
5893 if (!_session || rs.empty()) {
5897 begin_reversible_command (_("change region opacity"));
5899 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5900 (*i)->region()->clear_changes ();
5901 (*i)->region()->set_opaque (!(*i)->region()->opaque());
5902 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5905 commit_reversible_command ();
5909 Editor::toggle_record_enable ()
5911 bool new_state = false;
5913 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5914 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5917 if (!rtav->is_track())
5921 new_state = !rtav->track()->rec_enable_control()->get_value();
5925 rtav->track()->rec_enable_control()->set_value (new_state, Controllable::UseGroup);
5930 Editor::toggle_solo ()
5932 bool new_state = false;
5934 boost::shared_ptr<ControlList> cl (new ControlList);
5936 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5937 StripableTimeAxisView *stav = dynamic_cast<StripableTimeAxisView *>(*i);
5939 if (!stav || !stav->stripable()->solo_control()) {
5944 new_state = !stav->stripable()->solo_control()->soloed ();
5948 cl->push_back (stav->stripable()->solo_control());
5951 _session->set_controls (cl, new_state ? 1.0 : 0.0, Controllable::UseGroup);
5955 Editor::toggle_mute ()
5957 bool new_state = false;
5961 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5962 StripableTimeAxisView *stav = dynamic_cast<StripableTimeAxisView *>(*i);
5964 if (!stav || !stav->stripable()->mute_control()) {
5969 new_state = !stav->stripable()->mute_control()->muted();
5973 sl.push_back (stav->stripable());
5976 _session->set_controls (stripable_list_to_control_list (sl, &Stripable::mute_control), new_state, Controllable::UseGroup);
5980 Editor::toggle_solo_isolate ()
5986 Editor::fade_range ()
5988 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
5990 begin_reversible_command (_("fade range"));
5992 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
5993 (*i)->fade_range (selection->time);
5996 commit_reversible_command ();
6001 Editor::set_fade_length (bool in)
6003 RegionSelection rs = get_regions_from_selection_and_entered ();
6009 /* we need a region to measure the offset from the start */
6011 RegionView* rv = rs.front ();
6013 framepos_t pos = get_preferred_edit_position();
6017 if (pos > rv->region()->last_frame() || pos < rv->region()->first_frame()) {
6018 /* edit point is outside the relevant region */
6023 if (pos <= rv->region()->position()) {
6027 len = pos - rv->region()->position();
6028 cmd = _("set fade in length");
6030 if (pos >= rv->region()->last_frame()) {
6034 len = rv->region()->last_frame() - pos;
6035 cmd = _("set fade out length");
6038 bool in_command = false;
6040 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
6041 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
6047 boost::shared_ptr<AutomationList> alist;
6049 alist = tmp->audio_region()->fade_in();
6051 alist = tmp->audio_region()->fade_out();
6054 XMLNode &before = alist->get_state();
6057 tmp->audio_region()->set_fade_in_length (len);
6058 tmp->audio_region()->set_fade_in_active (true);
6060 tmp->audio_region()->set_fade_out_length (len);
6061 tmp->audio_region()->set_fade_out_active (true);
6065 begin_reversible_command (cmd);
6068 XMLNode &after = alist->get_state();
6069 _session->add_command(new MementoCommand<AutomationList>(*alist, &before, &after));
6073 commit_reversible_command ();
6078 Editor::set_fade_in_shape (FadeShape shape)
6080 RegionSelection rs = get_regions_from_selection_and_entered ();
6085 bool in_command = false;
6087 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
6088 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
6094 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_in();
6095 XMLNode &before = alist->get_state();
6097 tmp->audio_region()->set_fade_in_shape (shape);
6100 begin_reversible_command (_("set fade in shape"));
6103 XMLNode &after = alist->get_state();
6104 _session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
6108 commit_reversible_command ();
6113 Editor::set_fade_out_shape (FadeShape shape)
6115 RegionSelection rs = get_regions_from_selection_and_entered ();
6120 bool in_command = false;
6122 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
6123 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
6129 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_out();
6130 XMLNode &before = alist->get_state();
6132 tmp->audio_region()->set_fade_out_shape (shape);
6135 begin_reversible_command (_("set fade out shape"));
6138 XMLNode &after = alist->get_state();
6139 _session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
6143 commit_reversible_command ();
6148 Editor::set_fade_in_active (bool yn)
6150 RegionSelection rs = get_regions_from_selection_and_entered ();
6155 bool in_command = false;
6157 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
6158 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
6165 boost::shared_ptr<AudioRegion> ar (tmp->audio_region());
6167 ar->clear_changes ();
6168 ar->set_fade_in_active (yn);
6171 begin_reversible_command (_("set fade in active"));
6174 _session->add_command (new StatefulDiffCommand (ar));
6178 commit_reversible_command ();
6183 Editor::set_fade_out_active (bool yn)
6185 RegionSelection rs = get_regions_from_selection_and_entered ();
6190 bool in_command = false;
6192 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
6193 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
6199 boost::shared_ptr<AudioRegion> ar (tmp->audio_region());
6201 ar->clear_changes ();
6202 ar->set_fade_out_active (yn);
6205 begin_reversible_command (_("set fade out active"));
6208 _session->add_command(new StatefulDiffCommand (ar));
6212 commit_reversible_command ();
6217 Editor::toggle_region_fades (int dir)
6219 if (_ignore_region_action) {
6223 boost::shared_ptr<AudioRegion> ar;
6226 RegionSelection rs = get_regions_from_selection_and_entered ();
6232 RegionSelection::iterator i;
6233 for (i = rs.begin(); i != rs.end(); ++i) {
6234 if ((ar = boost::dynamic_pointer_cast<AudioRegion>((*i)->region())) != 0) {
6236 yn = ar->fade_out_active ();
6238 yn = ar->fade_in_active ();
6244 if (i == rs.end()) {
6248 /* XXX should this undo-able? */
6249 bool in_command = false;
6251 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
6252 if ((ar = boost::dynamic_pointer_cast<AudioRegion>((*i)->region())) == 0) {
6255 ar->clear_changes ();
6257 if (dir == 1 || dir == 0) {
6258 ar->set_fade_in_active (!yn);
6261 if (dir == -1 || dir == 0) {
6262 ar->set_fade_out_active (!yn);
6265 begin_reversible_command (_("toggle fade active"));
6268 _session->add_command(new StatefulDiffCommand (ar));
6272 commit_reversible_command ();
6277 /** Update region fade visibility after its configuration has been changed */
6279 Editor::update_region_fade_visibility ()
6281 bool _fade_visibility = _session->config.get_show_region_fades ();
6283 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
6284 AudioTimeAxisView* v = dynamic_cast<AudioTimeAxisView*>(*i);
6286 if (_fade_visibility) {
6287 v->audio_view()->show_all_fades ();
6289 v->audio_view()->hide_all_fades ();
6296 Editor::set_edit_point ()
6299 MusicFrame where (0, 0);
6301 if (!mouse_frame (where.frame, ignored)) {
6307 if (selection->markers.empty()) {
6309 mouse_add_new_marker (where.frame);
6314 Location* loc = find_location_from_marker (selection->markers.front(), ignored);
6317 loc->move_to (where.frame, where.division);
6323 Editor::set_playhead_cursor ()
6325 if (entered_marker) {
6326 _session->request_locate (entered_marker->position(), _session->transport_rolling());
6328 MusicFrame where (0, 0);
6331 if (!mouse_frame (where.frame, ignored)) {
6338 _session->request_locate (where.frame, _session->transport_rolling());
6342 //not sure what this was for; remove it for now.
6343 // if (UIConfiguration::instance().get_follow_edits() && (!_session || !_session->config.get_external_sync())) {
6344 // cancel_time_selection();
6350 Editor::split_region ()
6352 if (_drags->active ()) {
6356 //if a range is selected, separate it
6357 if ( !selection->time.empty()) {
6358 separate_regions_between (selection->time);
6362 //if no range was selected, try to find some regions to split
6363 if (current_mouse_mode() == MouseObject) { //don't try this for Internal Edit, Stretch, Draw, etc.
6365 RegionSelection rs = get_regions_from_selection_and_edit_point ();
6366 const framepos_t pos = get_preferred_edit_position();
6367 const int32_t division = get_grid_music_divisions (0);
6368 MusicFrame where (pos, division);
6374 split_regions_at (where, rs);
6380 Editor::select_next_stripable (bool routes_only)
6382 if (selection->tracks.empty()) {
6383 selection->set (track_views.front());
6387 TimeAxisView* current = selection->tracks.front();
6391 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
6393 if (*i == current) {
6395 if (i != track_views.end()) {
6398 current = (*(track_views.begin()));
6399 //selection->set (*(track_views.begin()));
6406 RouteUI* rui = dynamic_cast<RouteUI *>(current);
6407 valid = rui && rui->route()->active();
6409 valid = 0 != current->stripable ().get();
6412 } while (current->hidden() || !valid);
6414 selection->set (current);
6416 ensure_time_axis_view_is_visible (*current, false);
6420 Editor::select_prev_stripable (bool routes_only)
6422 if (selection->tracks.empty()) {
6423 selection->set (track_views.front());
6427 TimeAxisView* current = selection->tracks.front();
6431 for (TrackViewList::reverse_iterator i = track_views.rbegin(); i != track_views.rend(); ++i) {
6433 if (*i == current) {
6435 if (i != track_views.rend()) {
6438 current = *(track_views.rbegin());
6444 RouteUI* rui = dynamic_cast<RouteUI *>(current);
6445 valid = rui && rui->route()->active();
6447 valid = 0 != current->stripable ().get();
6450 } while (current->hidden() || !valid);
6452 selection->set (current);
6454 ensure_time_axis_view_is_visible (*current, false);
6458 Editor::set_loop_from_selection (bool play)
6460 if (_session == 0) {
6464 framepos_t start, end;
6465 if (!get_selection_extents ( start, end))
6468 set_loop_range (start, end, _("set loop range from selection"));
6471 _session->request_play_loop (true, true);
6476 Editor::set_loop_from_region (bool play)
6478 framepos_t start, end;
6479 if (!get_selection_extents ( start, end))
6482 set_loop_range (start, end, _("set loop range from region"));
6485 _session->request_locate (start, true);
6486 _session->request_play_loop (true);
6491 Editor::set_punch_from_selection ()
6493 if (_session == 0) {
6497 framepos_t start, end;
6498 if (!get_selection_extents ( start, end))
6501 set_punch_range (start, end, _("set punch range from selection"));
6505 Editor::set_auto_punch_range ()
6507 // auto punch in/out button from a single button
6508 // If Punch In is unset, set punch range from playhead to end, enable punch in
6509 // If Punch In is set, the next punch sets Punch Out, unless the playhead has been
6510 // rewound beyond the Punch In marker, in which case that marker will be moved back
6511 // to the current playhead position.
6512 // If punch out is set, it clears the punch range and Punch In/Out buttons
6514 if (_session == 0) {
6518 Location* tpl = transport_punch_location();
6519 framepos_t now = playhead_cursor->current_frame();
6520 framepos_t begin = now;
6521 framepos_t end = _session->current_end_frame();
6523 if (!_session->config.get_punch_in()) {
6524 // First Press - set punch in and create range from here to eternity
6525 set_punch_range (begin, end, _("Auto Punch In"));
6526 _session->config.set_punch_in(true);
6527 } else if (tpl && !_session->config.get_punch_out()) {
6528 // Second press - update end range marker and set punch_out
6529 if (now < tpl->start()) {
6530 // playhead has been rewound - move start back and pretend nothing happened
6532 set_punch_range (begin, end, _("Auto Punch In/Out"));
6534 // normal case for 2nd press - set the punch out
6535 end = playhead_cursor->current_frame ();
6536 set_punch_range (tpl->start(), now, _("Auto Punch In/Out"));
6537 _session->config.set_punch_out(true);
6540 if (_session->config.get_punch_out()) {
6541 _session->config.set_punch_out(false);
6544 if (_session->config.get_punch_in()) {
6545 _session->config.set_punch_in(false);
6550 // third press - unset punch in/out and remove range
6551 _session->locations()->remove(tpl);
6558 Editor::set_session_extents_from_selection ()
6560 if (_session == 0) {
6564 framepos_t start, end;
6565 if (!get_selection_extents ( start, end))
6569 if ((loc = _session->locations()->session_range_location()) == 0) {
6570 _session->set_session_extents (start, end); // this will create a new session range; no need for UNDO
6572 XMLNode &before = loc->get_state();
6574 _session->set_session_extents (start, end);
6576 XMLNode &after = loc->get_state();
6578 begin_reversible_command (_("set session start/end from selection"));
6580 _session->add_command (new MementoCommand<Location>(*loc, &before, &after));
6582 commit_reversible_command ();
6585 _session->set_end_is_free (false);
6589 Editor::set_punch_start_from_edit_point ()
6593 MusicFrame start (0, 0);
6594 framepos_t end = max_framepos;
6596 //use the existing punch end, if any
6597 Location* tpl = transport_punch_location();
6602 if ((_edit_point == EditAtPlayhead) && _session->transport_rolling()) {
6603 start.frame = _session->audible_frame();
6605 start.frame = get_preferred_edit_position();
6608 //snap the selection start/end
6611 //if there's not already a sensible selection endpoint, go "forever"
6612 if (start.frame > end ) {
6616 set_punch_range (start.frame, end, _("set punch start from EP"));
6622 Editor::set_punch_end_from_edit_point ()
6626 framepos_t start = 0;
6627 MusicFrame end (max_framepos, 0);
6629 //use the existing punch start, if any
6630 Location* tpl = transport_punch_location();
6632 start = tpl->start();
6635 if ((_edit_point == EditAtPlayhead) && _session->transport_rolling()) {
6636 end.frame = _session->audible_frame();
6638 end.frame = get_preferred_edit_position();
6641 //snap the selection start/end
6644 set_punch_range (start, end.frame, _("set punch end from EP"));
6650 Editor::set_loop_start_from_edit_point ()
6654 MusicFrame start (0, 0);
6655 framepos_t end = max_framepos;
6657 //use the existing loop end, if any
6658 Location* tpl = transport_loop_location();
6663 if ((_edit_point == EditAtPlayhead) && _session->transport_rolling()) {
6664 start.frame = _session->audible_frame();
6666 start.frame = get_preferred_edit_position();
6669 //snap the selection start/end
6672 //if there's not already a sensible selection endpoint, go "forever"
6673 if (start.frame > end ) {
6677 set_loop_range (start.frame, end, _("set loop start from EP"));
6683 Editor::set_loop_end_from_edit_point ()
6687 framepos_t start = 0;
6688 MusicFrame end (max_framepos, 0);
6690 //use the existing loop start, if any
6691 Location* tpl = transport_loop_location();
6693 start = tpl->start();
6696 if ((_edit_point == EditAtPlayhead) && _session->transport_rolling()) {
6697 end.frame = _session->audible_frame();
6699 end.frame = get_preferred_edit_position();
6702 //snap the selection start/end
6705 set_loop_range (start, end.frame, _("set loop end from EP"));
6710 Editor::set_punch_from_region ()
6712 framepos_t start, end;
6713 if (!get_selection_extents ( start, end))
6716 set_punch_range (start, end, _("set punch range from region"));
6720 Editor::pitch_shift_region ()
6722 RegionSelection rs = get_regions_from_selection_and_entered ();
6724 RegionSelection audio_rs;
6725 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
6726 if (dynamic_cast<AudioRegionView*> (*i)) {
6727 audio_rs.push_back (*i);
6731 if (audio_rs.empty()) {
6735 pitch_shift (audio_rs, 1.2);
6739 Editor::set_tempo_from_region ()
6741 RegionSelection rs = get_regions_from_selection_and_entered ();
6743 if (!_session || rs.empty()) {
6747 RegionView* rv = rs.front();
6749 define_one_bar (rv->region()->position(), rv->region()->last_frame() + 1);
6753 Editor::use_range_as_bar ()
6755 framepos_t start, end;
6756 if (get_edit_op_range (start, end)) {
6757 define_one_bar (start, end);
6762 Editor::define_one_bar (framepos_t start, framepos_t end)
6764 framepos_t length = end - start;
6766 const Meter& m (_session->tempo_map().meter_at_frame (start));
6768 /* length = 1 bar */
6770 /* We're going to deliver a constant tempo here,
6771 so we can use frames per beat to determine length.
6772 now we want frames per beat.
6773 we have frames per bar, and beats per bar, so ...
6776 /* XXXX METER MATH */
6778 double frames_per_beat = length / m.divisions_per_bar();
6780 /* beats per minute = */
6782 double beats_per_minute = (_session->frame_rate() * 60.0) / frames_per_beat;
6784 /* now decide whether to:
6786 (a) set global tempo
6787 (b) add a new tempo marker
6791 const TempoSection& t (_session->tempo_map().tempo_section_at_frame (start));
6793 bool do_global = false;
6795 if ((_session->tempo_map().n_tempos() == 1) && (_session->tempo_map().n_meters() == 1)) {
6797 /* only 1 tempo & 1 meter: ask if the user wants to set the tempo
6798 at the start, or create a new marker
6801 vector<string> options;
6802 options.push_back (_("Cancel"));
6803 options.push_back (_("Add new marker"));
6804 options.push_back (_("Set global tempo"));
6807 _("Define one bar"),
6808 _("Do you want to set the global tempo or add a new tempo marker?"),
6812 c.set_default_response (2);
6828 /* more than 1 tempo and/or meter section already, go ahead do the "usual":
6829 if the marker is at the region starter, change it, otherwise add
6834 begin_reversible_command (_("set tempo from region"));
6835 XMLNode& before (_session->tempo_map().get_state());
6838 _session->tempo_map().change_initial_tempo (beats_per_minute, t.note_type(), t.end_note_types_per_minute());
6839 } else if (t.frame() == start) {
6840 _session->tempo_map().change_existing_tempo_at (start, beats_per_minute, t.note_type(), t.end_note_types_per_minute());
6842 /* constant tempo */
6843 const Tempo tempo (beats_per_minute, t.note_type());
6844 _session->tempo_map().add_tempo (tempo, 0.0, start, AudioTime);
6847 XMLNode& after (_session->tempo_map().get_state());
6849 _session->add_command (new MementoCommand<TempoMap>(_session->tempo_map(), &before, &after));
6850 commit_reversible_command ();
6854 Editor::split_region_at_transients ()
6856 AnalysisFeatureList positions;
6858 RegionSelection rs = get_regions_from_selection_and_entered ();
6860 if (!_session || rs.empty()) {
6864 begin_reversible_command (_("split regions"));
6866 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ) {
6868 RegionSelection::iterator tmp;
6873 boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion> ((*i)->region());
6876 ar->transients (positions);
6877 split_region_at_points ((*i)->region(), positions, true);
6884 commit_reversible_command ();
6889 Editor::split_region_at_points (boost::shared_ptr<Region> r, AnalysisFeatureList& positions, bool can_ferret, bool select_new)
6891 bool use_rhythmic_rodent = false;
6893 boost::shared_ptr<Playlist> pl = r->playlist();
6895 list<boost::shared_ptr<Region> > new_regions;
6901 if (positions.empty()) {
6905 if (positions.size() > 20 && can_ferret) {
6906 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);
6907 MessageDialog msg (msgstr,
6910 Gtk::BUTTONS_OK_CANCEL);
6913 msg.add_button (_("Call for the Ferret!"), RESPONSE_APPLY);
6914 msg.set_secondary_text (_("Press OK to continue with this split operation\nor ask the Ferret dialog to tune the analysis"));
6916 msg.set_secondary_text (_("Press OK to continue with this split operation"));
6919 msg.set_title (_("Excessive split?"));
6922 int response = msg.run();
6928 case RESPONSE_APPLY:
6929 use_rhythmic_rodent = true;
6936 if (use_rhythmic_rodent) {
6937 show_rhythm_ferret ();
6941 AnalysisFeatureList::const_iterator x;
6943 pl->clear_changes ();
6944 pl->clear_owned_changes ();
6946 x = positions.begin();
6948 if (x == positions.end()) {
6953 pl->remove_region (r);
6957 framepos_t rstart = r->first_frame ();
6958 framepos_t rend = r->last_frame ();
6960 while (x != positions.end()) {
6962 /* deal with positons that are out of scope of present region bounds */
6963 if (*x <= rstart || *x > rend) {
6968 /* file start = original start + how far we from the initial position ? */
6970 framepos_t file_start = r->start() + pos;
6972 /* length = next position - current position */
6974 framepos_t len = (*x) - pos - rstart;
6976 /* XXX we do we really want to allow even single-sample regions?
6977 * shouldn't we have some kind of lower limit on region size?
6986 if (RegionFactory::region_name (new_name, r->name())) {
6990 /* do NOT announce new regions 1 by one, just wait till they are all done */
6994 plist.add (ARDOUR::Properties::start, file_start);
6995 plist.add (ARDOUR::Properties::length, len);
6996 plist.add (ARDOUR::Properties::name, new_name);
6997 plist.add (ARDOUR::Properties::layer, 0);
6998 // TODO set transients_offset
7000 boost::shared_ptr<Region> nr = RegionFactory::create (r->sources(), plist, false);
7001 /* because we set annouce to false, manually add the new region to the
7004 RegionFactory::map_add (nr);
7006 pl->add_region (nr, rstart + pos);
7009 new_regions.push_front(nr);
7018 RegionFactory::region_name (new_name, r->name());
7020 /* Add the final region */
7023 plist.add (ARDOUR::Properties::start, r->start() + pos);
7024 plist.add (ARDOUR::Properties::length, r->last_frame() - (r->position() + pos) + 1);
7025 plist.add (ARDOUR::Properties::name, new_name);
7026 plist.add (ARDOUR::Properties::layer, 0);
7028 boost::shared_ptr<Region> nr = RegionFactory::create (r->sources(), plist, false);
7029 /* because we set annouce to false, manually add the new region to the
7032 RegionFactory::map_add (nr);
7033 pl->add_region (nr, r->position() + pos);
7036 new_regions.push_front(nr);
7041 /* We might have removed regions, which alters other regions' layering_index,
7042 so we need to do a recursive diff here.
7044 vector<Command*> cmds;
7046 _session->add_commands (cmds);
7048 _session->add_command (new StatefulDiffCommand (pl));
7052 for (list<boost::shared_ptr<Region> >::iterator i = new_regions.begin(); i != new_regions.end(); ++i){
7053 set_selected_regionview_from_region_list ((*i), Selection::Add);
7059 Editor::place_transient()
7065 RegionSelection rs = get_regions_from_selection_and_edit_point ();
7071 framepos_t where = get_preferred_edit_position();
7073 begin_reversible_command (_("place transient"));
7075 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
7076 (*r)->region()->add_transient(where);
7079 commit_reversible_command ();
7083 Editor::remove_transient(ArdourCanvas::Item* item)
7089 ArdourCanvas::Line* _line = reinterpret_cast<ArdourCanvas::Line*> (item);
7092 AudioRegionView* _arv = reinterpret_cast<AudioRegionView*> (item->get_data ("regionview"));
7093 _arv->remove_transient (*(float*) _line->get_data ("position"));
7097 Editor::snap_regions_to_grid ()
7099 list <boost::shared_ptr<Playlist > > used_playlists;
7101 RegionSelection rs = get_regions_from_selection_and_entered ();
7103 if (!_session || rs.empty()) {
7107 begin_reversible_command (_("snap regions to grid"));
7109 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
7111 boost::shared_ptr<Playlist> pl = (*r)->region()->playlist();
7113 if (!pl->frozen()) {
7114 /* we haven't seen this playlist before */
7116 /* remember used playlists so we can thaw them later */
7117 used_playlists.push_back(pl);
7120 (*r)->region()->clear_changes ();
7122 MusicFrame start ((*r)->region()->first_frame (), 0);
7124 (*r)->region()->set_position (start.frame, start.division);
7125 _session->add_command(new StatefulDiffCommand ((*r)->region()));
7128 while (used_playlists.size() > 0) {
7129 list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
7131 used_playlists.pop_front();
7134 commit_reversible_command ();
7138 Editor::close_region_gaps ()
7140 list <boost::shared_ptr<Playlist > > used_playlists;
7142 RegionSelection rs = get_regions_from_selection_and_entered ();
7144 if (!_session || rs.empty()) {
7148 Dialog dialog (_("Close Region Gaps"));
7151 table.set_spacings (12);
7152 table.set_border_width (12);
7153 Label* l = manage (left_aligned_label (_("Crossfade length")));
7154 table.attach (*l, 0, 1, 0, 1);
7156 SpinButton spin_crossfade (1, 0);
7157 spin_crossfade.set_range (0, 15);
7158 spin_crossfade.set_increments (1, 1);
7159 spin_crossfade.set_value (5);
7160 table.attach (spin_crossfade, 1, 2, 0, 1);
7162 table.attach (*manage (new Label (_("ms"))), 2, 3, 0, 1);
7164 l = manage (left_aligned_label (_("Pull-back length")));
7165 table.attach (*l, 0, 1, 1, 2);
7167 SpinButton spin_pullback (1, 0);
7168 spin_pullback.set_range (0, 100);
7169 spin_pullback.set_increments (1, 1);
7170 spin_pullback.set_value(30);
7171 table.attach (spin_pullback, 1, 2, 1, 2);
7173 table.attach (*manage (new Label (_("ms"))), 2, 3, 1, 2);
7175 dialog.get_vbox()->pack_start (table);
7176 dialog.add_button (Stock::CANCEL, RESPONSE_CANCEL);
7177 dialog.add_button (_("Ok"), RESPONSE_ACCEPT);
7180 if (dialog.run () == RESPONSE_CANCEL) {
7184 framepos_t crossfade_len = spin_crossfade.get_value();
7185 framepos_t pull_back_frames = spin_pullback.get_value();
7187 crossfade_len = lrintf (crossfade_len * _session->frame_rate()/1000);
7188 pull_back_frames = lrintf (pull_back_frames * _session->frame_rate()/1000);
7190 /* Iterate over the region list and make adjacent regions overlap by crossfade_len_ms */
7192 begin_reversible_command (_("close region gaps"));
7195 boost::shared_ptr<Region> last_region;
7197 rs.sort_by_position_and_track();
7199 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
7201 boost::shared_ptr<Playlist> pl = (*r)->region()->playlist();
7203 if (!pl->frozen()) {
7204 /* we haven't seen this playlist before */
7206 /* remember used playlists so we can thaw them later */
7207 used_playlists.push_back(pl);
7211 framepos_t position = (*r)->region()->position();
7213 if (idx == 0 || position < last_region->position()){
7214 last_region = (*r)->region();
7219 (*r)->region()->clear_changes ();
7220 (*r)->region()->trim_front( (position - pull_back_frames));
7222 last_region->clear_changes ();
7223 last_region->trim_end( (position - pull_back_frames + crossfade_len));
7225 _session->add_command (new StatefulDiffCommand ((*r)->region()));
7226 _session->add_command (new StatefulDiffCommand (last_region));
7228 last_region = (*r)->region();
7232 while (used_playlists.size() > 0) {
7233 list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
7235 used_playlists.pop_front();
7238 commit_reversible_command ();
7242 Editor::tab_to_transient (bool forward)
7244 AnalysisFeatureList positions;
7246 RegionSelection rs = get_regions_from_selection_and_entered ();
7252 framepos_t pos = _session->audible_frame ();
7254 if (!selection->tracks.empty()) {
7256 /* don't waste time searching for transients in duplicate playlists.
7259 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
7261 for (TrackViewList::iterator t = ts.begin(); t != ts.end(); ++t) {
7263 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*t);
7266 boost::shared_ptr<Track> tr = rtv->track();
7268 boost::shared_ptr<Playlist> pl = tr->playlist ();
7270 framepos_t result = pl->find_next_transient (pos, forward ? 1 : -1);
7273 positions.push_back (result);
7286 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
7287 (*r)->region()->get_transients (positions);
7291 TransientDetector::cleanup_transients (positions, _session->frame_rate(), 3.0);
7294 AnalysisFeatureList::iterator x;
7296 for (x = positions.begin(); x != positions.end(); ++x) {
7302 if (x != positions.end ()) {
7303 _session->request_locate (*x);
7307 AnalysisFeatureList::reverse_iterator x;
7309 for (x = positions.rbegin(); x != positions.rend(); ++x) {
7315 if (x != positions.rend ()) {
7316 _session->request_locate (*x);
7322 Editor::playhead_forward_to_grid ()
7328 MusicFrame pos (playhead_cursor->current_frame (), 0);
7330 if (pos.frame < max_framepos - 1) {
7332 snap_to_internal (pos, RoundUpAlways, false, true);
7333 _session->request_locate (pos.frame);
7339 Editor::playhead_backward_to_grid ()
7345 MusicFrame pos (playhead_cursor->current_frame (), 0);
7347 if (pos.frame > 2) {
7349 snap_to_internal (pos, RoundDownAlways, false, true);
7350 _session->request_locate (pos.frame);
7355 Editor::set_track_height (Height h)
7357 TrackSelection& ts (selection->tracks);
7359 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
7360 (*x)->set_height_enum (h);
7365 Editor::toggle_tracks_active ()
7367 TrackSelection& ts (selection->tracks);
7369 bool target = false;
7375 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
7376 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*x);
7380 target = !rtv->_route->active();
7383 rtv->_route->set_active (target, this);
7389 Editor::remove_tracks ()
7391 /* this will delete GUI objects that may be the subject of an event
7392 handler in which this method is called. Defer actual deletion to the
7393 next idle callback, when all event handling is finished.
7395 Glib::signal_idle().connect (sigc::mem_fun (*this, &Editor::idle_remove_tracks));
7399 Editor::idle_remove_tracks ()
7401 Session::StateProtector sp (_session);
7403 return false; /* do not call again */
7407 Editor::_remove_tracks ()
7409 TrackSelection& ts (selection->tracks);
7415 vector<string> choices;
7420 const char* trackstr;
7423 vector<boost::shared_ptr<Route> > routes;
7424 vector<boost::shared_ptr<VCA> > vcas;
7425 bool special_bus = false;
7427 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
7428 VCATimeAxisView* vtv = dynamic_cast<VCATimeAxisView*> (*x);
7430 vcas.push_back (vtv->vca());
7434 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*x);
7438 if (rtv->is_track()) {
7443 routes.push_back (rtv->_route);
7445 if (rtv->route()->is_master() || rtv->route()->is_monitor()) {
7450 if (special_bus && !Config->get_allow_special_bus_removal()) {
7451 MessageDialog msg (_("That would be bad news ...."),
7455 msg.set_secondary_text (string_compose (_(
7456 "Removing the master or monitor bus is such a bad idea\n\
7457 that %1 is not going to allow it.\n\
7459 If you really want to do this sort of thing\n\
7460 edit your ardour.rc file to set the\n\
7461 \"allow-special-bus-removal\" option to be \"yes\""), PROGRAM_NAME));
7468 if (ntracks + nbusses + nvcas == 0) {
7474 trackstr = P_("track", "tracks", ntracks);
7475 busstr = P_("bus", "busses", nbusses);
7476 vcastr = P_("VCA", "VCAs", nvcas);
7478 if (ntracks > 0 && nbusses > 0 && nvcas > 0) {
7479 title = _("Remove various strips");
7480 prompt = string_compose (_("Do you really want to remove %1 %2, %3 %4 and %5 %6?"),
7481 ntracks, trackstr, nbusses, busstr, nvcas, vcastr);
7483 else if (ntracks > 0 && nbusses > 0) {
7484 title = string_compose (_("Remove %1 and %2"), trackstr, busstr);
7485 prompt = string_compose (_("Do you really want to remove %1 %2 and %3 %4?"),
7486 ntracks, trackstr, nbusses, busstr);
7488 else if (ntracks > 0 && nvcas > 0) {
7489 title = string_compose (_("Remove %1 and %2"), trackstr, vcastr);
7490 prompt = string_compose (_("Do you really want to remove %1 %2 and %3 %4?"),
7491 ntracks, trackstr, nvcas, vcastr);
7493 else if (nbusses > 0 && nvcas > 0) {
7494 title = string_compose (_("Remove %1 and %2"), busstr, vcastr);
7495 prompt = string_compose (_("Do you really want to remove %1 %2 and %3 %4?"),
7496 nbusses, busstr, nvcas, vcastr);
7498 else if (ntracks > 0) {
7499 title = string_compose (_("Remove %1"), trackstr);
7500 prompt = string_compose (_("Do you really want to remove %1 %2?"),
7503 else if (nbusses > 0) {
7504 title = string_compose (_("Remove %1"), busstr);
7505 prompt = string_compose (_("Do you really want to remove %1 %2?"),
7508 else if (nvcas > 0) {
7509 title = string_compose (_("Remove %1"), vcastr);
7510 prompt = string_compose (_("Do you really want to remove %1 %2?"),
7518 prompt += "\n" + string_compose ("(You may also lose the playlists associated with the %1)", trackstr) + "\n";
7521 prompt += "\n" + string(_("This action cannot be undone, and the session file will be overwritten!"));
7523 choices.push_back (_("No, do nothing."));
7524 if (ntracks + nbusses + nvcas > 1) {
7525 choices.push_back (_("Yes, remove them."));
7527 choices.push_back (_("Yes, remove it."));
7530 Choice prompter (title, prompt, choices);
7532 if (prompter.run () != 1) {
7536 if (current_mixer_strip && routes.size () > 1 && std::find (routes.begin(), routes.end(), current_mixer_strip->route()) != routes.end ()) {
7537 /* Route deletion calls Editor::timeaxisview_deleted() iteratively (for each deleted
7538 * route). If the deleted route is currently displayed in the Editor-Mixer (highly
7539 * likely because deletion requires selection) this will call
7540 * Editor::set_selected_mixer_strip () which is expensive ( MixerStrip::set_route() ).
7541 * It's likewise likely that the route that has just been displayed in the
7542 * Editor-Mixer will be next in line for deletion.
7544 * So simply switch to the master-bus (if present)
7546 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
7547 if ((*i)->stripable ()->is_master ()) {
7548 set_selected_mixer_strip (*(*i));
7555 PresentationInfo::ChangeSuspender cs;
7556 DisplaySuspender ds;
7558 boost::shared_ptr<RouteList> rl (new RouteList);
7559 for (vector<boost::shared_ptr<Route> >::iterator x = routes.begin(); x != routes.end(); ++x) {
7562 _session->remove_routes (rl);
7564 for (vector<boost::shared_ptr<VCA> >::iterator x = vcas.begin(); x != vcas.end(); ++x) {
7565 _session->vca_manager().remove_vca (*x);
7569 /* TrackSelection and RouteList leave scope,
7570 * destructors are called,
7571 * diskstream drops references, save_state is called (again for every track)
7576 Editor::do_insert_time ()
7578 if (selection->tracks.empty()) {
7582 InsertRemoveTimeDialog d (*this);
7583 int response = d.run ();
7585 if (response != RESPONSE_OK) {
7589 if (d.distance() == 0) {
7596 d.intersected_region_action (),
7600 d.move_glued_markers(),
7601 d.move_locked_markers(),
7607 Editor::insert_time (
7608 framepos_t pos, framecnt_t frames, InsertTimeOption opt,
7609 bool all_playlists, bool ignore_music_glue, bool markers_too, bool glued_markers_too, bool locked_markers_too, bool tempo_too
7613 if (Config->get_edit_mode() == Lock) {
7616 bool in_command = false;
7618 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
7620 for (TrackViewList::iterator x = ts.begin(); x != ts.end(); ++x) {
7624 /* don't operate on any playlist more than once, which could
7625 * happen if "all playlists" is enabled, but there is more
7626 * than 1 track using playlists "from" a given track.
7629 set<boost::shared_ptr<Playlist> > pl;
7631 if (all_playlists) {
7632 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*x);
7633 if (rtav && rtav->track ()) {
7634 vector<boost::shared_ptr<Playlist> > all = _session->playlists->playlists_for_track (rtav->track ());
7635 for (vector<boost::shared_ptr<Playlist> >::iterator p = all.begin(); p != all.end(); ++p) {
7640 if ((*x)->playlist ()) {
7641 pl.insert ((*x)->playlist ());
7645 for (set<boost::shared_ptr<Playlist> >::iterator i = pl.begin(); i != pl.end(); ++i) {
7647 (*i)->clear_changes ();
7648 (*i)->clear_owned_changes ();
7651 begin_reversible_command (_("insert time"));
7655 if (opt == SplitIntersected) {
7656 /* non musical split */
7657 (*i)->split (MusicFrame (pos, 0));
7660 (*i)->shift (pos, frames, (opt == MoveIntersected), ignore_music_glue);
7662 vector<Command*> cmds;
7664 _session->add_commands (cmds);
7666 _session->add_command (new StatefulDiffCommand (*i));
7670 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*x);
7673 begin_reversible_command (_("insert time"));
7676 rtav->route ()->shift (pos, frames);
7683 const int32_t divisions = get_grid_music_divisions (0);
7684 XMLNode& before (_session->locations()->get_state());
7685 Locations::LocationList copy (_session->locations()->list());
7687 for (Locations::LocationList::iterator i = copy.begin(); i != copy.end(); ++i) {
7689 Locations::LocationList::const_iterator tmp;
7691 if ((*i)->position_lock_style() == AudioTime || glued_markers_too) {
7692 bool const was_locked = (*i)->locked ();
7693 if (locked_markers_too) {
7697 if ((*i)->start() >= pos) {
7698 // move end first, in case we're moving by more than the length of the range
7699 if (!(*i)->is_mark()) {
7700 (*i)->set_end ((*i)->end() + frames, false, true, divisions);
7702 (*i)->set_start ((*i)->start() + frames, false, true, divisions);
7714 begin_reversible_command (_("insert time"));
7717 XMLNode& after (_session->locations()->get_state());
7718 _session->add_command (new MementoCommand<Locations>(*_session->locations(), &before, &after));
7724 begin_reversible_command (_("insert time"));
7727 XMLNode& before (_session->tempo_map().get_state());
7728 _session->tempo_map().insert_time (pos, frames);
7729 XMLNode& after (_session->tempo_map().get_state());
7730 _session->add_command (new MementoCommand<TempoMap>(_session->tempo_map(), &before, &after));
7734 commit_reversible_command ();
7739 Editor::do_remove_time ()
7741 if (selection->tracks.empty()) {
7745 InsertRemoveTimeDialog d (*this, true);
7747 int response = d.run ();
7749 if (response != RESPONSE_OK) {
7753 framecnt_t distance = d.distance();
7755 if (distance == 0) {
7765 d.move_glued_markers(),
7766 d.move_locked_markers(),
7772 Editor::remove_time (framepos_t pos, framecnt_t frames, InsertTimeOption opt,
7773 bool ignore_music_glue, bool markers_too, bool glued_markers_too, bool locked_markers_too, bool tempo_too)
7775 if (Config->get_edit_mode() == Lock) {
7776 error << (_("Cannot insert or delete time when in Lock edit.")) << endmsg;
7779 bool in_command = false;
7781 for (TrackSelection::iterator x = selection->tracks.begin(); x != selection->tracks.end(); ++x) {
7783 boost::shared_ptr<Playlist> pl = (*x)->playlist();
7787 XMLNode &before = pl->get_state();
7790 begin_reversible_command (_("remove time"));
7794 std::list<AudioRange> rl;
7795 AudioRange ar(pos, pos+frames, 0);
7798 pl->shift (pos, -frames, true, ignore_music_glue);
7800 XMLNode &after = pl->get_state();
7802 _session->add_command (new MementoCommand<Playlist> (*pl, &before, &after));
7806 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*x);
7809 begin_reversible_command (_("remove time"));
7812 rtav->route ()->shift (pos, -frames);
7816 const int32_t divisions = get_grid_music_divisions (0);
7817 std::list<Location*> loc_kill_list;
7822 XMLNode& before (_session->locations()->get_state());
7823 Locations::LocationList copy (_session->locations()->list());
7825 for (Locations::LocationList::iterator i = copy.begin(); i != copy.end(); ++i) {
7826 if ((*i)->position_lock_style() == AudioTime || glued_markers_too) {
7828 bool const was_locked = (*i)->locked ();
7829 if (locked_markers_too) {
7833 if (!(*i)->is_mark()) { // it's a range; have to handle both start and end
7834 if ((*i)->end() >= pos
7835 && (*i)->end() < pos+frames
7836 && (*i)->start() >= pos
7837 && (*i)->end() < pos+frames) { // range is completely enclosed; kill it
7839 loc_kill_list.push_back(*i);
7840 } else { // only start or end is included, try to do the right thing
7841 // move start before moving end, to avoid trying to move the end to before the start
7842 // if we're removing more time than the length of the range
7843 if ((*i)->start() >= pos && (*i)->start() < pos+frames) {
7844 // start is within cut
7845 (*i)->set_start (pos, false, true,divisions); // bring the start marker to the beginning of the cut
7847 } else if ((*i)->start() >= pos+frames) {
7848 // start (and thus entire range) lies beyond end of cut
7849 (*i)->set_start ((*i)->start() - frames, false, true, divisions); // slip the start marker back
7852 if ((*i)->end() >= pos && (*i)->end() < pos+frames) {
7853 // end is inside cut
7854 (*i)->set_end (pos, false, true, divisions); // bring the end to the cut
7856 } else if ((*i)->end() >= pos+frames) {
7857 // end is beyond end of cut
7858 (*i)->set_end ((*i)->end() - frames, false, true, divisions); // slip the end marker back
7863 } else if ((*i)->start() >= pos && (*i)->start() < pos+frames ) {
7864 loc_kill_list.push_back(*i);
7866 } else if ((*i)->start() >= pos) {
7867 (*i)->set_start ((*i)->start() -frames, false, true, divisions);
7877 for (list<Location*>::iterator i = loc_kill_list.begin(); i != loc_kill_list.end(); ++i) {
7878 _session->locations()->remove( *i );
7883 begin_reversible_command (_("remove time"));
7886 XMLNode& after (_session->locations()->get_state());
7887 _session->add_command (new MementoCommand<Locations>(*_session->locations(), &before, &after));
7892 XMLNode& before (_session->tempo_map().get_state());
7894 if (_session->tempo_map().remove_time (pos, frames) ) {
7896 begin_reversible_command (_("remove time"));
7899 XMLNode& after (_session->tempo_map().get_state());
7900 _session->add_command (new MementoCommand<TempoMap>(_session->tempo_map(), &before, &after));
7905 commit_reversible_command ();
7910 Editor::fit_selection ()
7912 if (!selection->tracks.empty()) {
7913 fit_tracks (selection->tracks);
7917 /* no selected tracks - use tracks with selected regions */
7919 if (!selection->regions.empty()) {
7920 for (RegionSelection::iterator r = selection->regions.begin(); r != selection->regions.end(); ++r) {
7921 tvl.push_back (&(*r)->get_time_axis_view ());
7927 } else if (internal_editing()) {
7928 /* no selected tracks, or regions, but in internal edit mode, so follow the mouse and use
7931 if (entered_track) {
7932 tvl.push_back (entered_track);
7940 Editor::fit_tracks (TrackViewList & tracks)
7942 if (tracks.empty()) {
7946 uint32_t child_heights = 0;
7947 int visible_tracks = 0;
7949 for (TrackSelection::iterator t = tracks.begin(); t != tracks.end(); ++t) {
7951 if (!(*t)->marked_for_display()) {
7955 child_heights += (*t)->effective_height() - (*t)->current_height();
7959 /* compute the per-track height from:
7961 * total canvas visible height
7962 * - height that will be taken by visible children of selected tracks
7963 * - height of the ruler/hscroll area
7965 uint32_t h = (uint32_t) floor ((trackviews_height() - child_heights) / visible_tracks);
7966 double first_y_pos = DBL_MAX;
7968 if (h < TimeAxisView::preset_height (HeightSmall)) {
7969 MessageDialog msg (_("There are too many tracks to fit in the current window"));
7970 /* too small to be displayed */
7974 undo_visual_stack.push_back (current_visual_state (true));
7975 PBD::Unwinder<bool> nsv (no_save_visual, true);
7977 /* build a list of all tracks, including children */
7980 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
7982 TimeAxisView::Children c = (*i)->get_child_list ();
7983 for (TimeAxisView::Children::iterator j = c.begin(); j != c.end(); ++j) {
7984 all.push_back (j->get());
7989 // find selection range.
7990 // if someone knows how to user TrackViewList::iterator for this
7992 int selected_top = -1;
7993 int selected_bottom = -1;
7995 for (TrackViewList::iterator t = all.begin(); t != all.end(); ++t, ++i) {
7996 if ((*t)->marked_for_display ()) {
7997 if (tracks.contains(*t)) {
7998 if (selected_top == -1) {
8001 selected_bottom = i;
8007 for (TrackViewList::iterator t = all.begin(); t != all.end(); ++t, ++i) {
8008 if ((*t)->marked_for_display ()) {
8009 if (tracks.contains(*t)) {
8010 (*t)->set_height (h);
8011 first_y_pos = std::min ((*t)->y_position (), first_y_pos);
8013 if (i > selected_top && i < selected_bottom) {
8014 hide_track_in_display (*t);
8021 set the controls_layout height now, because waiting for its size
8022 request signal handler will cause the vertical adjustment setting to fail
8025 controls_layout.property_height () = _full_canvas_height;
8026 vertical_adjustment.set_value (first_y_pos);
8028 redo_visual_stack.push_back (current_visual_state (true));
8030 visible_tracks_selector.set_text (_("Sel"));
8034 Editor::save_visual_state (uint32_t n)
8036 while (visual_states.size() <= n) {
8037 visual_states.push_back (0);
8040 if (visual_states[n] != 0) {
8041 delete visual_states[n];
8044 visual_states[n] = current_visual_state (true);
8049 Editor::goto_visual_state (uint32_t n)
8051 if (visual_states.size() <= n) {
8055 if (visual_states[n] == 0) {
8059 use_visual_state (*visual_states[n]);
8063 Editor::start_visual_state_op (uint32_t n)
8065 save_visual_state (n);
8067 PopUp* pup = new PopUp (WIN_POS_MOUSE, 1000, true);
8069 snprintf (buf, sizeof (buf), _("Saved view %u"), n+1);
8070 pup->set_text (buf);
8075 Editor::cancel_visual_state_op (uint32_t n)
8077 goto_visual_state (n);
8081 Editor::toggle_region_mute ()
8083 if (_ignore_region_action) {
8087 RegionSelection rs = get_regions_from_selection_and_entered ();
8093 if (rs.size() > 1) {
8094 begin_reversible_command (_("mute regions"));
8096 begin_reversible_command (_("mute region"));
8099 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
8101 (*i)->region()->playlist()->clear_changes ();
8102 (*i)->region()->set_muted (!(*i)->region()->muted ());
8103 _session->add_command (new StatefulDiffCommand ((*i)->region()));
8107 commit_reversible_command ();
8111 Editor::combine_regions ()
8113 /* foreach track with selected regions, take all selected regions
8114 and join them into a new region containing the subregions (as a
8118 typedef set<RouteTimeAxisView*> RTVS;
8121 if (selection->regions.empty()) {
8125 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
8126 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(&(*i)->get_time_axis_view());
8129 tracks.insert (rtv);
8133 begin_reversible_command (_("combine regions"));
8135 vector<RegionView*> new_selection;
8137 for (RTVS::iterator i = tracks.begin(); i != tracks.end(); ++i) {
8140 if ((rv = (*i)->combine_regions ()) != 0) {
8141 new_selection.push_back (rv);
8145 selection->clear_regions ();
8146 for (vector<RegionView*>::iterator i = new_selection.begin(); i != new_selection.end(); ++i) {
8147 selection->add (*i);
8150 commit_reversible_command ();
8154 Editor::uncombine_regions ()
8156 typedef set<RouteTimeAxisView*> RTVS;
8159 if (selection->regions.empty()) {
8163 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
8164 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(&(*i)->get_time_axis_view());
8167 tracks.insert (rtv);
8171 begin_reversible_command (_("uncombine regions"));
8173 for (RTVS::iterator i = tracks.begin(); i != tracks.end(); ++i) {
8174 (*i)->uncombine_regions ();
8177 commit_reversible_command ();
8181 Editor::toggle_midi_input_active (bool flip_others)
8184 boost::shared_ptr<RouteList> rl (new RouteList);
8186 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
8187 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
8193 boost::shared_ptr<MidiTrack> mt = rtav->midi_track();
8196 rl->push_back (rtav->route());
8197 onoff = !mt->input_active();
8201 _session->set_exclusive_input_active (rl, onoff, flip_others);
8204 static bool ok_fine (GdkEventAny*) { return true; }
8210 lock_dialog = new Gtk::Dialog (string_compose (_("%1: Locked"), PROGRAM_NAME), true);
8212 Gtk::Image* padlock = manage (new Gtk::Image (ARDOUR_UI_UTILS::get_icon ("padlock_closed")));
8213 lock_dialog->get_vbox()->pack_start (*padlock);
8214 lock_dialog->signal_delete_event ().connect (sigc::ptr_fun (ok_fine));
8216 ArdourButton* b = manage (new ArdourButton);
8217 b->set_name ("lock button");
8218 b->set_text (_("Click to unlock"));
8219 b->signal_clicked.connect (sigc::mem_fun (*this, &Editor::unlock));
8220 lock_dialog->get_vbox()->pack_start (*b);
8222 lock_dialog->get_vbox()->show_all ();
8223 lock_dialog->set_size_request (200, 200);
8226 delete _main_menu_disabler;
8227 _main_menu_disabler = new MainMenuDisabler;
8229 lock_dialog->present ();
8231 lock_dialog->get_window()->set_decorations (Gdk::WMDecoration (0));
8237 lock_dialog->hide ();
8239 delete _main_menu_disabler;
8240 _main_menu_disabler = 0;
8242 if (UIConfiguration::instance().get_lock_gui_after_seconds()) {
8243 start_lock_event_timing ();
8248 Editor::bring_in_callback (Gtk::Label* label, uint32_t n, uint32_t total, string name)
8250 Gtkmm2ext::UI::instance()->call_slot (invalidator (*this), boost::bind (&Editor::update_bring_in_message, this, label, n, total, name));
8254 Editor::update_bring_in_message (Gtk::Label* label, uint32_t n, uint32_t total, string name)
8256 Timers::TimerSuspender t;
8257 label->set_text (string_compose ("Copying %1, %2 of %3", name, n, total));
8258 Gtkmm2ext::UI::instance()->flush_pending (1);
8262 Editor::bring_all_sources_into_session ()
8269 ArdourDialog w (_("Moving embedded files into session folder"));
8270 w.get_vbox()->pack_start (msg);
8273 /* flush all pending GUI events because we're about to start copying
8277 Timers::TimerSuspender t;
8278 Gtkmm2ext::UI::instance()->flush_pending (3);
8282 _session->bring_all_sources_into_session (boost::bind (&Editor::bring_in_callback, this, &msg, _1, _2, _3));