2 Copyright (C) 2000-2004 Paul Davis
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 /* Note: public Editor methods are documented in public_editor.h */
31 #include "pbd/error.h"
32 #include "pbd/basename.h"
33 #include "pbd/pthread_utils.h"
34 #include "pbd/memento_command.h"
35 #include "pbd/unwind.h"
36 #include "pbd/whitespace.h"
37 #include "pbd/stateful_diff_command.h"
39 #include <gtkmm2ext/utils.h>
40 #include <gtkmm2ext/choice.h>
41 #include <gtkmm2ext/popup.h>
43 #include "ardour/audio_track.h"
44 #include "ardour/audioregion.h"
45 #include "ardour/dB.h"
46 #include "ardour/location.h"
47 #include "ardour/midi_region.h"
48 #include "ardour/midi_track.h"
49 #include "ardour/operations.h"
50 #include "ardour/playlist_factory.h"
51 #include "ardour/profile.h"
52 #include "ardour/quantize.h"
53 #include "ardour/legatize.h"
54 #include "ardour/region_factory.h"
55 #include "ardour/reverse.h"
56 #include "ardour/session.h"
57 #include "ardour/session_playlists.h"
58 #include "ardour/strip_silence.h"
59 #include "ardour/transient_detector.h"
61 #include "canvas/canvas.h"
64 #include "ardour_ui.h"
65 #include "audio_region_view.h"
66 #include "audio_streamview.h"
67 #include "audio_time_axis.h"
68 #include "automation_region_view.h"
69 #include "automation_time_axis.h"
70 #include "control_point.h"
74 #include "editor_cursors.h"
75 #include "editor_drag.h"
76 #include "editor_regions.h"
77 #include "editor_routes.h"
78 #include "gui_thread.h"
79 #include "insert_time_dialog.h"
80 #include "interthread_progress_window.h"
81 #include "item_counts.h"
83 #include "midi_region_view.h"
84 #include "mixer_strip.h"
85 #include "mouse_cursors.h"
86 #include "normalize_dialog.h"
88 #include "paste_context.h"
89 #include "patch_change_dialog.h"
90 #include "quantize_dialog.h"
91 #include "region_gain_line.h"
92 #include "rgb_macros.h"
93 #include "route_time_axis.h"
94 #include "selection.h"
95 #include "selection_templates.h"
96 #include "streamview.h"
97 #include "strip_silence_dialog.h"
98 #include "time_axis_view.h"
99 #include "transpose_dialog.h"
104 using namespace ARDOUR;
107 using namespace Gtkmm2ext;
108 using namespace Editing;
109 using Gtkmm2ext::Keyboard;
111 /***********************************************************************
113 ***********************************************************************/
116 Editor::undo (uint32_t n)
118 if (_drags->active ()) {
128 Editor::redo (uint32_t n)
130 if (_drags->active ()) {
140 Editor::split_regions_at (framepos_t where, RegionSelection& regions)
144 RegionSelection pre_selected_regions = selection->regions;
145 bool working_on_selection = !pre_selected_regions.empty();
147 list<boost::shared_ptr<Playlist> > used_playlists;
148 list<RouteTimeAxisView*> used_trackviews;
150 if (regions.empty()) {
154 begin_reversible_command (_("split"));
156 // if splitting a single region, and snap-to is using
157 // region boundaries, don't pay attention to them
159 if (regions.size() == 1) {
160 switch (_snap_type) {
161 case SnapToRegionStart:
162 case SnapToRegionSync:
163 case SnapToRegionEnd:
172 EditorFreeze(); /* Emit Signal */
175 for (RegionSelection::iterator a = regions.begin(); a != regions.end(); ) {
177 RegionSelection::iterator tmp;
179 /* XXX this test needs to be more complicated, to make sure we really
180 have something to split.
183 if (!(*a)->region()->covers (where)) {
191 boost::shared_ptr<Playlist> pl = (*a)->region()->playlist();
199 /* we haven't seen this playlist before */
201 /* remember used playlists so we can thaw them later */
202 used_playlists.push_back(pl);
204 TimeAxisView& tv = (*a)->get_time_axis_view();
205 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (&tv);
207 used_trackviews.push_back (rtv);
214 pl->clear_changes ();
215 pl->split_region ((*a)->region(), where);
216 _session->add_command (new StatefulDiffCommand (pl));
222 vector<sigc::connection> region_added_connections;
224 for (list<RouteTimeAxisView*>::iterator i = used_trackviews.begin(); i != used_trackviews.end(); ++i) {
225 region_added_connections.push_back ((*i)->view()->RegionViewAdded.connect (sigc::mem_fun(*this, &Editor::collect_new_region_view)));
228 latest_regionviews.clear ();
230 while (used_playlists.size() > 0) {
231 list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
233 used_playlists.pop_front();
236 for (vector<sigc::connection>::iterator c = region_added_connections.begin(); c != region_added_connections.end(); ++c) {
240 commit_reversible_command ();
243 EditorThaw(); /* Emit Signal */
246 if (ARDOUR::Profile->get_mixbus()) {
247 //IFF we were working on selected regions, try to reinstate the other region selections that existed before the freeze/thaw.
248 _ignore_follow_edits = true; //a split will change the region selection in mysterious ways; its not practical or wanted to follow this edit
249 if( working_on_selection ) {
250 selection->add ( pre_selected_regions );
251 selection->add (latest_regionviews); //these are the new regions created after the split
253 _ignore_follow_edits = false;
257 /** Move one extreme of the current range selection. If more than one range is selected,
258 * the start of the earliest range or the end of the latest range is moved.
260 * @param move_end true to move the end of the current range selection, false to move
262 * @param next true to move the extreme to the next region boundary, false to move to
266 Editor::move_range_selection_start_or_end_to_region_boundary (bool move_end, bool next)
268 if (selection->time.start() == selection->time.end_frame()) {
272 framepos_t start = selection->time.start ();
273 framepos_t end = selection->time.end_frame ();
275 /* the position of the thing we may move */
276 framepos_t pos = move_end ? end : start;
277 int dir = next ? 1 : -1;
279 /* so we don't find the current region again */
280 if (dir > 0 || pos > 0) {
284 framepos_t const target = get_region_boundary (pos, dir, true, false);
299 begin_reversible_command (_("alter selection"));
300 selection->set_preserving_all_ranges (start, end);
301 commit_reversible_command ();
305 Editor::nudge_forward_release (GdkEventButton* ev)
307 if (ev->state & Keyboard::PrimaryModifier) {
308 nudge_forward (false, true);
310 nudge_forward (false, false);
316 Editor::nudge_backward_release (GdkEventButton* ev)
318 if (ev->state & Keyboard::PrimaryModifier) {
319 nudge_backward (false, true);
321 nudge_backward (false, false);
328 Editor::nudge_forward (bool next, bool force_playhead)
331 framepos_t next_distance;
337 RegionSelection rs = get_regions_from_selection_and_entered ();
339 if (!force_playhead && !rs.empty()) {
341 begin_reversible_command (_("nudge regions forward"));
343 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
344 boost::shared_ptr<Region> r ((*i)->region());
346 distance = get_nudge_distance (r->position(), next_distance);
349 distance = next_distance;
353 r->set_position (r->position() + distance);
354 _session->add_command (new StatefulDiffCommand (r));
357 commit_reversible_command ();
360 } else if (!force_playhead && !selection->markers.empty()) {
364 begin_reversible_command (_("nudge location forward"));
366 for (MarkerSelection::iterator i = selection->markers.begin(); i != selection->markers.end(); ++i) {
368 Location* loc = find_location_from_marker ((*i), is_start);
372 XMLNode& before (loc->get_state());
375 distance = get_nudge_distance (loc->start(), next_distance);
377 distance = next_distance;
379 if (max_framepos - distance > loc->start() + loc->length()) {
380 loc->set_start (loc->start() + distance);
382 loc->set_start (max_framepos - loc->length());
385 distance = get_nudge_distance (loc->end(), next_distance);
387 distance = next_distance;
389 if (max_framepos - distance > loc->end()) {
390 loc->set_end (loc->end() + distance);
392 loc->set_end (max_framepos);
395 XMLNode& after (loc->get_state());
396 _session->add_command (new MementoCommand<Location>(*loc, &before, &after));
400 commit_reversible_command ();
403 distance = get_nudge_distance (playhead_cursor->current_frame (), next_distance);
404 _session->request_locate (playhead_cursor->current_frame () + distance);
409 Editor::nudge_backward (bool next, bool force_playhead)
412 framepos_t next_distance;
418 RegionSelection rs = get_regions_from_selection_and_entered ();
420 if (!force_playhead && !rs.empty()) {
422 begin_reversible_command (_("nudge regions backward"));
424 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
425 boost::shared_ptr<Region> r ((*i)->region());
427 distance = get_nudge_distance (r->position(), next_distance);
430 distance = next_distance;
435 if (r->position() > distance) {
436 r->set_position (r->position() - distance);
440 _session->add_command (new StatefulDiffCommand (r));
443 commit_reversible_command ();
445 } else if (!force_playhead && !selection->markers.empty()) {
449 begin_reversible_command (_("nudge location forward"));
451 for (MarkerSelection::iterator i = selection->markers.begin(); i != selection->markers.end(); ++i) {
453 Location* loc = find_location_from_marker ((*i), is_start);
457 XMLNode& before (loc->get_state());
460 distance = get_nudge_distance (loc->start(), next_distance);
462 distance = next_distance;
464 if (distance < loc->start()) {
465 loc->set_start (loc->start() - distance);
470 distance = get_nudge_distance (loc->end(), next_distance);
473 distance = next_distance;
476 if (distance < loc->end() - loc->length()) {
477 loc->set_end (loc->end() - distance);
479 loc->set_end (loc->length());
483 XMLNode& after (loc->get_state());
484 _session->add_command (new MementoCommand<Location>(*loc, &before, &after));
488 commit_reversible_command ();
492 distance = get_nudge_distance (playhead_cursor->current_frame (), next_distance);
494 if (playhead_cursor->current_frame () > distance) {
495 _session->request_locate (playhead_cursor->current_frame () - distance);
497 _session->goto_start();
503 Editor::nudge_forward_capture_offset ()
505 RegionSelection rs = get_regions_from_selection_and_entered ();
507 if (!_session || rs.empty()) {
511 begin_reversible_command (_("nudge forward"));
513 framepos_t const distance = _session->worst_output_latency();
515 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
516 boost::shared_ptr<Region> r ((*i)->region());
519 r->set_position (r->position() + distance);
520 _session->add_command(new StatefulDiffCommand (r));
523 commit_reversible_command ();
527 Editor::nudge_backward_capture_offset ()
529 RegionSelection rs = get_regions_from_selection_and_entered ();
531 if (!_session || rs.empty()) {
535 begin_reversible_command (_("nudge backward"));
537 framepos_t const distance = _session->worst_output_latency();
539 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
540 boost::shared_ptr<Region> r ((*i)->region());
544 if (r->position() > distance) {
545 r->set_position (r->position() - distance);
549 _session->add_command(new StatefulDiffCommand (r));
552 commit_reversible_command ();
555 struct RegionSelectionPositionSorter {
556 bool operator() (RegionView* a, RegionView* b) {
557 return a->region()->position() < b->region()->position();
562 Editor::sequence_regions ()
565 framepos_t r_end_prev;
573 RegionSelection rs = get_regions_from_selection_and_entered ();
574 rs.sort(RegionSelectionPositionSorter());
578 begin_reversible_command (_("sequence regions"));
579 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
580 boost::shared_ptr<Region> r ((*i)->region());
588 if(r->position_locked())
595 r->set_position(r_end_prev);
598 _session->add_command (new StatefulDiffCommand (r));
600 r_end=r->position() + r->length();
604 commit_reversible_command ();
612 Editor::move_to_start ()
614 _session->goto_start ();
618 Editor::move_to_end ()
621 _session->request_locate (_session->current_end_frame());
625 Editor::build_region_boundary_cache ()
628 vector<RegionPoint> interesting_points;
629 boost::shared_ptr<Region> r;
630 TrackViewList tracks;
633 region_boundary_cache.clear ();
639 switch (_snap_type) {
640 case SnapToRegionStart:
641 interesting_points.push_back (Start);
643 case SnapToRegionEnd:
644 interesting_points.push_back (End);
646 case SnapToRegionSync:
647 interesting_points.push_back (SyncPoint);
649 case SnapToRegionBoundary:
650 interesting_points.push_back (Start);
651 interesting_points.push_back (End);
654 fatal << string_compose (_("build_region_boundary_cache called with snap_type = %1"), _snap_type) << endmsg;
655 abort(); /*NOTREACHED*/
659 TimeAxisView *ontrack = 0;
662 if (!selection->tracks.empty()) {
663 tlist = selection->tracks.filter_to_unique_playlists ();
665 tlist = track_views.filter_to_unique_playlists ();
668 while (pos < _session->current_end_frame() && !at_end) {
671 framepos_t lpos = max_framepos;
673 for (vector<RegionPoint>::iterator p = interesting_points.begin(); p != interesting_points.end(); ++p) {
675 if ((r = find_next_region (pos, *p, 1, tlist, &ontrack)) == 0) {
676 if (*p == interesting_points.back()) {
679 /* move to next point type */
685 rpos = r->first_frame();
689 rpos = r->last_frame();
693 rpos = r->sync_position ();
701 RouteTimeAxisView *rtav;
703 if (ontrack != 0 && (rtav = dynamic_cast<RouteTimeAxisView*>(ontrack)) != 0 ) {
704 if (rtav->track() != 0) {
705 speed = rtav->track()->speed();
709 rpos = track_frame_to_session_frame (rpos, speed);
715 /* prevent duplicates, but we don't use set<> because we want to be able
719 vector<framepos_t>::iterator ri;
721 for (ri = region_boundary_cache.begin(); ri != region_boundary_cache.end(); ++ri) {
727 if (ri == region_boundary_cache.end()) {
728 region_boundary_cache.push_back (rpos);
735 /* finally sort to be sure that the order is correct */
737 sort (region_boundary_cache.begin(), region_boundary_cache.end());
740 boost::shared_ptr<Region>
741 Editor::find_next_region (framepos_t frame, RegionPoint point, int32_t dir, TrackViewList& tracks, TimeAxisView **ontrack)
743 TrackViewList::iterator i;
744 framepos_t closest = max_framepos;
745 boost::shared_ptr<Region> ret;
749 framepos_t track_frame;
750 RouteTimeAxisView *rtav;
752 for (i = tracks.begin(); i != tracks.end(); ++i) {
755 boost::shared_ptr<Region> r;
758 if ( (rtav = dynamic_cast<RouteTimeAxisView*>(*i)) != 0 ) {
759 if (rtav->track()!=0)
760 track_speed = rtav->track()->speed();
763 track_frame = session_frame_to_track_frame(frame, track_speed);
765 if ((r = (*i)->find_next_region (track_frame, point, dir)) == 0) {
771 rpos = r->first_frame ();
775 rpos = r->last_frame ();
779 rpos = r->sync_position ();
783 // rpos is a "track frame", converting it to "_session frame"
784 rpos = track_frame_to_session_frame(rpos, track_speed);
787 distance = rpos - frame;
789 distance = frame - rpos;
792 if (distance < closest) {
804 Editor::find_next_region_boundary (framepos_t pos, int32_t dir, const TrackViewList& tracks)
806 framecnt_t distance = max_framepos;
807 framepos_t current_nearest = -1;
809 for (TrackViewList::const_iterator i = tracks.begin(); i != tracks.end(); ++i) {
810 framepos_t contender;
813 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*i);
819 if ((contender = rtv->find_next_region_boundary (pos, dir)) < 0) {
823 d = ::llabs (pos - contender);
826 current_nearest = contender;
831 return current_nearest;
835 Editor::get_region_boundary (framepos_t pos, int32_t dir, bool with_selection, bool only_onscreen)
840 if (with_selection && Config->get_region_boundaries_from_selected_tracks()) {
842 if (!selection->tracks.empty()) {
844 target = find_next_region_boundary (pos, dir, selection->tracks);
848 if (only_onscreen || Config->get_region_boundaries_from_onscreen_tracks()) {
849 get_onscreen_tracks (tvl);
850 target = find_next_region_boundary (pos, dir, tvl);
852 target = find_next_region_boundary (pos, dir, track_views);
858 if (only_onscreen || Config->get_region_boundaries_from_onscreen_tracks()) {
859 get_onscreen_tracks (tvl);
860 target = find_next_region_boundary (pos, dir, tvl);
862 target = find_next_region_boundary (pos, dir, track_views);
870 Editor::cursor_to_region_boundary (bool with_selection, int32_t dir)
872 framepos_t pos = playhead_cursor->current_frame ();
879 // so we don't find the current region again..
880 if (dir > 0 || pos > 0) {
884 if ((target = get_region_boundary (pos, dir, with_selection, false)) < 0) {
888 _session->request_locate (target);
892 Editor::cursor_to_next_region_boundary (bool with_selection)
894 cursor_to_region_boundary (with_selection, 1);
898 Editor::cursor_to_previous_region_boundary (bool with_selection)
900 cursor_to_region_boundary (with_selection, -1);
904 Editor::cursor_to_region_point (EditorCursor* cursor, RegionPoint point, int32_t dir)
906 boost::shared_ptr<Region> r;
907 framepos_t pos = cursor->current_frame ();
913 TimeAxisView *ontrack = 0;
915 // so we don't find the current region again..
919 if (!selection->tracks.empty()) {
921 r = find_next_region (pos, point, dir, selection->tracks, &ontrack);
923 } else if (clicked_axisview) {
926 t.push_back (clicked_axisview);
928 r = find_next_region (pos, point, dir, t, &ontrack);
932 r = find_next_region (pos, point, dir, track_views, &ontrack);
941 pos = r->first_frame ();
945 pos = r->last_frame ();
949 pos = r->sync_position ();
954 RouteTimeAxisView *rtav;
956 if ( ontrack != 0 && (rtav = dynamic_cast<RouteTimeAxisView*>(ontrack)) != 0 ) {
957 if (rtav->track() != 0) {
958 speed = rtav->track()->speed();
962 pos = track_frame_to_session_frame(pos, speed);
964 if (cursor == playhead_cursor) {
965 _session->request_locate (pos);
967 cursor->set_position (pos);
972 Editor::cursor_to_next_region_point (EditorCursor* cursor, RegionPoint point)
974 cursor_to_region_point (cursor, point, 1);
978 Editor::cursor_to_previous_region_point (EditorCursor* cursor, RegionPoint point)
980 cursor_to_region_point (cursor, point, -1);
984 Editor::cursor_to_selection_start (EditorCursor *cursor)
988 switch (mouse_mode) {
990 if (!selection->regions.empty()) {
991 pos = selection->regions.start();
996 if (!selection->time.empty()) {
997 pos = selection->time.start ();
1005 if (cursor == playhead_cursor) {
1006 _session->request_locate (pos);
1008 cursor->set_position (pos);
1013 Editor::cursor_to_selection_end (EditorCursor *cursor)
1017 switch (mouse_mode) {
1019 if (!selection->regions.empty()) {
1020 pos = selection->regions.end_frame();
1025 if (!selection->time.empty()) {
1026 pos = selection->time.end_frame ();
1034 if (cursor == playhead_cursor) {
1035 _session->request_locate (pos);
1037 cursor->set_position (pos);
1042 Editor::selected_marker_to_region_boundary (bool with_selection, int32_t dir)
1052 if (selection->markers.empty()) {
1056 if (!mouse_frame (mouse, ignored)) {
1060 add_location_mark (mouse);
1063 if ((loc = find_location_from_marker (selection->markers.front(), ignored)) == 0) {
1067 framepos_t pos = loc->start();
1069 // so we don't find the current region again..
1070 if (dir > 0 || pos > 0) {
1074 if ((target = get_region_boundary (pos, dir, with_selection, false)) < 0) {
1078 loc->move_to (target);
1082 Editor::selected_marker_to_next_region_boundary (bool with_selection)
1084 selected_marker_to_region_boundary (with_selection, 1);
1088 Editor::selected_marker_to_previous_region_boundary (bool with_selection)
1090 selected_marker_to_region_boundary (with_selection, -1);
1094 Editor::selected_marker_to_region_point (RegionPoint point, int32_t dir)
1096 boost::shared_ptr<Region> r;
1101 if (!_session || selection->markers.empty()) {
1105 if ((loc = find_location_from_marker (selection->markers.front(), ignored)) == 0) {
1109 TimeAxisView *ontrack = 0;
1113 // so we don't find the current region again..
1117 if (!selection->tracks.empty()) {
1119 r = find_next_region (pos, point, dir, selection->tracks, &ontrack);
1123 r = find_next_region (pos, point, dir, track_views, &ontrack);
1132 pos = r->first_frame ();
1136 pos = r->last_frame ();
1140 pos = r->adjust_to_sync (r->first_frame());
1145 RouteTimeAxisView *rtav;
1147 if (ontrack != 0 && (rtav = dynamic_cast<RouteTimeAxisView*>(ontrack)) != 0) {
1148 if (rtav->track() != 0) {
1149 speed = rtav->track()->speed();
1153 pos = track_frame_to_session_frame(pos, speed);
1159 Editor::selected_marker_to_next_region_point (RegionPoint point)
1161 selected_marker_to_region_point (point, 1);
1165 Editor::selected_marker_to_previous_region_point (RegionPoint point)
1167 selected_marker_to_region_point (point, -1);
1171 Editor::selected_marker_to_selection_start ()
1177 if (!_session || selection->markers.empty()) {
1181 if ((loc = find_location_from_marker (selection->markers.front(), ignored)) == 0) {
1185 switch (mouse_mode) {
1187 if (!selection->regions.empty()) {
1188 pos = selection->regions.start();
1193 if (!selection->time.empty()) {
1194 pos = selection->time.start ();
1206 Editor::selected_marker_to_selection_end ()
1212 if (!_session || selection->markers.empty()) {
1216 if ((loc = find_location_from_marker (selection->markers.front(), ignored)) == 0) {
1220 switch (mouse_mode) {
1222 if (!selection->regions.empty()) {
1223 pos = selection->regions.end_frame();
1228 if (!selection->time.empty()) {
1229 pos = selection->time.end_frame ();
1241 Editor::scroll_playhead (bool forward)
1243 framepos_t pos = playhead_cursor->current_frame ();
1244 framecnt_t delta = (framecnt_t) floor (current_page_samples() / 0.8);
1247 if (pos == max_framepos) {
1251 if (pos < max_framepos - delta) {
1270 _session->request_locate (pos);
1274 Editor::cursor_align (bool playhead_to_edit)
1280 if (playhead_to_edit) {
1282 if (selection->markers.empty()) {
1286 _session->request_locate (selection->markers.front()->position(), _session->transport_rolling());
1289 /* move selected markers to playhead */
1291 for (MarkerSelection::iterator i = selection->markers.begin(); i != selection->markers.end(); ++i) {
1294 Location* loc = find_location_from_marker (*i, ignored);
1296 if (loc->is_mark()) {
1297 loc->set_start (playhead_cursor->current_frame ());
1299 loc->set (playhead_cursor->current_frame (),
1300 playhead_cursor->current_frame () + loc->length());
1307 Editor::scroll_backward (float pages)
1309 framepos_t const one_page = (framepos_t) rint (_visible_canvas_width * samples_per_pixel);
1310 framepos_t const cnt = (framepos_t) floor (pages * one_page);
1313 if (leftmost_frame < cnt) {
1316 frame = leftmost_frame - cnt;
1319 reset_x_origin (frame);
1323 Editor::scroll_forward (float pages)
1325 framepos_t const one_page = (framepos_t) rint (_visible_canvas_width * samples_per_pixel);
1326 framepos_t const cnt = (framepos_t) floor (pages * one_page);
1329 if (max_framepos - cnt < leftmost_frame) {
1330 frame = max_framepos - cnt;
1332 frame = leftmost_frame + cnt;
1335 reset_x_origin (frame);
1339 Editor::scroll_tracks_down ()
1341 double vert_value = vertical_adjustment.get_value() + vertical_adjustment.get_page_size();
1342 if (vert_value > vertical_adjustment.get_upper() - _visible_canvas_height) {
1343 vert_value = vertical_adjustment.get_upper() - _visible_canvas_height;
1346 vertical_adjustment.set_value (vert_value);
1350 Editor::scroll_tracks_up ()
1352 vertical_adjustment.set_value (vertical_adjustment.get_value() - vertical_adjustment.get_page_size());
1356 Editor::scroll_tracks_down_line ()
1358 double vert_value = vertical_adjustment.get_value() + 60;
1360 if (vert_value > vertical_adjustment.get_upper() - _visible_canvas_height) {
1361 vert_value = vertical_adjustment.get_upper() - _visible_canvas_height;
1364 vertical_adjustment.set_value (vert_value);
1368 Editor::scroll_tracks_up_line ()
1370 reset_y_origin (vertical_adjustment.get_value() - 60);
1374 Editor::scroll_down_one_track ()
1376 TrackViewList::reverse_iterator next = track_views.rend();
1377 std::pair<TimeAxisView*,double> res;
1378 const double top_of_trackviews = vertical_adjustment.get_value();
1380 for (TrackViewList::reverse_iterator t = track_views.rbegin(); t != track_views.rend(); ++t) {
1381 if ((*t)->hidden()) {
1386 /* If this is the upper-most visible trackview, we want to display
1387 the one above it (next)
1390 res = (*t)->covers_y_position (top_of_trackviews);
1398 /* move to the track below the first one that covers the */
1400 if (next != track_views.rend()) {
1401 ensure_time_axis_view_is_visible (**next, true);
1409 Editor::scroll_up_one_track ()
1411 TrackViewList::iterator prev = track_views.end();
1412 std::pair<TimeAxisView*,double> res;
1413 double top_of_trackviews = vertical_adjustment.get_value ();
1415 for (TrackViewList::iterator t = track_views.begin(); t != track_views.end(); ++t) {
1417 if ((*t)->hidden()) {
1421 /* find the trackview at the top of the trackview group */
1422 res = (*t)->covers_y_position (top_of_trackviews);
1431 if (prev != track_views.end()) {
1432 ensure_time_axis_view_is_visible (**prev, true);
1442 Editor::tav_zoom_step (bool coarser)
1444 DisplaySuspender ds;
1448 if (selection->tracks.empty()) {
1451 ts = &selection->tracks;
1454 for (TrackViewList::iterator i = ts->begin(); i != ts->end(); ++i) {
1455 TimeAxisView *tv = (static_cast<TimeAxisView*>(*i));
1456 tv->step_height (coarser);
1461 Editor::tav_zoom_smooth (bool coarser, bool force_all)
1463 DisplaySuspender ds;
1467 if (selection->tracks.empty() || force_all) {
1470 ts = &selection->tracks;
1473 for (TrackViewList::iterator i = ts->begin(); i != ts->end(); ++i) {
1474 TimeAxisView *tv = (static_cast<TimeAxisView*>(*i));
1475 uint32_t h = tv->current_height ();
1480 if (h >= TimeAxisView::preset_height (HeightSmall)) {
1485 tv->set_height (h + 5);
1492 Editor::temporal_zoom_step (bool coarser)
1494 ENSURE_GUI_THREAD (*this, &Editor::temporal_zoom_step, coarser)
1496 framecnt_t nspp = samples_per_pixel;
1504 temporal_zoom (nspp);
1508 Editor::temporal_zoom (framecnt_t fpp)
1514 framepos_t current_page = current_page_samples();
1515 framepos_t current_leftmost = leftmost_frame;
1516 framepos_t current_rightmost;
1517 framepos_t current_center;
1518 framepos_t new_page_size;
1519 framepos_t half_page_size;
1520 framepos_t leftmost_after_zoom = 0;
1522 bool in_track_canvas;
1526 if (fpp == samples_per_pixel) {
1530 // Imposing an arbitrary limit to zoom out as too much zoom out produces
1531 // segfaults for lack of memory. If somebody decides this is not high enough I
1532 // believe it can be raisen to higher values but some limit must be in place.
1534 // This constant represents 1 day @ 48kHz on a 1600 pixel wide display
1535 // all of which is used for the editor track displays. The whole day
1536 // would be 4147200000 samples, so 2592000 samples per pixel.
1538 nfpp = min (fpp, (framecnt_t) 2592000);
1539 nfpp = max ((framecnt_t) 1, nfpp);
1541 new_page_size = (framepos_t) floor (_visible_canvas_width * nfpp);
1542 half_page_size = new_page_size / 2;
1544 switch (zoom_focus) {
1546 leftmost_after_zoom = current_leftmost;
1549 case ZoomFocusRight:
1550 current_rightmost = leftmost_frame + current_page;
1551 if (current_rightmost < new_page_size) {
1552 leftmost_after_zoom = 0;
1554 leftmost_after_zoom = current_rightmost - new_page_size;
1558 case ZoomFocusCenter:
1559 current_center = current_leftmost + (current_page/2);
1560 if (current_center < half_page_size) {
1561 leftmost_after_zoom = 0;
1563 leftmost_after_zoom = current_center - half_page_size;
1567 case ZoomFocusPlayhead:
1568 /* centre playhead */
1569 l = playhead_cursor->current_frame () - (new_page_size * 0.5);
1572 leftmost_after_zoom = 0;
1573 } else if (l > max_framepos) {
1574 leftmost_after_zoom = max_framepos - new_page_size;
1576 leftmost_after_zoom = (framepos_t) l;
1580 case ZoomFocusMouse:
1581 /* try to keep the mouse over the same point in the display */
1583 if (!mouse_frame (where, in_track_canvas)) {
1584 /* use playhead instead */
1585 where = playhead_cursor->current_frame ();
1587 if (where < half_page_size) {
1588 leftmost_after_zoom = 0;
1590 leftmost_after_zoom = where - half_page_size;
1595 l = - ((new_page_size * ((where - current_leftmost)/(double)current_page)) - where);
1598 leftmost_after_zoom = 0;
1599 } else if (l > max_framepos) {
1600 leftmost_after_zoom = max_framepos - new_page_size;
1602 leftmost_after_zoom = (framepos_t) l;
1609 /* try to keep the edit point in the same place */
1610 where = get_preferred_edit_position ();
1614 double l = - ((new_page_size * ((where - current_leftmost)/(double)current_page)) - where);
1617 leftmost_after_zoom = 0;
1618 } else if (l > max_framepos) {
1619 leftmost_after_zoom = max_framepos - new_page_size;
1621 leftmost_after_zoom = (framepos_t) l;
1625 /* edit point not defined */
1632 // leftmost_after_zoom = min (leftmost_after_zoom, _session->current_end_frame());
1634 reposition_and_zoom (leftmost_after_zoom, nfpp);
1638 Editor::calc_extra_zoom_edges(framepos_t &start, framepos_t &end)
1640 /* this func helps make sure we leave a little space
1641 at each end of the editor so that the zoom doesn't fit the region
1642 precisely to the screen.
1645 GdkScreen* screen = gdk_screen_get_default ();
1646 const gint pixwidth = gdk_screen_get_width (screen);
1647 const gint mmwidth = gdk_screen_get_width_mm (screen);
1648 const double pix_per_mm = (double) pixwidth/ (double) mmwidth;
1649 const double one_centimeter_in_pixels = pix_per_mm * 10.0;
1651 const framepos_t range = end - start;
1652 const framecnt_t new_fpp = (framecnt_t) ceil ((double) range / (double) _visible_canvas_width);
1653 const framepos_t extra_samples = (framepos_t) floor (one_centimeter_in_pixels * new_fpp);
1655 if (start > extra_samples) {
1656 start -= extra_samples;
1661 if (max_framepos - extra_samples > end) {
1662 end += extra_samples;
1669 Editor::temporal_zoom_region (bool both_axes)
1671 framepos_t start = max_framepos;
1673 set<TimeAxisView*> tracks;
1675 RegionSelection rs = get_regions_from_selection_and_entered ();
1681 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
1683 if ((*i)->region()->position() < start) {
1684 start = (*i)->region()->position();
1687 if ((*i)->region()->last_frame() + 1 > end) {
1688 end = (*i)->region()->last_frame() + 1;
1691 tracks.insert (&((*i)->get_time_axis_view()));
1694 if ((start == 0 && end == 0) || end < start) {
1698 calc_extra_zoom_edges (start, end);
1700 /* if we're zooming on both axes we need to save track heights etc.
1703 undo_visual_stack.push_back (current_visual_state (both_axes));
1705 PBD::Unwinder<bool> nsv (no_save_visual, true);
1707 temporal_zoom_by_frame (start, end);
1710 uint32_t per_track_height = (uint32_t) floor ((_visible_canvas_height - 10.0) / tracks.size());
1712 /* set visible track heights appropriately */
1714 for (set<TimeAxisView*>::iterator t = tracks.begin(); t != tracks.end(); ++t) {
1715 (*t)->set_height (per_track_height);
1718 /* hide irrelevant tracks */
1720 DisplaySuspender ds;
1722 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1723 if (find (tracks.begin(), tracks.end(), (*i)) == tracks.end()) {
1724 hide_track_in_display (*i);
1728 vertical_adjustment.set_value (0.0);
1731 redo_visual_stack.push_back (current_visual_state (both_axes));
1735 Editor::zoom_to_region (bool both_axes)
1737 temporal_zoom_region (both_axes);
1741 Editor::temporal_zoom_selection (bool both_axes)
1743 if (!selection) return;
1745 //if a range is selected, zoom to that
1746 if (!selection->time.empty()) {
1748 framepos_t start = selection->time.start();
1749 framepos_t end = selection->time.end_frame();
1751 calc_extra_zoom_edges(start, end);
1753 temporal_zoom_by_frame (start, end);
1756 fit_selected_tracks();
1759 temporal_zoom_region (both_axes);
1766 Editor::temporal_zoom_session ()
1768 ENSURE_GUI_THREAD (*this, &Editor::temporal_zoom_session)
1771 framecnt_t start = _session->current_start_frame();
1772 framecnt_t end = _session->current_end_frame();
1774 if (_session->actively_recording () ) {
1775 framepos_t cur = playhead_cursor->current_frame ();
1777 /* recording beyond the end marker; zoom out
1778 * by 5 seconds more so that if 'follow
1779 * playhead' is active we don't immediately
1782 end = cur + _session->frame_rate() * 5;
1786 if ((start == 0 && end == 0) || end < start) {
1790 calc_extra_zoom_edges(start, end);
1792 temporal_zoom_by_frame (start, end);
1797 Editor::temporal_zoom_by_frame (framepos_t start, framepos_t end)
1799 if (!_session) return;
1801 if ((start == 0 && end == 0) || end < start) {
1805 framepos_t range = end - start;
1807 const framecnt_t new_fpp = (framecnt_t) ceil ((double) range / (double) _visible_canvas_width);
1809 framepos_t new_page = range;
1810 framepos_t middle = (framepos_t) floor ((double) start + ((double) range / 2.0f));
1811 framepos_t new_leftmost = (framepos_t) floor ((double) middle - ((double) new_page / 2.0f));
1813 if (new_leftmost > middle) {
1817 if (new_leftmost < 0) {
1821 reposition_and_zoom (new_leftmost, new_fpp);
1825 Editor::temporal_zoom_to_frame (bool coarser, framepos_t frame)
1831 framecnt_t range_before = frame - leftmost_frame;
1835 if (samples_per_pixel <= 1) {
1838 new_spp = samples_per_pixel + (samples_per_pixel/2);
1840 range_before += range_before/2;
1842 if (samples_per_pixel >= 1) {
1843 new_spp = samples_per_pixel - (samples_per_pixel/2);
1845 /* could bail out here since we cannot zoom any finer,
1846 but leave that to the equality test below
1848 new_spp = samples_per_pixel;
1851 range_before -= range_before/2;
1854 if (new_spp == samples_per_pixel) {
1858 /* zoom focus is automatically taken as @param frame when this
1862 framepos_t new_leftmost = frame - (framepos_t)range_before;
1864 if (new_leftmost > frame) {
1868 if (new_leftmost < 0) {
1872 reposition_and_zoom (new_leftmost, new_spp);
1877 Editor::choose_new_marker_name(string &name) {
1879 if (!Config->get_name_new_markers()) {
1880 /* don't prompt user for a new name */
1884 ArdourPrompter dialog (true);
1886 dialog.set_prompt (_("New Name:"));
1888 dialog.set_title (_("New Location Marker"));
1890 dialog.set_name ("MarkNameWindow");
1891 dialog.set_size_request (250, -1);
1892 dialog.set_position (Gtk::WIN_POS_MOUSE);
1894 dialog.add_button (Stock::OK, RESPONSE_ACCEPT);
1895 dialog.set_initial_text (name);
1899 switch (dialog.run ()) {
1900 case RESPONSE_ACCEPT:
1906 dialog.get_result(name);
1913 Editor::add_location_from_selection ()
1917 if (selection->time.empty()) {
1921 if (_session == 0 || clicked_axisview == 0) {
1925 framepos_t start = selection->time[clicked_selection].start;
1926 framepos_t end = selection->time[clicked_selection].end;
1928 _session->locations()->next_available_name(rangename,"selection");
1929 Location *location = new Location (*_session, start, end, rangename, Location::IsRangeMarker);
1931 _session->begin_reversible_command (_("add marker"));
1932 XMLNode &before = _session->locations()->get_state();
1933 _session->locations()->add (location, true);
1934 XMLNode &after = _session->locations()->get_state();
1935 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
1936 _session->commit_reversible_command ();
1940 Editor::add_location_mark (framepos_t where)
1944 select_new_marker = true;
1946 _session->locations()->next_available_name(markername,"mark");
1947 if (!choose_new_marker_name(markername)) {
1950 Location *location = new Location (*_session, where, where, markername, Location::IsMark);
1951 _session->begin_reversible_command (_("add marker"));
1952 XMLNode &before = _session->locations()->get_state();
1953 _session->locations()->add (location, true);
1954 XMLNode &after = _session->locations()->get_state();
1955 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
1956 _session->commit_reversible_command ();
1960 Editor::add_location_from_playhead_cursor ()
1962 add_location_mark (_session->audible_frame());
1966 Editor::remove_location_at_playhead_cursor ()
1971 _session->begin_reversible_command (_("remove marker"));
1972 XMLNode &before = _session->locations()->get_state();
1973 bool removed = false;
1975 //find location(s) at this time
1976 Locations::LocationList locs;
1977 _session->locations()->find_all_between (_session->audible_frame(), _session->audible_frame()+1, locs, Location::Flags(0));
1978 for (Locations::LocationList::iterator i = locs.begin(); i != locs.end(); ++i) {
1979 if ((*i)->is_mark()) {
1980 _session->locations()->remove (*i);
1987 XMLNode &after = _session->locations()->get_state();
1988 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
1989 _session->commit_reversible_command ();
1994 /** Add a range marker around each selected region */
1996 Editor::add_locations_from_region ()
1998 RegionSelection rs = get_regions_from_selection_and_entered ();
2004 _session->begin_reversible_command (selection->regions.size () > 1 ? _("add markers") : _("add marker"));
2005 XMLNode &before = _session->locations()->get_state();
2007 for (RegionSelection::iterator i = rs.begin (); i != rs.end (); ++i) {
2009 boost::shared_ptr<Region> region = (*i)->region ();
2011 Location *location = new Location (*_session, region->position(), region->last_frame(), region->name(), Location::IsRangeMarker);
2013 _session->locations()->add (location, true);
2016 XMLNode &after = _session->locations()->get_state();
2017 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2018 _session->commit_reversible_command ();
2021 /** Add a single range marker around all selected regions */
2023 Editor::add_location_from_region ()
2025 RegionSelection rs = get_regions_from_selection_and_entered ();
2031 _session->begin_reversible_command (_("add marker"));
2032 XMLNode &before = _session->locations()->get_state();
2036 if (rs.size() > 1) {
2037 _session->locations()->next_available_name(markername, "regions");
2039 RegionView* rv = *(rs.begin());
2040 boost::shared_ptr<Region> region = rv->region();
2041 markername = region->name();
2044 if (!choose_new_marker_name(markername)) {
2048 // single range spanning all selected
2049 Location *location = new Location (*_session, selection->regions.start(), selection->regions.end_frame(), markername, Location::IsRangeMarker);
2050 _session->locations()->add (location, true);
2052 XMLNode &after = _session->locations()->get_state();
2053 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2054 _session->commit_reversible_command ();
2060 Editor::jump_forward_to_mark ()
2066 framepos_t pos = _session->locations()->first_mark_after (playhead_cursor->current_frame());
2072 _session->request_locate (pos, _session->transport_rolling());
2076 Editor::jump_backward_to_mark ()
2082 framepos_t pos = _session->locations()->first_mark_before (playhead_cursor->current_frame());
2088 _session->request_locate (pos, _session->transport_rolling());
2094 framepos_t const pos = _session->audible_frame ();
2097 _session->locations()->next_available_name (markername, "mark");
2099 if (!choose_new_marker_name (markername)) {
2103 _session->locations()->add (new Location (*_session, pos, 0, markername, Location::IsMark), true);
2107 Editor::clear_markers ()
2110 _session->begin_reversible_command (_("clear markers"));
2111 XMLNode &before = _session->locations()->get_state();
2112 _session->locations()->clear_markers ();
2113 XMLNode &after = _session->locations()->get_state();
2114 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2115 _session->commit_reversible_command ();
2120 Editor::clear_ranges ()
2123 _session->begin_reversible_command (_("clear ranges"));
2124 XMLNode &before = _session->locations()->get_state();
2126 _session->locations()->clear_ranges ();
2128 XMLNode &after = _session->locations()->get_state();
2129 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2130 _session->commit_reversible_command ();
2135 Editor::clear_locations ()
2137 _session->begin_reversible_command (_("clear locations"));
2138 XMLNode &before = _session->locations()->get_state();
2139 _session->locations()->clear ();
2140 XMLNode &after = _session->locations()->get_state();
2141 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2142 _session->commit_reversible_command ();
2143 _session->locations()->clear ();
2147 Editor::unhide_markers ()
2149 for (LocationMarkerMap::iterator i = location_markers.begin(); i != location_markers.end(); ++i) {
2150 Location *l = (*i).first;
2151 if (l->is_hidden() && l->is_mark()) {
2152 l->set_hidden(false, this);
2158 Editor::unhide_ranges ()
2160 for (LocationMarkerMap::iterator i = location_markers.begin(); i != location_markers.end(); ++i) {
2161 Location *l = (*i).first;
2162 if (l->is_hidden() && l->is_range_marker()) {
2163 l->set_hidden(false, this);
2168 /* INSERT/REPLACE */
2171 Editor::insert_region_list_selection (float times)
2173 RouteTimeAxisView *tv = 0;
2174 boost::shared_ptr<Playlist> playlist;
2176 if (clicked_routeview != 0) {
2177 tv = clicked_routeview;
2178 } else if (!selection->tracks.empty()) {
2179 if ((tv = dynamic_cast<RouteTimeAxisView*>(selection->tracks.front())) == 0) {
2182 } else if (entered_track != 0) {
2183 if ((tv = dynamic_cast<RouteTimeAxisView*>(entered_track)) == 0) {
2190 if ((playlist = tv->playlist()) == 0) {
2194 boost::shared_ptr<Region> region = _regions->get_single_selection ();
2199 begin_reversible_command (_("insert region"));
2200 playlist->clear_changes ();
2201 playlist->add_region ((RegionFactory::create (region, true)), get_preferred_edit_position(), times);
2202 if (Config->get_edit_mode() == Ripple)
2203 playlist->ripple (get_preferred_edit_position(), region->length() * times, boost::shared_ptr<Region>());
2205 _session->add_command(new StatefulDiffCommand (playlist));
2206 commit_reversible_command ();
2209 /* BUILT-IN EFFECTS */
2212 Editor::reverse_selection ()
2217 /* GAIN ENVELOPE EDITING */
2220 Editor::edit_envelope ()
2227 Editor::transition_to_rolling (bool fwd)
2233 if (_session->config.get_external_sync()) {
2234 switch (Config->get_sync_source()) {
2238 /* transport controlled by the master */
2243 if (_session->is_auditioning()) {
2244 _session->cancel_audition ();
2248 _session->request_transport_speed (fwd ? 1.0f : -1.0f);
2252 Editor::play_from_start ()
2254 _session->request_locate (_session->current_start_frame(), true);
2258 Editor::play_from_edit_point ()
2260 _session->request_locate (get_preferred_edit_position(), true);
2264 Editor::play_from_edit_point_and_return ()
2266 framepos_t start_frame;
2267 framepos_t return_frame;
2269 start_frame = get_preferred_edit_position (true);
2271 if (_session->transport_rolling()) {
2272 _session->request_locate (start_frame, false);
2276 /* don't reset the return frame if its already set */
2278 if ((return_frame = _session->requested_return_frame()) < 0) {
2279 return_frame = _session->audible_frame();
2282 if (start_frame >= 0) {
2283 _session->request_roll_at_and_return (start_frame, return_frame);
2288 Editor::play_selection ()
2290 if (selection->time.empty()) {
2294 _session->request_play_range (&selection->time, true);
2298 Editor::get_preroll ()
2300 return 1.0 /*Config->get_edit_preroll_seconds()*/ * _session->frame_rate();
2305 Editor::maybe_locate_with_edit_preroll ( framepos_t location )
2307 if ( _session->transport_rolling() || !Config->get_follow_edits() || _ignore_follow_edits )
2310 location -= get_preroll();
2312 //don't try to locate before the beginning of time
2316 //if follow_playhead is on, keep the playhead on the screen
2317 if ( _follow_playhead )
2318 if ( location < leftmost_frame )
2319 location = leftmost_frame;
2321 _session->request_locate( location );
2325 Editor::play_with_preroll ()
2327 if (selection->time.empty()) {
2330 framepos_t preroll = get_preroll();
2332 framepos_t start = 0;
2333 if (selection->time[clicked_selection].start > preroll)
2334 start = selection->time[clicked_selection].start - preroll;
2336 framepos_t end = selection->time[clicked_selection].end + preroll;
2338 AudioRange ar (start, end, 0);
2339 list<AudioRange> lar;
2342 _session->request_play_range (&lar, true);
2347 Editor::play_location (Location& location)
2349 if (location.start() <= location.end()) {
2353 _session->request_bounded_roll (location.start(), location.end());
2357 Editor::loop_location (Location& location)
2359 if (location.start() <= location.end()) {
2365 if ((tll = transport_loop_location()) != 0) {
2366 tll->set (location.start(), location.end());
2368 // enable looping, reposition and start rolling
2369 _session->request_locate (tll->start(), true);
2370 _session->request_play_loop (true);
2375 Editor::do_layer_operation (LayerOperation op)
2377 if (selection->regions.empty ()) {
2381 bool const multiple = selection->regions.size() > 1;
2385 begin_reversible_command (_("raise regions"));
2387 begin_reversible_command (_("raise region"));
2393 begin_reversible_command (_("raise regions to top"));
2395 begin_reversible_command (_("raise region to top"));
2401 begin_reversible_command (_("lower regions"));
2403 begin_reversible_command (_("lower region"));
2409 begin_reversible_command (_("lower regions to bottom"));
2411 begin_reversible_command (_("lower region"));
2416 set<boost::shared_ptr<Playlist> > playlists = selection->regions.playlists ();
2417 for (set<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
2418 (*i)->clear_owned_changes ();
2421 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
2422 boost::shared_ptr<Region> r = (*i)->region ();
2434 r->lower_to_bottom ();
2438 for (set<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
2439 vector<Command*> cmds;
2441 _session->add_commands (cmds);
2444 commit_reversible_command ();
2448 Editor::raise_region ()
2450 do_layer_operation (Raise);
2454 Editor::raise_region_to_top ()
2456 do_layer_operation (RaiseToTop);
2460 Editor::lower_region ()
2462 do_layer_operation (Lower);
2466 Editor::lower_region_to_bottom ()
2468 do_layer_operation (LowerToBottom);
2471 /** Show the region editor for the selected regions */
2473 Editor::show_region_properties ()
2475 selection->foreach_regionview (&RegionView::show_region_editor);
2478 /** Show the midi list editor for the selected MIDI regions */
2480 Editor::show_midi_list_editor ()
2482 selection->foreach_midi_regionview (&MidiRegionView::show_list_editor);
2486 Editor::rename_region ()
2488 RegionSelection rs = get_regions_from_selection_and_entered ();
2494 ArdourDialog d (*this, _("Rename Region"), true, false);
2496 Label label (_("New name:"));
2499 hbox.set_spacing (6);
2500 hbox.pack_start (label, false, false);
2501 hbox.pack_start (entry, true, true);
2503 d.get_vbox()->set_border_width (12);
2504 d.get_vbox()->pack_start (hbox, false, false);
2506 d.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
2507 d.add_button(Gtk::Stock::OK, Gtk::RESPONSE_OK);
2509 d.set_size_request (300, -1);
2511 entry.set_text (rs.front()->region()->name());
2512 entry.select_region (0, -1);
2514 entry.signal_activate().connect (sigc::bind (sigc::mem_fun (d, &Dialog::response), RESPONSE_OK));
2520 int const ret = d.run();
2524 if (ret != RESPONSE_OK) {
2528 std::string str = entry.get_text();
2529 strip_whitespace_edges (str);
2531 rs.front()->region()->set_name (str);
2532 _regions->redisplay ();
2537 Editor::audition_playlist_region_via_route (boost::shared_ptr<Region> region, Route& route)
2539 if (_session->is_auditioning()) {
2540 _session->cancel_audition ();
2543 // note: some potential for creativity here, because region doesn't
2544 // have to belong to the playlist that Route is handling
2546 // bool was_soloed = route.soloed();
2548 route.set_solo (true, this);
2550 _session->request_bounded_roll (region->position(), region->position() + region->length());
2552 /* XXX how to unset the solo state ? */
2555 /** Start an audition of the first selected region */
2557 Editor::play_edit_range ()
2559 framepos_t start, end;
2561 if (get_edit_op_range (start, end)) {
2562 _session->request_bounded_roll (start, end);
2567 Editor::play_selected_region ()
2569 framepos_t start = max_framepos;
2572 RegionSelection rs = get_regions_from_selection_and_entered ();
2578 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
2579 if ((*i)->region()->position() < start) {
2580 start = (*i)->region()->position();
2582 if ((*i)->region()->last_frame() + 1 > end) {
2583 end = (*i)->region()->last_frame() + 1;
2587 _session->request_bounded_roll (start, end);
2591 Editor::audition_playlist_region_standalone (boost::shared_ptr<Region> region)
2593 _session->audition_region (region);
2597 Editor::region_from_selection ()
2599 if (clicked_axisview == 0) {
2603 if (selection->time.empty()) {
2607 framepos_t start = selection->time[clicked_selection].start;
2608 framepos_t end = selection->time[clicked_selection].end;
2610 TrackViewList tracks = get_tracks_for_range_action ();
2612 framepos_t selection_cnt = end - start + 1;
2614 for (TrackSelection::iterator i = tracks.begin(); i != tracks.end(); ++i) {
2615 boost::shared_ptr<Region> current;
2616 boost::shared_ptr<Playlist> pl;
2617 framepos_t internal_start;
2620 if ((pl = (*i)->playlist()) == 0) {
2624 if ((current = pl->top_region_at (start)) == 0) {
2628 internal_start = start - current->position();
2629 RegionFactory::region_name (new_name, current->name(), true);
2633 plist.add (ARDOUR::Properties::start, current->start() + internal_start);
2634 plist.add (ARDOUR::Properties::length, selection_cnt);
2635 plist.add (ARDOUR::Properties::name, new_name);
2636 plist.add (ARDOUR::Properties::layer, 0);
2638 boost::shared_ptr<Region> region (RegionFactory::create (current, plist));
2643 Editor::create_region_from_selection (vector<boost::shared_ptr<Region> >& new_regions)
2645 if (selection->time.empty() || selection->tracks.empty()) {
2649 framepos_t start = selection->time[clicked_selection].start;
2650 framepos_t end = selection->time[clicked_selection].end;
2652 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
2653 sort_track_selection (ts);
2655 for (TrackSelection::iterator i = ts.begin(); i != ts.end(); ++i) {
2656 boost::shared_ptr<Region> current;
2657 boost::shared_ptr<Playlist> playlist;
2658 framepos_t internal_start;
2661 if ((playlist = (*i)->playlist()) == 0) {
2665 if ((current = playlist->top_region_at(start)) == 0) {
2669 internal_start = start - current->position();
2670 RegionFactory::region_name (new_name, current->name(), true);
2674 plist.add (ARDOUR::Properties::start, current->start() + internal_start);
2675 plist.add (ARDOUR::Properties::length, end - start + 1);
2676 plist.add (ARDOUR::Properties::name, new_name);
2678 new_regions.push_back (RegionFactory::create (current, plist));
2683 Editor::split_multichannel_region ()
2685 RegionSelection rs = get_regions_from_selection_and_entered ();
2691 vector< boost::shared_ptr<Region> > v;
2693 for (list<RegionView*>::iterator x = rs.begin(); x != rs.end(); ++x) {
2694 (*x)->region()->separate_by_channel (*_session, v);
2699 Editor::new_region_from_selection ()
2701 region_from_selection ();
2702 cancel_selection ();
2706 add_if_covered (RegionView* rv, const AudioRange* ar, RegionSelection* rs)
2708 switch (rv->region()->coverage (ar->start, ar->end - 1)) {
2709 // n.b. -1 because AudioRange::end is one past the end, but coverage expects inclusive ranges
2710 case Evoral::OverlapNone:
2718 * - selected tracks, or if there are none...
2719 * - tracks containing selected regions, or if there are none...
2724 Editor::get_tracks_for_range_action () const
2728 if (selection->tracks.empty()) {
2730 /* use tracks with selected regions */
2732 RegionSelection rs = selection->regions;
2734 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
2735 TimeAxisView* tv = &(*i)->get_time_axis_view();
2737 if (!t.contains (tv)) {
2743 /* no regions and no tracks: use all tracks */
2749 t = selection->tracks;
2752 return t.filter_to_unique_playlists();
2756 Editor::separate_regions_between (const TimeSelection& ts)
2758 bool in_command = false;
2759 boost::shared_ptr<Playlist> playlist;
2760 RegionSelection new_selection;
2762 TrackViewList tmptracks = get_tracks_for_range_action ();
2763 sort_track_selection (tmptracks);
2765 for (TrackSelection::iterator i = tmptracks.begin(); i != tmptracks.end(); ++i) {
2767 RouteTimeAxisView* rtv;
2769 if ((rtv = dynamic_cast<RouteTimeAxisView*> ((*i))) != 0) {
2771 if (rtv->is_track()) {
2773 /* no edits to destructive tracks */
2775 if (rtv->track()->destructive()) {
2779 if ((playlist = rtv->playlist()) != 0) {
2781 playlist->clear_changes ();
2783 /* XXX need to consider musical time selections here at some point */
2785 double speed = rtv->track()->speed();
2788 for (list<AudioRange>::const_iterator t = ts.begin(); t != ts.end(); ++t) {
2790 sigc::connection c = rtv->view()->RegionViewAdded.connect (
2791 sigc::mem_fun(*this, &Editor::collect_new_region_view));
2793 latest_regionviews.clear ();
2795 playlist->partition ((framepos_t)((*t).start * speed),
2796 (framepos_t)((*t).end * speed), false);
2800 if (!latest_regionviews.empty()) {
2802 rtv->view()->foreach_regionview (sigc::bind (
2803 sigc::ptr_fun (add_if_covered),
2804 &(*t), &new_selection));
2807 begin_reversible_command (_("separate"));
2811 /* pick up changes to existing regions */
2813 vector<Command*> cmds;
2814 playlist->rdiff (cmds);
2815 _session->add_commands (cmds);
2817 /* pick up changes to the playlist itself (adds/removes)
2820 _session->add_command(new StatefulDiffCommand (playlist));
2829 // selection->set (new_selection);
2831 commit_reversible_command ();
2835 struct PlaylistState {
2836 boost::shared_ptr<Playlist> playlist;
2840 /** Take tracks from get_tracks_for_range_action and cut any regions
2841 * on those tracks so that the tracks are empty over the time
2845 Editor::separate_region_from_selection ()
2847 /* preferentially use *all* ranges in the time selection if we're in range mode
2848 to allow discontiguous operation, since get_edit_op_range() currently
2849 returns a single range.
2852 if (!selection->time.empty()) {
2854 separate_regions_between (selection->time);
2861 if (get_edit_op_range (start, end)) {
2863 AudioRange ar (start, end, 1);
2867 separate_regions_between (ts);
2873 Editor::separate_region_from_punch ()
2875 Location* loc = _session->locations()->auto_punch_location();
2877 separate_regions_using_location (*loc);
2882 Editor::separate_region_from_loop ()
2884 Location* loc = _session->locations()->auto_loop_location();
2886 separate_regions_using_location (*loc);
2891 Editor::separate_regions_using_location (Location& loc)
2893 if (loc.is_mark()) {
2897 AudioRange ar (loc.start(), loc.end(), 1);
2902 separate_regions_between (ts);
2905 /** Separate regions under the selected region */
2907 Editor::separate_under_selected_regions ()
2909 vector<PlaylistState> playlists;
2913 rs = get_regions_from_selection_and_entered();
2915 if (!_session || rs.empty()) {
2919 begin_reversible_command (_("separate region under"));
2921 list<boost::shared_ptr<Region> > regions_to_remove;
2923 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
2924 // we can't just remove the region(s) in this loop because
2925 // this removes them from the RegionSelection, and they thus
2926 // disappear from underneath the iterator, and the ++i above
2927 // SEGVs in a puzzling fashion.
2929 // so, first iterate over the regions to be removed from rs and
2930 // add them to the regions_to_remove list, and then
2931 // iterate over the list to actually remove them.
2933 regions_to_remove.push_back ((*i)->region());
2936 for (list<boost::shared_ptr<Region> >::iterator rl = regions_to_remove.begin(); rl != regions_to_remove.end(); ++rl) {
2938 boost::shared_ptr<Playlist> playlist = (*rl)->playlist();
2941 // is this check necessary?
2945 vector<PlaylistState>::iterator i;
2947 //only take state if this is a new playlist.
2948 for (i = playlists.begin(); i != playlists.end(); ++i) {
2949 if ((*i).playlist == playlist) {
2954 if (i == playlists.end()) {
2956 PlaylistState before;
2957 before.playlist = playlist;
2958 before.before = &playlist->get_state();
2960 playlist->freeze ();
2961 playlists.push_back(before);
2964 //Partition on the region bounds
2965 playlist->partition ((*rl)->first_frame() - 1, (*rl)->last_frame() + 1, true);
2967 //Re-add region that was just removed due to the partition operation
2968 playlist->add_region( (*rl), (*rl)->first_frame() );
2971 vector<PlaylistState>::iterator pl;
2973 for (pl = playlists.begin(); pl != playlists.end(); ++pl) {
2974 (*pl).playlist->thaw ();
2975 _session->add_command(new MementoCommand<Playlist>(*(*pl).playlist, (*pl).before, &(*pl).playlist->get_state()));
2978 commit_reversible_command ();
2982 Editor::crop_region_to_selection ()
2984 if (!selection->time.empty()) {
2986 crop_region_to (selection->time.start(), selection->time.end_frame());
2993 if (get_edit_op_range (start, end)) {
2994 crop_region_to (start, end);
3001 Editor::crop_region_to (framepos_t start, framepos_t end)
3003 vector<boost::shared_ptr<Playlist> > playlists;
3004 boost::shared_ptr<Playlist> playlist;
3007 if (selection->tracks.empty()) {
3008 ts = track_views.filter_to_unique_playlists();
3010 ts = selection->tracks.filter_to_unique_playlists ();
3013 sort_track_selection (ts);
3015 for (TrackSelection::iterator i = ts.begin(); i != ts.end(); ++i) {
3017 RouteTimeAxisView* rtv;
3019 if ((rtv = dynamic_cast<RouteTimeAxisView*> ((*i))) != 0) {
3021 boost::shared_ptr<Track> t = rtv->track();
3023 if (t != 0 && ! t->destructive()) {
3025 if ((playlist = rtv->playlist()) != 0) {
3026 playlists.push_back (playlist);
3032 if (playlists.empty()) {
3036 framepos_t the_start;
3040 begin_reversible_command (_("trim to selection"));
3042 for (vector<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
3044 boost::shared_ptr<Region> region;
3048 if ((region = (*i)->top_region_at(the_start)) == 0) {
3052 /* now adjust lengths to that we do the right thing
3053 if the selection extends beyond the region
3056 the_start = max (the_start, (framepos_t) region->position());
3057 if (max_framepos - the_start < region->length()) {
3058 the_end = the_start + region->length() - 1;
3060 the_end = max_framepos;
3062 the_end = min (end, the_end);
3063 cnt = the_end - the_start + 1;
3065 region->clear_changes ();
3066 region->trim_to (the_start, cnt);
3067 _session->add_command (new StatefulDiffCommand (region));
3070 commit_reversible_command ();
3074 Editor::region_fill_track ()
3076 RegionSelection rs = get_regions_from_selection_and_entered ();
3078 if (!_session || rs.empty()) {
3082 framepos_t const end = _session->current_end_frame ();
3084 begin_reversible_command (Operations::region_fill);
3086 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3088 boost::shared_ptr<Region> region ((*i)->region());
3090 boost::shared_ptr<Playlist> pl = region->playlist();
3092 if (end <= region->last_frame()) {
3096 double times = (double) (end - region->last_frame()) / (double) region->length();
3102 pl->clear_changes ();
3103 pl->add_region (RegionFactory::create (region, true), region->last_frame(), times);
3104 _session->add_command (new StatefulDiffCommand (pl));
3107 commit_reversible_command ();
3111 Editor::region_fill_selection ()
3113 if (clicked_routeview == 0 || !clicked_routeview->is_audio_track()) {
3117 if (selection->time.empty()) {
3121 boost::shared_ptr<Region> region = _regions->get_single_selection ();
3126 framepos_t start = selection->time[clicked_selection].start;
3127 framepos_t end = selection->time[clicked_selection].end;
3129 boost::shared_ptr<Playlist> playlist;
3131 if (selection->tracks.empty()) {
3135 framepos_t selection_length = end - start;
3136 float times = (float)selection_length / region->length();
3138 begin_reversible_command (Operations::fill_selection);
3140 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
3142 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
3144 if ((playlist = (*i)->playlist()) == 0) {
3148 playlist->clear_changes ();
3149 playlist->add_region (RegionFactory::create (region, true), start, times);
3150 _session->add_command (new StatefulDiffCommand (playlist));
3153 commit_reversible_command ();
3157 Editor::set_region_sync_position ()
3159 set_sync_point (get_preferred_edit_position (), get_regions_from_selection_and_edit_point ());
3163 Editor::set_sync_point (framepos_t where, const RegionSelection& rs)
3165 bool in_command = false;
3167 for (RegionSelection::const_iterator r = rs.begin(); r != rs.end(); ++r) {
3169 if (!(*r)->region()->covers (where)) {
3173 boost::shared_ptr<Region> region ((*r)->region());
3176 begin_reversible_command (_("set sync point"));
3180 region->clear_changes ();
3181 region->set_sync_position (where);
3182 _session->add_command(new StatefulDiffCommand (region));
3186 commit_reversible_command ();
3190 /** Remove the sync positions of the selection */
3192 Editor::remove_region_sync ()
3194 RegionSelection rs = get_regions_from_selection_and_entered ();
3200 begin_reversible_command (_("remove region sync"));
3202 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3204 (*i)->region()->clear_changes ();
3205 (*i)->region()->clear_sync_position ();
3206 _session->add_command(new StatefulDiffCommand ((*i)->region()));
3209 commit_reversible_command ();
3213 Editor::naturalize_region ()
3215 RegionSelection rs = get_regions_from_selection_and_entered ();
3221 if (rs.size() > 1) {
3222 begin_reversible_command (_("move regions to original position"));
3224 begin_reversible_command (_("move region to original position"));
3227 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3228 (*i)->region()->clear_changes ();
3229 (*i)->region()->move_to_natural_position ();
3230 _session->add_command (new StatefulDiffCommand ((*i)->region()));
3233 commit_reversible_command ();
3237 Editor::align_regions (RegionPoint what)
3239 RegionSelection const rs = get_regions_from_selection_and_edit_point ();
3245 begin_reversible_command (_("align selection"));
3247 framepos_t const position = get_preferred_edit_position ();
3249 for (RegionSelection::const_iterator i = rs.begin(); i != rs.end(); ++i) {
3250 align_region_internal ((*i)->region(), what, position);
3253 commit_reversible_command ();
3256 struct RegionSortByTime {
3257 bool operator() (const RegionView* a, const RegionView* b) {
3258 return a->region()->position() < b->region()->position();
3263 Editor::align_regions_relative (RegionPoint point)
3265 RegionSelection const rs = get_regions_from_selection_and_edit_point ();
3271 framepos_t const position = get_preferred_edit_position ();
3273 framepos_t distance = 0;
3277 list<RegionView*> sorted;
3278 rs.by_position (sorted);
3280 boost::shared_ptr<Region> r ((*sorted.begin())->region());
3285 if (position > r->position()) {
3286 distance = position - r->position();
3288 distance = r->position() - position;
3294 if (position > r->last_frame()) {
3295 distance = position - r->last_frame();
3296 pos = r->position() + distance;
3298 distance = r->last_frame() - position;
3299 pos = r->position() - distance;
3305 pos = r->adjust_to_sync (position);
3306 if (pos > r->position()) {
3307 distance = pos - r->position();
3309 distance = r->position() - pos;
3315 if (pos == r->position()) {
3319 begin_reversible_command (_("align selection (relative)"));
3321 /* move first one specially */
3323 r->clear_changes ();
3324 r->set_position (pos);
3325 _session->add_command(new StatefulDiffCommand (r));
3327 /* move rest by the same amount */
3331 for (list<RegionView*>::iterator i = sorted.begin(); i != sorted.end(); ++i) {
3333 boost::shared_ptr<Region> region ((*i)->region());
3335 region->clear_changes ();
3338 region->set_position (region->position() + distance);
3340 region->set_position (region->position() - distance);
3343 _session->add_command(new StatefulDiffCommand (region));
3347 commit_reversible_command ();
3351 Editor::align_region (boost::shared_ptr<Region> region, RegionPoint point, framepos_t position)
3353 begin_reversible_command (_("align region"));
3354 align_region_internal (region, point, position);
3355 commit_reversible_command ();
3359 Editor::align_region_internal (boost::shared_ptr<Region> region, RegionPoint point, framepos_t position)
3361 region->clear_changes ();
3365 region->set_position (region->adjust_to_sync (position));
3369 if (position > region->length()) {
3370 region->set_position (position - region->length());
3375 region->set_position (position);
3379 _session->add_command(new StatefulDiffCommand (region));
3383 Editor::trim_region_front ()
3389 Editor::trim_region_back ()
3391 trim_region (false);
3395 Editor::trim_region (bool front)
3397 framepos_t where = get_preferred_edit_position();
3398 RegionSelection rs = get_regions_from_selection_and_edit_point ();
3404 begin_reversible_command (front ? _("trim front") : _("trim back"));
3406 for (list<RegionView*>::const_iterator i = rs.by_layer().begin(); i != rs.by_layer().end(); ++i) {
3407 if (!(*i)->region()->locked()) {
3409 (*i)->region()->clear_changes ();
3412 (*i)->region()->trim_front (where);
3413 maybe_locate_with_edit_preroll ( where );
3415 (*i)->region()->trim_end (where);
3416 maybe_locate_with_edit_preroll ( where );
3419 _session->add_command (new StatefulDiffCommand ((*i)->region()));
3423 commit_reversible_command ();
3426 /** Trim the end of the selected regions to the position of the edit cursor */
3428 Editor::trim_region_to_loop ()
3430 Location* loc = _session->locations()->auto_loop_location();
3434 trim_region_to_location (*loc, _("trim to loop"));
3438 Editor::trim_region_to_punch ()
3440 Location* loc = _session->locations()->auto_punch_location();
3444 trim_region_to_location (*loc, _("trim to punch"));
3448 Editor::trim_region_to_location (const Location& loc, const char* str)
3450 RegionSelection rs = get_regions_from_selection_and_entered ();
3452 begin_reversible_command (str);
3454 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
3455 RegionView* rv = (*x);
3457 /* require region to span proposed trim */
3458 switch (rv->region()->coverage (loc.start(), loc.end())) {
3459 case Evoral::OverlapInternal:
3465 RouteTimeAxisView* tav = dynamic_cast<RouteTimeAxisView*> (&rv->get_time_axis_view());
3474 if (tav->track() != 0) {
3475 speed = tav->track()->speed();
3478 start = session_frame_to_track_frame (loc.start(), speed);
3479 end = session_frame_to_track_frame (loc.end(), speed);
3481 rv->region()->clear_changes ();
3482 rv->region()->trim_to (start, (end - start));
3483 _session->add_command(new StatefulDiffCommand (rv->region()));
3486 commit_reversible_command ();
3490 Editor::trim_region_to_previous_region_end ()
3492 return trim_to_region(false);
3496 Editor::trim_region_to_next_region_start ()
3498 return trim_to_region(true);
3502 Editor::trim_to_region(bool forward)
3504 RegionSelection rs = get_regions_from_selection_and_entered ();
3506 begin_reversible_command (_("trim to region"));
3508 boost::shared_ptr<Region> next_region;
3510 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
3512 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*x);
3518 AudioTimeAxisView* atav = dynamic_cast<AudioTimeAxisView*> (&arv->get_time_axis_view());
3526 if (atav->track() != 0) {
3527 speed = atav->track()->speed();
3531 boost::shared_ptr<Region> region = arv->region();
3532 boost::shared_ptr<Playlist> playlist (region->playlist());
3534 region->clear_changes ();
3538 next_region = playlist->find_next_region (region->first_frame(), Start, 1);
3544 region->trim_end((framepos_t) ( (next_region->first_frame() - 1) * speed));
3545 arv->region_changed (PropertyChange (ARDOUR::Properties::length));
3549 next_region = playlist->find_next_region (region->first_frame(), Start, 0);
3555 region->trim_front((framepos_t) ((next_region->last_frame() + 1) * speed));
3557 arv->region_changed (ARDOUR::bounds_change);
3560 _session->add_command(new StatefulDiffCommand (region));
3563 commit_reversible_command ();
3567 Editor::unfreeze_route ()
3569 if (clicked_routeview == 0 || !clicked_routeview->is_track()) {
3573 clicked_routeview->track()->unfreeze ();
3577 Editor::_freeze_thread (void* arg)
3579 return static_cast<Editor*>(arg)->freeze_thread ();
3583 Editor::freeze_thread ()
3585 /* create event pool because we may need to talk to the session */
3586 SessionEvent::create_per_thread_pool ("freeze events", 64);
3587 /* create per-thread buffers for process() tree to use */
3588 clicked_routeview->audio_track()->freeze_me (*current_interthread_info);
3589 current_interthread_info->done = true;
3594 Editor::freeze_route ()
3600 /* stop transport before we start. this is important */
3602 _session->request_transport_speed (0.0);
3604 /* wait for just a little while, because the above call is asynchronous */
3606 Glib::usleep (250000);
3608 if (clicked_routeview == 0 || !clicked_routeview->is_audio_track()) {
3612 if (!clicked_routeview->track()->bounceable (clicked_routeview->track()->main_outs(), true)) {
3614 _("This track/bus cannot be frozen because the signal adds or loses channels before reaching the outputs.\n"
3615 "This is typically caused by plugins that generate stereo output from mono input or vice versa.")
3617 d.set_title (_("Cannot freeze"));
3622 if (clicked_routeview->track()->has_external_redirects()) {
3623 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"
3624 "Freezing will only process the signal as far as the first send/insert/return."),
3625 clicked_routeview->track()->name()), true, MESSAGE_INFO, BUTTONS_NONE, true);
3627 d.add_button (_("Freeze anyway"), Gtk::RESPONSE_OK);
3628 d.add_button (_("Don't freeze"), Gtk::RESPONSE_CANCEL);
3629 d.set_title (_("Freeze Limits"));
3631 int response = d.run ();
3634 case Gtk::RESPONSE_CANCEL:
3641 InterThreadInfo itt;
3642 current_interthread_info = &itt;
3644 InterthreadProgressWindow ipw (current_interthread_info, _("Freeze"), _("Cancel Freeze"));
3646 pthread_create_and_store (X_("freezer"), &itt.thread, _freeze_thread, this);
3648 set_canvas_cursor (_cursors->wait);
3650 while (!itt.done && !itt.cancel) {
3651 gtk_main_iteration ();
3654 current_interthread_info = 0;
3655 set_canvas_cursor (current_canvas_cursor);
3659 Editor::bounce_range_selection (bool replace, bool enable_processing)
3661 if (selection->time.empty()) {
3665 TrackSelection views = selection->tracks;
3667 for (TrackViewList::iterator i = views.begin(); i != views.end(); ++i) {
3669 if (enable_processing) {
3671 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*i);
3673 if (rtv && rtv->track() && replace && enable_processing && !rtv->track()->bounceable (rtv->track()->main_outs(), false)) {
3675 _("You can't perform this operation because the processing of the signal "
3676 "will cause one or more of the tracks to end up with a region with more channels than this track has inputs.\n\n"
3677 "You can do this without processing, which is a different operation.")
3679 d.set_title (_("Cannot bounce"));
3686 framepos_t start = selection->time[clicked_selection].start;
3687 framepos_t end = selection->time[clicked_selection].end;
3688 framepos_t cnt = end - start + 1;
3690 begin_reversible_command (_("bounce range"));
3692 for (TrackViewList::iterator i = views.begin(); i != views.end(); ++i) {
3694 RouteTimeAxisView* rtv;
3696 if ((rtv = dynamic_cast<RouteTimeAxisView*> (*i)) == 0) {
3700 boost::shared_ptr<Playlist> playlist;
3702 if ((playlist = rtv->playlist()) == 0) {
3706 InterThreadInfo itt;
3708 playlist->clear_changes ();
3709 playlist->clear_owned_changes ();
3711 boost::shared_ptr<Region> r;
3713 if (enable_processing) {
3714 r = rtv->track()->bounce_range (start, start+cnt, itt, rtv->track()->main_outs(), false);
3716 r = rtv->track()->bounce_range (start, start+cnt, itt, boost::shared_ptr<Processor>(), false);
3724 list<AudioRange> ranges;
3725 ranges.push_back (AudioRange (start, start+cnt, 0));
3726 playlist->cut (ranges); // discard result
3727 playlist->add_region (r, start);
3730 vector<Command*> cmds;
3731 playlist->rdiff (cmds);
3732 _session->add_commands (cmds);
3734 _session->add_command (new StatefulDiffCommand (playlist));
3737 commit_reversible_command ();
3740 /** Delete selected regions, automation points or a time range */
3744 //special case: if the user is pointing in the editor/mixer strip, they may be trying to delete a plugin.
3745 //we need this because the editor-mixer strip is in the editor window, so it doesn't get the bindings from the mix window
3746 bool deleted = false;
3747 if ( current_mixer_strip && current_mixer_strip == MixerStrip::entered_mixer_strip() )
3748 deleted = current_mixer_strip->delete_processors ();
3754 /** Cut selected regions, automation points or a time range */
3761 /** Copy selected regions, automation points or a time range */
3769 /** @return true if a Cut, Copy or Clear is possible */
3771 Editor::can_cut_copy () const
3773 if (!selection->time.empty() || !selection->regions.empty() || !selection->points.empty())
3780 /** Cut, copy or clear selected regions, automation points or a time range.
3781 * @param op Operation (Delete, Cut, Copy or Clear)
3784 Editor::cut_copy (CutCopyOp op)
3786 /* only cancel selection if cut/copy is successful.*/
3792 opname = _("delete");
3801 opname = _("clear");
3805 /* if we're deleting something, and the mouse is still pressed,
3806 the thing we started a drag for will be gone when we release
3807 the mouse button(s). avoid this. see part 2 at the end of
3811 if (op == Delete || op == Cut || op == Clear) {
3812 if (_drags->active ()) {
3817 if ( op != Delete ) //"Delete" doesn't change copy/paste buf
3818 cut_buffer->clear ();
3820 if (entered_marker) {
3822 /* cut/delete op while pointing at a marker */
3825 Location* loc = find_location_from_marker (entered_marker, ignored);
3827 if (_session && loc) {
3828 Glib::signal_idle().connect (sigc::bind (sigc::mem_fun(*this, &Editor::really_remove_marker), loc));
3835 if (internal_editing()) {
3837 switch (effective_mouse_mode()) {
3840 begin_reversible_command (opname + ' ' + X_("MIDI"));
3842 commit_reversible_command ();
3851 bool did_edit = false;
3853 if (!selection->regions.empty() || !selection->points.empty()) {
3854 begin_reversible_command (opname + ' ' + _("objects"));
3857 if (!selection->regions.empty()) {
3858 cut_copy_regions (op, selection->regions);
3860 if (op == Cut || op == Delete) {
3861 selection->clear_regions ();
3865 if (!selection->points.empty()) {
3866 cut_copy_points (op);
3868 if (op == Cut || op == Delete) {
3869 selection->clear_points ();
3872 } else if (selection->time.empty()) {
3873 framepos_t start, end;
3874 /* no time selection, see if we can get an edit range
3877 if (get_edit_op_range (start, end)) {
3878 selection->set (start, end);
3880 } else if (!selection->time.empty()) {
3881 begin_reversible_command (opname + ' ' + _("range"));
3884 cut_copy_ranges (op);
3886 if (op == Cut || op == Delete) {
3887 selection->clear_time ();
3892 /* reset repeated paste state */
3895 commit_reversible_command ();
3898 if (op == Delete || op == Cut || op == Clear) {
3903 struct AutomationRecord {
3904 AutomationRecord () : state (0) , line(NULL) {}
3905 AutomationRecord (XMLNode* s, const AutomationLine* l) : state (s) , line (l) {}
3907 XMLNode* state; ///< state before any operation
3908 const AutomationLine* line; ///< line this came from
3909 boost::shared_ptr<Evoral::ControlList> copy; ///< copied events for the cut buffer
3912 /** Cut, copy or clear selected automation points.
3913 * @param op Operation (Cut, Copy or Clear)
3916 Editor::cut_copy_points (Editing::CutCopyOp op, Evoral::MusicalTime earliest, bool midi)
3918 if (selection->points.empty ()) {
3922 /* XXX: not ideal, as there may be more than one track involved in the point selection */
3923 _last_cut_copy_source_track = &selection->points.front()->line().trackview;
3925 /* Keep a record of the AutomationLists that we end up using in this operation */
3926 typedef std::map<boost::shared_ptr<AutomationList>, AutomationRecord> Lists;
3929 /* Go through all selected points, making an AutomationRecord for each distinct AutomationList */
3930 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
3931 const AutomationLine& line = (*i)->line();
3932 const boost::shared_ptr<AutomationList> al = line.the_list();
3933 if (lists.find (al) == lists.end ()) {
3934 /* We haven't seen this list yet, so make a record for it. This includes
3935 taking a copy of its current state, in case this is needed for undo later.
3937 lists[al] = AutomationRecord (&al->get_state (), &line);
3941 if (op == Cut || op == Copy) {
3942 /* This operation will involve putting things in the cut buffer, so create an empty
3943 ControlList for each of our source lists to put the cut buffer data in.
3945 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
3946 i->second.copy = i->first->create (i->first->parameter (), i->first->descriptor());
3949 /* Add all selected points to the relevant copy ControlLists */
3950 framepos_t start = std::numeric_limits<framepos_t>::max();
3951 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
3952 boost::shared_ptr<AutomationList> al = (*i)->line().the_list();
3953 AutomationList::const_iterator j = (*i)->model();
3955 lists[al].copy->fast_simple_add ((*j)->when, (*j)->value);
3957 /* Update earliest MIDI start time in beats */
3958 earliest = std::min(earliest, Evoral::MusicalTime((*j)->when));
3960 /* Update earliest session start time in frames */
3961 start = std::min(start, (*i)->line().session_position(j));
3965 /* Snap start time backwards, so copy/paste is snap aligned. */
3967 if (earliest == Evoral::MusicalTime::max()) {
3968 earliest = Evoral::MusicalTime(); // Weird... don't offset
3970 earliest.round_down_to_beat();
3972 if (start == std::numeric_limits<double>::max()) {
3973 start = 0; // Weird... don't offset
3975 snap_to(start, RoundDownMaybe);
3978 const double line_offset = midi ? earliest.to_double() : start;
3979 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
3980 /* Correct this copy list so that it is relative to the earliest
3981 start time, so relative ordering between points is preserved
3982 when copying from several lists and the paste starts at the
3983 earliest copied piece of data. */
3984 for (AutomationList::iterator j = i->second.copy->begin(); j != i->second.copy->end(); ++j) {
3985 (*j)->when -= line_offset;
3988 /* And add it to the cut buffer */
3989 cut_buffer->add (i->second.copy);
3993 if (op == Delete || op == Cut) {
3994 /* This operation needs to remove things from the main AutomationList, so do that now */
3996 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
3997 i->first->freeze ();
4000 /* Remove each selected point from its AutomationList */
4001 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
4002 boost::shared_ptr<AutomationList> al = (*i)->line().the_list();
4003 al->erase ((*i)->model ());
4006 /* Thaw the lists and add undo records for them */
4007 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
4008 boost::shared_ptr<AutomationList> al = i->first;
4010 _session->add_command (new MementoCommand<AutomationList> (*al.get(), i->second.state, &(al->get_state ())));
4015 /** Cut, copy or clear selected automation points.
4016 * @param op Operation (Cut, Copy or Clear)
4019 Editor::cut_copy_midi (CutCopyOp op)
4021 Evoral::MusicalTime earliest = Evoral::MusicalTime::max();
4022 for (MidiRegionSelection::iterator i = selection->midi_regions.begin(); i != selection->midi_regions.end(); ++i) {
4023 MidiRegionView* mrv = dynamic_cast<MidiRegionView*>(*i);
4025 if (!mrv->selection().empty()) {
4026 earliest = std::min(earliest, (*mrv->selection().begin())->note()->time());
4028 mrv->cut_copy_clear (op);
4030 /* XXX: not ideal, as there may be more than one track involved in the selection */
4031 _last_cut_copy_source_track = &mrv->get_time_axis_view();
4035 if (!selection->points.empty()) {
4036 cut_copy_points (op, earliest, true);
4037 if (op == Cut || op == Delete) {
4038 selection->clear_points ();
4043 struct lt_playlist {
4044 bool operator () (const PlaylistState& a, const PlaylistState& b) {
4045 return a.playlist < b.playlist;
4049 struct PlaylistMapping {
4051 boost::shared_ptr<Playlist> pl;
4053 PlaylistMapping (TimeAxisView* tvp) : tv (tvp) {}
4056 /** Remove `clicked_regionview' */
4058 Editor::remove_clicked_region ()
4060 if (clicked_routeview == 0 || clicked_regionview == 0) {
4064 begin_reversible_command (_("remove region"));
4066 boost::shared_ptr<Playlist> playlist = clicked_routeview->playlist();
4068 playlist->clear_changes ();
4069 playlist->clear_owned_changes ();
4070 playlist->remove_region (clicked_regionview->region());
4071 if (Config->get_edit_mode() == Ripple)
4072 playlist->ripple (clicked_regionview->region()->position(), -clicked_regionview->region()->length(), boost::shared_ptr<Region>());
4074 /* We might have removed regions, which alters other regions' layering_index,
4075 so we need to do a recursive diff here.
4077 vector<Command*> cmds;
4078 playlist->rdiff (cmds);
4079 _session->add_commands (cmds);
4081 _session->add_command(new StatefulDiffCommand (playlist));
4082 commit_reversible_command ();
4086 /** Remove the selected regions */
4088 Editor::remove_selected_regions ()
4090 RegionSelection rs = get_regions_from_selection_and_entered ();
4092 if (!_session || rs.empty()) {
4096 begin_reversible_command (_("remove region"));
4098 list<boost::shared_ptr<Region> > regions_to_remove;
4100 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
4101 // we can't just remove the region(s) in this loop because
4102 // this removes them from the RegionSelection, and they thus
4103 // disappear from underneath the iterator, and the ++i above
4104 // SEGVs in a puzzling fashion.
4106 // so, first iterate over the regions to be removed from rs and
4107 // add them to the regions_to_remove list, and then
4108 // iterate over the list to actually remove them.
4110 regions_to_remove.push_back ((*i)->region());
4113 vector<boost::shared_ptr<Playlist> > playlists;
4115 for (list<boost::shared_ptr<Region> >::iterator rl = regions_to_remove.begin(); rl != regions_to_remove.end(); ++rl) {
4117 boost::shared_ptr<Playlist> playlist = (*rl)->playlist();
4120 // is this check necessary?
4124 /* get_regions_from_selection_and_entered() guarantees that
4125 the playlists involved are unique, so there is no need
4129 playlists.push_back (playlist);
4131 playlist->clear_changes ();
4132 playlist->clear_owned_changes ();
4133 playlist->freeze ();
4134 playlist->remove_region (*rl);
4135 if (Config->get_edit_mode() == Ripple)
4136 playlist->ripple ((*rl)->position(), -(*rl)->length(), boost::shared_ptr<Region>());
4140 vector<boost::shared_ptr<Playlist> >::iterator pl;
4142 for (pl = playlists.begin(); pl != playlists.end(); ++pl) {
4145 /* We might have removed regions, which alters other regions' layering_index,
4146 so we need to do a recursive diff here.
4148 vector<Command*> cmds;
4149 (*pl)->rdiff (cmds);
4150 _session->add_commands (cmds);
4152 _session->add_command(new StatefulDiffCommand (*pl));
4155 commit_reversible_command ();
4158 /** Cut, copy or clear selected regions.
4159 * @param op Operation (Cut, Copy or Clear)
4162 Editor::cut_copy_regions (CutCopyOp op, RegionSelection& rs)
4164 /* we can't use a std::map here because the ordering is important, and we can't trivially sort
4165 a map when we want ordered access to both elements. i think.
4168 vector<PlaylistMapping> pmap;
4170 framepos_t first_position = max_framepos;
4172 typedef set<boost::shared_ptr<Playlist> > FreezeList;
4173 FreezeList freezelist;
4175 /* get ordering correct before we cut/copy */
4177 rs.sort_by_position_and_track ();
4179 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
4181 first_position = min ((framepos_t) (*x)->region()->position(), first_position);
4183 if (op == Cut || op == Clear || op == Delete) {
4184 boost::shared_ptr<Playlist> pl = (*x)->region()->playlist();
4187 FreezeList::iterator fl;
4189 // only take state if this is a new playlist.
4190 for (fl = freezelist.begin(); fl != freezelist.end(); ++fl) {
4196 if (fl == freezelist.end()) {
4197 pl->clear_changes();
4198 pl->clear_owned_changes ();
4200 freezelist.insert (pl);
4205 TimeAxisView* tv = &(*x)->get_time_axis_view();
4206 vector<PlaylistMapping>::iterator z;
4208 for (z = pmap.begin(); z != pmap.end(); ++z) {
4209 if ((*z).tv == tv) {
4214 if (z == pmap.end()) {
4215 pmap.push_back (PlaylistMapping (tv));
4219 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ) {
4221 boost::shared_ptr<Playlist> pl = (*x)->region()->playlist();
4224 /* region not yet associated with a playlist (e.g. unfinished
4231 TimeAxisView& tv = (*x)->get_time_axis_view();
4232 boost::shared_ptr<Playlist> npl;
4233 RegionSelection::iterator tmp;
4240 vector<PlaylistMapping>::iterator z;
4242 for (z = pmap.begin(); z != pmap.end(); ++z) {
4243 if ((*z).tv == &tv) {
4248 assert (z != pmap.end());
4251 npl = PlaylistFactory::create (pl->data_type(), *_session, "cutlist", true);
4259 boost::shared_ptr<Region> r = (*x)->region();
4260 boost::shared_ptr<Region> _xx;
4266 pl->remove_region (r);
4267 if (Config->get_edit_mode() == Ripple)
4268 pl->ripple (r->position(), -r->length(), boost::shared_ptr<Region>());
4272 _xx = RegionFactory::create (r);
4273 npl->add_region (_xx, r->position() - first_position);
4274 pl->remove_region (r);
4275 if (Config->get_edit_mode() == Ripple)
4276 pl->ripple (r->position(), -r->length(), boost::shared_ptr<Region>());
4280 /* copy region before adding, so we're not putting same object into two different playlists */
4281 npl->add_region (RegionFactory::create (r), r->position() - first_position);
4285 pl->remove_region (r);
4286 if (Config->get_edit_mode() == Ripple)
4287 pl->ripple (r->position(), -r->length(), boost::shared_ptr<Region>());
4296 list<boost::shared_ptr<Playlist> > foo;
4298 /* the pmap is in the same order as the tracks in which selected regions occured */
4300 for (vector<PlaylistMapping>::iterator i = pmap.begin(); i != pmap.end(); ++i) {
4303 foo.push_back ((*i).pl);
4308 cut_buffer->set (foo);
4312 _last_cut_copy_source_track = 0;
4314 _last_cut_copy_source_track = pmap.front().tv;
4318 for (FreezeList::iterator pl = freezelist.begin(); pl != freezelist.end(); ++pl) {
4321 /* We might have removed regions, which alters other regions' layering_index,
4322 so we need to do a recursive diff here.
4324 vector<Command*> cmds;
4325 (*pl)->rdiff (cmds);
4326 _session->add_commands (cmds);
4328 _session->add_command (new StatefulDiffCommand (*pl));
4333 Editor::cut_copy_ranges (CutCopyOp op)
4335 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4337 /* Sort the track selection now, so that it if is used, the playlists
4338 selected by the calls below to cut_copy_clear are in the order that
4339 their tracks appear in the editor. This makes things like paste
4340 of ranges work properly.
4343 sort_track_selection (ts);
4346 if (!entered_track) {
4349 ts.push_back (entered_track);
4352 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4353 (*i)->cut_copy_clear (*selection, op);
4358 Editor::paste (float times, bool from_context)
4360 DEBUG_TRACE (DEBUG::CutNPaste, "paste to preferred edit pos\n");
4362 paste_internal (get_preferred_edit_position (false, from_context), times);
4366 Editor::mouse_paste ()
4371 if (!mouse_frame (where, ignored)) {
4376 paste_internal (where, 1);
4380 Editor::paste_internal (framepos_t position, float times)
4382 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("apparent paste position is %1\n", position));
4384 if (cut_buffer->empty(internal_editing())) {
4388 if (position == max_framepos) {
4389 position = get_preferred_edit_position();
4390 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("preferred edit position is %1\n", position));
4393 if (position == last_paste_pos) {
4394 /* repeated paste in the same position */
4397 /* paste in new location, reset repeated paste state */
4399 last_paste_pos = position;
4402 /* get everything in the correct order */
4405 if (!selection->tracks.empty()) {
4406 /* If there is a track selection, paste into exactly those tracks and
4407 only those tracks. This allows the user to be explicit and override
4408 the below "do the reasonable thing" logic. */
4409 ts = selection->tracks.filter_to_unique_playlists ();
4410 sort_track_selection (ts);
4412 /* Figure out which track to base the paste at. */
4413 TimeAxisView* base_track = NULL;
4414 if (_edit_point == Editing::EditAtMouse && entered_track) {
4415 /* With the mouse edit point, paste onto the track under the mouse. */
4416 base_track = entered_track;
4417 } else if (_edit_point == Editing::EditAtMouse && entered_regionview) {
4418 /* With the mouse edit point, paste onto the track of the region under the mouse. */
4419 base_track = &entered_regionview->get_time_axis_view();
4420 } else if (_last_cut_copy_source_track) {
4421 /* Paste to the track that the cut/copy came from (see mantis #333). */
4422 base_track = _last_cut_copy_source_track;
4424 /* This is "impossible" since we've copied... well, do nothing. */
4428 /* Walk up to parent if necessary, so base track is a route. */
4429 while (base_track->get_parent()) {
4430 base_track = base_track->get_parent();
4433 /* Add base track and all tracks below it. The paste logic will select
4434 the appropriate object types from the cut buffer in relative order. */
4435 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4436 if ((*i)->order() >= base_track->order()) {
4441 /* Sort tracks so the nth track of type T will pick the nth object of type T. */
4442 sort_track_selection (ts);
4444 /* Add automation children of each track in order, for pasting several lines. */
4445 for (TrackViewList::iterator i = ts.begin(); i != ts.end();) {
4446 /* Add any automation children for pasting several lines */
4447 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*i++);
4452 typedef RouteTimeAxisView::AutomationTracks ATracks;
4453 const ATracks& atracks = rtv->automation_tracks();
4454 for (ATracks::const_iterator a = atracks.begin(); a != atracks.end(); ++a) {
4455 i = ts.insert(i, a->second.get());
4460 /* We now have a list of trackviews starting at base_track, including
4461 automation children, in the order shown in the editor, e.g. R1,
4462 R1.A1, R1.A2, R2, R2.A1, ... */
4465 if (ts.size() == 1 && cut_buffer->lines.size() == 1 &&
4466 dynamic_cast<AutomationTimeAxisView*>(ts.front())) {
4467 /* Only one line copied, and one automation track selected. Do a
4468 "greedy" paste from one automation type to another. */
4470 begin_reversible_command (Operations::paste);
4472 PasteContext ctx(paste_count, times, ItemCounts(), true);
4473 ts.front()->paste (position, *cut_buffer, ctx);
4475 commit_reversible_command ();
4477 } else if (internal_editing ()) {
4479 /* undo/redo is handled by individual tracks/regions */
4482 get_regions_at (rs, position, ts);
4484 PasteContext ctx(paste_count, times, ItemCounts(), false);
4485 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
4486 MidiRegionView* mrv = dynamic_cast<MidiRegionView*> (*r);
4488 mrv->paste (position, *cut_buffer, ctx);
4494 /* we do redo (do you do voodoo?) */
4496 begin_reversible_command (Operations::paste);
4498 PasteContext ctx(paste_count, times, ItemCounts(), false);
4499 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4500 (*i)->paste (position, *cut_buffer, ctx);
4503 commit_reversible_command ();
4508 Editor::duplicate_some_regions (RegionSelection& regions, float times)
4510 boost::shared_ptr<Playlist> playlist;
4511 RegionSelection sel = regions; // clear (below) may clear the argument list if its the current region selection
4512 RegionSelection foo;
4514 framepos_t const start_frame = regions.start ();
4515 framepos_t const end_frame = regions.end_frame ();
4517 begin_reversible_command (Operations::duplicate_region);
4519 selection->clear_regions ();
4521 for (RegionSelection::iterator i = sel.begin(); i != sel.end(); ++i) {
4523 boost::shared_ptr<Region> r ((*i)->region());
4525 TimeAxisView& tv = (*i)->get_time_axis_view();
4526 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (&tv);
4527 latest_regionviews.clear ();
4528 sigc::connection c = rtv->view()->RegionViewAdded.connect (sigc::mem_fun(*this, &Editor::collect_new_region_view));
4530 playlist = (*i)->region()->playlist();
4531 playlist->clear_changes ();
4532 playlist->duplicate (r, end_frame + (r->first_frame() - start_frame), times);
4533 _session->add_command(new StatefulDiffCommand (playlist));
4537 foo.insert (foo.end(), latest_regionviews.begin(), latest_regionviews.end());
4540 commit_reversible_command ();
4543 selection->set (foo);
4548 Editor::duplicate_selection (float times)
4550 if (selection->time.empty() || selection->tracks.empty()) {
4554 boost::shared_ptr<Playlist> playlist;
4555 vector<boost::shared_ptr<Region> > new_regions;
4556 vector<boost::shared_ptr<Region> >::iterator ri;
4558 create_region_from_selection (new_regions);
4560 if (new_regions.empty()) {
4564 begin_reversible_command (_("duplicate selection"));
4566 ri = new_regions.begin();
4568 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4570 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4571 if ((playlist = (*i)->playlist()) == 0) {
4574 playlist->clear_changes ();
4575 playlist->duplicate (*ri, selection->time[clicked_selection].end, times);
4576 _session->add_command (new StatefulDiffCommand (playlist));
4579 if (ri == new_regions.end()) {
4584 commit_reversible_command ();
4587 /** Reset all selected points to the relevant default value */
4589 Editor::reset_point_selection ()
4591 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
4592 ARDOUR::AutomationList::iterator j = (*i)->model ();
4593 (*j)->value = (*i)->line().the_list()->default_value ();
4598 Editor::center_playhead ()
4600 float const page = _visible_canvas_width * samples_per_pixel;
4601 center_screen_internal (playhead_cursor->current_frame (), page);
4605 Editor::center_edit_point ()
4607 float const page = _visible_canvas_width * samples_per_pixel;
4608 center_screen_internal (get_preferred_edit_position(), page);
4611 /** Caller must begin and commit a reversible command */
4613 Editor::clear_playlist (boost::shared_ptr<Playlist> playlist)
4615 playlist->clear_changes ();
4617 _session->add_command (new StatefulDiffCommand (playlist));
4621 Editor::nudge_track (bool use_edit, bool forwards)
4623 boost::shared_ptr<Playlist> playlist;
4624 framepos_t distance;
4625 framepos_t next_distance;
4629 start = get_preferred_edit_position();
4634 if ((distance = get_nudge_distance (start, next_distance)) == 0) {
4638 if (selection->tracks.empty()) {
4642 begin_reversible_command (_("nudge track"));
4644 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4646 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4648 if ((playlist = (*i)->playlist()) == 0) {
4652 playlist->clear_changes ();
4653 playlist->clear_owned_changes ();
4655 playlist->nudge_after (start, distance, forwards);
4657 vector<Command*> cmds;
4659 playlist->rdiff (cmds);
4660 _session->add_commands (cmds);
4662 _session->add_command (new StatefulDiffCommand (playlist));
4665 commit_reversible_command ();
4669 Editor::remove_last_capture ()
4671 vector<string> choices;
4678 if (Config->get_verify_remove_last_capture()) {
4679 prompt = _("Do you really want to destroy the last capture?"
4680 "\n(This is destructive and cannot be undone)");
4682 choices.push_back (_("No, do nothing."));
4683 choices.push_back (_("Yes, destroy it."));
4685 Gtkmm2ext::Choice prompter (_("Destroy last capture"), prompt, choices);
4687 if (prompter.run () == 1) {
4688 _session->remove_last_capture ();
4689 _regions->redisplay ();
4693 _session->remove_last_capture();
4694 _regions->redisplay ();
4699 Editor::normalize_region ()
4705 RegionSelection rs = get_regions_from_selection_and_entered ();
4711 NormalizeDialog dialog (rs.size() > 1);
4713 if (dialog.run () == RESPONSE_CANCEL) {
4717 set_canvas_cursor (_cursors->wait);
4720 /* XXX: should really only count audio regions here */
4721 int const regions = rs.size ();
4723 /* Make a list of the selected audio regions' maximum amplitudes, and also
4724 obtain the maximum amplitude of them all.
4726 list<double> max_amps;
4728 for (RegionSelection::const_iterator i = rs.begin(); i != rs.end(); ++i) {
4729 AudioRegionView const * arv = dynamic_cast<AudioRegionView const *> (*i);
4731 dialog.descend (1.0 / regions);
4732 double const a = arv->audio_region()->maximum_amplitude (&dialog);
4735 /* the user cancelled the operation */
4736 set_canvas_cursor (current_canvas_cursor);
4740 max_amps.push_back (a);
4741 max_amp = max (max_amp, a);
4746 begin_reversible_command (_("normalize"));
4748 list<double>::const_iterator a = max_amps.begin ();
4750 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
4751 AudioRegionView* const arv = dynamic_cast<AudioRegionView*> (*r);
4756 arv->region()->clear_changes ();
4758 double const amp = dialog.normalize_individually() ? *a : max_amp;
4760 arv->audio_region()->normalize (amp, dialog.target ());
4761 _session->add_command (new StatefulDiffCommand (arv->region()));
4766 commit_reversible_command ();
4767 set_canvas_cursor (current_canvas_cursor);
4772 Editor::reset_region_scale_amplitude ()
4778 RegionSelection rs = get_regions_from_selection_and_entered ();
4784 begin_reversible_command ("reset gain");
4786 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
4787 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
4790 arv->region()->clear_changes ();
4791 arv->audio_region()->set_scale_amplitude (1.0f);
4792 _session->add_command (new StatefulDiffCommand (arv->region()));
4795 commit_reversible_command ();
4799 Editor::adjust_region_gain (bool up)
4801 RegionSelection rs = get_regions_from_selection_and_entered ();
4803 if (!_session || rs.empty()) {
4807 begin_reversible_command ("adjust region gain");
4809 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
4810 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
4815 arv->region()->clear_changes ();
4817 double dB = accurate_coefficient_to_dB (arv->audio_region()->scale_amplitude ());
4825 arv->audio_region()->set_scale_amplitude (dB_to_coefficient (dB));
4826 _session->add_command (new StatefulDiffCommand (arv->region()));
4829 commit_reversible_command ();
4834 Editor::reverse_region ()
4840 Reverse rev (*_session);
4841 apply_filter (rev, _("reverse regions"));
4845 Editor::strip_region_silence ()
4851 RegionSelection rs = get_regions_from_selection_and_entered ();
4857 std::list<RegionView*> audio_only;
4859 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
4860 AudioRegionView* const arv = dynamic_cast<AudioRegionView*> (*i);
4862 audio_only.push_back (arv);
4866 StripSilenceDialog d (_session, audio_only);
4867 int const r = d.run ();
4871 if (r == Gtk::RESPONSE_OK) {
4872 ARDOUR::AudioIntervalMap silences;
4873 d.silences (silences);
4874 StripSilence s (*_session, silences, d.fade_length());
4875 apply_filter (s, _("strip silence"), &d);
4880 Editor::apply_midi_note_edit_op_to_region (MidiOperator& op, MidiRegionView& mrv)
4882 Evoral::Sequence<Evoral::MusicalTime>::Notes selected;
4883 mrv.selection_as_notelist (selected, true);
4885 vector<Evoral::Sequence<Evoral::MusicalTime>::Notes> v;
4886 v.push_back (selected);
4888 framepos_t pos_frames = mrv.midi_region()->position() - mrv.midi_region()->start();
4889 Evoral::MusicalTime pos_beats = _session->tempo_map().framewalk_to_beats(0, pos_frames);
4891 return op (mrv.midi_region()->model(), pos_beats, v);
4895 Editor::apply_midi_note_edit_op (MidiOperator& op)
4899 RegionSelection rs = get_regions_from_selection_and_entered ();
4905 begin_reversible_command (op.name ());
4907 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
4908 RegionSelection::iterator tmp = r;
4911 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*r);
4914 cmd = apply_midi_note_edit_op_to_region (op, *mrv);
4917 _session->add_command (cmd);
4924 commit_reversible_command ();
4928 Editor::fork_region ()
4930 RegionSelection rs = get_regions_from_selection_and_entered ();
4936 begin_reversible_command (_("Fork Region(s)"));
4938 set_canvas_cursor (_cursors->wait);
4941 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
4942 RegionSelection::iterator tmp = r;
4945 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*>(*r);
4949 boost::shared_ptr<Playlist> playlist = mrv->region()->playlist();
4950 boost::shared_ptr<MidiSource> new_source = _session->create_midi_source_by_stealing_name (mrv->midi_view()->track());
4951 boost::shared_ptr<MidiRegion> newregion = mrv->midi_region()->clone (new_source);
4953 playlist->clear_changes ();
4954 playlist->replace_region (mrv->region(), newregion, mrv->region()->position());
4955 _session->add_command(new StatefulDiffCommand (playlist));
4957 error << string_compose (_("Could not unlink %1"), mrv->region()->name()) << endmsg;
4964 commit_reversible_command ();
4966 set_canvas_cursor (current_canvas_cursor);
4970 Editor::quantize_region ()
4972 int selected_midi_region_cnt = 0;
4978 RegionSelection rs = get_regions_from_selection_and_entered ();
4984 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
4985 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*r);
4987 selected_midi_region_cnt++;
4991 if (selected_midi_region_cnt == 0) {
4995 QuantizeDialog* qd = new QuantizeDialog (*this);
4998 const int r = qd->run ();
5001 if (r == Gtk::RESPONSE_OK) {
5002 Quantize quant (qd->snap_start(), qd->snap_end(),
5003 qd->start_grid_size(), qd->end_grid_size(),
5004 qd->strength(), qd->swing(), qd->threshold());
5006 apply_midi_note_edit_op (quant);
5011 Editor::legatize_region (bool shrink_only)
5013 int selected_midi_region_cnt = 0;
5019 RegionSelection rs = get_regions_from_selection_and_entered ();
5025 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
5026 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*r);
5028 selected_midi_region_cnt++;
5032 if (selected_midi_region_cnt == 0) {
5036 Legatize legatize(shrink_only);
5037 apply_midi_note_edit_op (legatize);
5041 Editor::insert_patch_change (bool from_context)
5043 RegionSelection rs = get_regions_from_selection_and_entered ();
5049 const framepos_t p = get_preferred_edit_position (false, from_context);
5051 /* XXX: bit of a hack; use the MIDNAM from the first selected region;
5052 there may be more than one, but the PatchChangeDialog can only offer
5053 one set of patch menus.
5055 MidiRegionView* first = dynamic_cast<MidiRegionView*> (rs.front ());
5057 Evoral::PatchChange<Evoral::MusicalTime> empty (Evoral::MusicalTime(), 0, 0, 0);
5058 PatchChangeDialog d (0, _session, empty, first->instrument_info(), Gtk::Stock::ADD);
5060 if (d.run() == RESPONSE_CANCEL) {
5064 for (RegionSelection::iterator i = rs.begin (); i != rs.end(); ++i) {
5065 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*i);
5067 if (p >= mrv->region()->first_frame() && p <= mrv->region()->last_frame()) {
5068 mrv->add_patch_change (p - mrv->region()->position(), d.patch ());
5075 Editor::apply_filter (Filter& filter, string command, ProgressReporter* progress)
5077 RegionSelection rs = get_regions_from_selection_and_entered ();
5083 begin_reversible_command (command);
5085 set_canvas_cursor (_cursors->wait);
5089 int const N = rs.size ();
5091 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
5092 RegionSelection::iterator tmp = r;
5095 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
5097 boost::shared_ptr<Playlist> playlist = arv->region()->playlist();
5100 progress->descend (1.0 / N);
5103 if (arv->audio_region()->apply (filter, progress) == 0) {
5105 playlist->clear_changes ();
5106 playlist->clear_owned_changes ();
5108 if (filter.results.empty ()) {
5110 /* no regions returned; remove the old one */
5111 playlist->remove_region (arv->region ());
5115 std::vector<boost::shared_ptr<Region> >::iterator res = filter.results.begin ();
5117 /* first region replaces the old one */
5118 playlist->replace_region (arv->region(), *res, (*res)->position());
5122 while (res != filter.results.end()) {
5123 playlist->add_region (*res, (*res)->position());
5129 /* We might have removed regions, which alters other regions' layering_index,
5130 so we need to do a recursive diff here.
5132 vector<Command*> cmds;
5133 playlist->rdiff (cmds);
5134 _session->add_commands (cmds);
5136 _session->add_command(new StatefulDiffCommand (playlist));
5142 progress->ascend ();
5150 commit_reversible_command ();
5153 set_canvas_cursor (current_canvas_cursor);
5157 Editor::external_edit_region ()
5163 Editor::reset_region_gain_envelopes ()
5165 RegionSelection rs = get_regions_from_selection_and_entered ();
5167 if (!_session || rs.empty()) {
5171 _session->begin_reversible_command (_("reset region gain"));
5173 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5174 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
5176 boost::shared_ptr<AutomationList> alist (arv->audio_region()->envelope());
5177 XMLNode& before (alist->get_state());
5179 arv->audio_region()->set_default_envelope ();
5180 _session->add_command (new MementoCommand<AutomationList>(*arv->audio_region()->envelope().get(), &before, &alist->get_state()));
5184 _session->commit_reversible_command ();
5188 Editor::set_region_gain_visibility (RegionView* rv)
5190 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (rv);
5192 arv->update_envelope_visibility();
5197 Editor::set_gain_envelope_visibility ()
5203 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5204 AudioTimeAxisView* v = dynamic_cast<AudioTimeAxisView*>(*i);
5206 v->audio_view()->foreach_regionview (sigc::mem_fun (this, &Editor::set_region_gain_visibility));
5212 Editor::toggle_gain_envelope_active ()
5214 if (_ignore_region_action) {
5218 RegionSelection rs = get_regions_from_selection_and_entered ();
5220 if (!_session || rs.empty()) {
5224 _session->begin_reversible_command (_("region gain envelope active"));
5226 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5227 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
5229 arv->region()->clear_changes ();
5230 arv->audio_region()->set_envelope_active (!arv->audio_region()->envelope_active());
5231 _session->add_command (new StatefulDiffCommand (arv->region()));
5235 _session->commit_reversible_command ();
5239 Editor::toggle_region_lock ()
5241 if (_ignore_region_action) {
5245 RegionSelection rs = get_regions_from_selection_and_entered ();
5247 if (!_session || rs.empty()) {
5251 _session->begin_reversible_command (_("toggle region lock"));
5253 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5254 (*i)->region()->clear_changes ();
5255 (*i)->region()->set_locked (!(*i)->region()->locked());
5256 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5259 _session->commit_reversible_command ();
5263 Editor::toggle_region_video_lock ()
5265 if (_ignore_region_action) {
5269 RegionSelection rs = get_regions_from_selection_and_entered ();
5271 if (!_session || rs.empty()) {
5275 _session->begin_reversible_command (_("Toggle Video Lock"));
5277 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5278 (*i)->region()->clear_changes ();
5279 (*i)->region()->set_video_locked (!(*i)->region()->video_locked());
5280 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5283 _session->commit_reversible_command ();
5287 Editor::toggle_region_lock_style ()
5289 if (_ignore_region_action) {
5293 RegionSelection rs = get_regions_from_selection_and_entered ();
5295 if (!_session || rs.empty()) {
5299 _session->begin_reversible_command (_("region lock style"));
5301 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5302 (*i)->region()->clear_changes ();
5303 PositionLockStyle const ns = (*i)->region()->position_lock_style() == AudioTime ? MusicTime : AudioTime;
5304 (*i)->region()->set_position_lock_style (ns);
5305 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5308 _session->commit_reversible_command ();
5312 Editor::toggle_opaque_region ()
5314 if (_ignore_region_action) {
5318 RegionSelection rs = get_regions_from_selection_and_entered ();
5320 if (!_session || rs.empty()) {
5324 _session->begin_reversible_command (_("change region opacity"));
5326 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5327 (*i)->region()->clear_changes ();
5328 (*i)->region()->set_opaque (!(*i)->region()->opaque());
5329 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5332 _session->commit_reversible_command ();
5336 Editor::toggle_record_enable ()
5338 bool new_state = false;
5340 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5341 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5344 if (!rtav->is_track())
5348 new_state = !rtav->track()->record_enabled();
5352 rtav->track()->set_record_enabled (new_state, this);
5357 Editor::toggle_solo ()
5359 bool new_state = false;
5361 boost::shared_ptr<RouteList> rl (new RouteList);
5363 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5364 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5371 new_state = !rtav->route()->soloed ();
5375 rl->push_back (rtav->route());
5378 _session->set_solo (rl, new_state, Session::rt_cleanup, true);
5382 Editor::toggle_mute ()
5384 bool new_state = false;
5386 boost::shared_ptr<RouteList> rl (new RouteList);
5388 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5389 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5396 new_state = !rtav->route()->muted();
5400 rl->push_back (rtav->route());
5403 _session->set_mute (rl, new_state, Session::rt_cleanup, true);
5407 Editor::toggle_solo_isolate ()
5413 Editor::fade_range ()
5415 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
5417 begin_reversible_command (_("fade range"));
5419 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
5420 (*i)->fade_range (selection->time);
5423 commit_reversible_command ();
5428 Editor::set_fade_length (bool in)
5430 RegionSelection rs = get_regions_from_selection_and_entered ();
5436 /* we need a region to measure the offset from the start */
5438 RegionView* rv = rs.front ();
5440 framepos_t pos = get_preferred_edit_position();
5444 if (pos > rv->region()->last_frame() || pos < rv->region()->first_frame()) {
5445 /* edit point is outside the relevant region */
5450 if (pos <= rv->region()->position()) {
5454 len = pos - rv->region()->position();
5455 cmd = _("set fade in length");
5457 if (pos >= rv->region()->last_frame()) {
5461 len = rv->region()->last_frame() - pos;
5462 cmd = _("set fade out length");
5465 begin_reversible_command (cmd);
5467 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5468 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5474 boost::shared_ptr<AutomationList> alist;
5476 alist = tmp->audio_region()->fade_in();
5478 alist = tmp->audio_region()->fade_out();
5481 XMLNode &before = alist->get_state();
5484 tmp->audio_region()->set_fade_in_length (len);
5485 tmp->audio_region()->set_fade_in_active (true);
5487 tmp->audio_region()->set_fade_out_length (len);
5488 tmp->audio_region()->set_fade_out_active (true);
5491 XMLNode &after = alist->get_state();
5492 _session->add_command(new MementoCommand<AutomationList>(*alist, &before, &after));
5495 commit_reversible_command ();
5499 Editor::set_fade_in_shape (FadeShape shape)
5501 RegionSelection rs = get_regions_from_selection_and_entered ();
5507 begin_reversible_command (_("set fade in shape"));
5509 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5510 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5516 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_in();
5517 XMLNode &before = alist->get_state();
5519 tmp->audio_region()->set_fade_in_shape (shape);
5521 XMLNode &after = alist->get_state();
5522 _session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
5525 commit_reversible_command ();
5530 Editor::set_fade_out_shape (FadeShape shape)
5532 RegionSelection rs = get_regions_from_selection_and_entered ();
5538 begin_reversible_command (_("set fade out shape"));
5540 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5541 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5547 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_out();
5548 XMLNode &before = alist->get_state();
5550 tmp->audio_region()->set_fade_out_shape (shape);
5552 XMLNode &after = alist->get_state();
5553 _session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
5556 commit_reversible_command ();
5560 Editor::set_fade_in_active (bool yn)
5562 RegionSelection rs = get_regions_from_selection_and_entered ();
5568 begin_reversible_command (_("set fade in active"));
5570 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5571 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5578 boost::shared_ptr<AudioRegion> ar (tmp->audio_region());
5580 ar->clear_changes ();
5581 ar->set_fade_in_active (yn);
5582 _session->add_command (new StatefulDiffCommand (ar));
5585 commit_reversible_command ();
5589 Editor::set_fade_out_active (bool yn)
5591 RegionSelection rs = get_regions_from_selection_and_entered ();
5597 begin_reversible_command (_("set fade out active"));
5599 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5600 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5606 boost::shared_ptr<AudioRegion> ar (tmp->audio_region());
5608 ar->clear_changes ();
5609 ar->set_fade_out_active (yn);
5610 _session->add_command(new StatefulDiffCommand (ar));
5613 commit_reversible_command ();
5617 Editor::toggle_region_fades (int dir)
5619 if (_ignore_region_action) {
5623 boost::shared_ptr<AudioRegion> ar;
5626 RegionSelection rs = get_regions_from_selection_and_entered ();
5632 RegionSelection::iterator i;
5633 for (i = rs.begin(); i != rs.end(); ++i) {
5634 if ((ar = boost::dynamic_pointer_cast<AudioRegion>((*i)->region())) != 0) {
5636 yn = ar->fade_out_active ();
5638 yn = ar->fade_in_active ();
5644 if (i == rs.end()) {
5648 /* XXX should this undo-able? */
5650 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5651 if ((ar = boost::dynamic_pointer_cast<AudioRegion>((*i)->region())) == 0) {
5654 if (dir == 1 || dir == 0) {
5655 ar->set_fade_in_active (!yn);
5658 if (dir == -1 || dir == 0) {
5659 ar->set_fade_out_active (!yn);
5665 /** Update region fade visibility after its configuration has been changed */
5667 Editor::update_region_fade_visibility ()
5669 bool _fade_visibility = _session->config.get_show_region_fades ();
5671 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5672 AudioTimeAxisView* v = dynamic_cast<AudioTimeAxisView*>(*i);
5674 if (_fade_visibility) {
5675 v->audio_view()->show_all_fades ();
5677 v->audio_view()->hide_all_fades ();
5684 Editor::set_edit_point ()
5689 if (!mouse_frame (where, ignored)) {
5695 if (selection->markers.empty()) {
5697 mouse_add_new_marker (where);
5702 Location* loc = find_location_from_marker (selection->markers.front(), ignored);
5705 loc->move_to (where);
5711 Editor::set_playhead_cursor ()
5713 if (entered_marker) {
5714 _session->request_locate (entered_marker->position(), _session->transport_rolling());
5719 if (!mouse_frame (where, ignored)) {
5726 _session->request_locate (where, _session->transport_rolling());
5730 if ( Config->get_follow_edits() )
5731 cancel_time_selection();
5735 Editor::split_region ()
5737 if ( !selection->time.empty()) {
5738 separate_regions_between (selection->time);
5742 RegionSelection rs = get_regions_from_selection_and_edit_point ();
5744 framepos_t where = get_preferred_edit_position ();
5750 split_regions_at (where, rs);
5753 struct EditorOrderRouteSorter {
5754 bool operator() (boost::shared_ptr<Route> a, boost::shared_ptr<Route> b) {
5755 return a->order_key () < b->order_key ();
5760 Editor::select_next_route()
5762 if (selection->tracks.empty()) {
5763 selection->set (track_views.front());
5767 TimeAxisView* current = selection->tracks.front();
5771 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5772 if (*i == current) {
5774 if (i != track_views.end()) {
5777 current = (*(track_views.begin()));
5778 //selection->set (*(track_views.begin()));
5783 rui = dynamic_cast<RouteUI *>(current);
5784 } while ( current->hidden() || (rui != NULL && !rui->route()->active()));
5786 selection->set(current);
5788 ensure_time_axis_view_is_visible (*current, false);
5792 Editor::select_prev_route()
5794 if (selection->tracks.empty()) {
5795 selection->set (track_views.front());
5799 TimeAxisView* current = selection->tracks.front();
5803 for (TrackViewList::reverse_iterator i = track_views.rbegin(); i != track_views.rend(); ++i) {
5804 if (*i == current) {
5806 if (i != track_views.rend()) {
5809 current = *(track_views.rbegin());
5814 rui = dynamic_cast<RouteUI *>(current);
5815 } while ( current->hidden() || (rui != NULL && !rui->route()->active()));
5817 selection->set (current);
5819 ensure_time_axis_view_is_visible (*current, false);
5823 Editor::set_loop_from_selection (bool play)
5825 if (_session == 0 || selection->time.empty()) {
5829 framepos_t start = selection->time[clicked_selection].start;
5830 framepos_t end = selection->time[clicked_selection].end;
5832 set_loop_range (start, end, _("set loop range from selection"));
5835 _session->request_locate (start, true);
5836 _session->request_play_loop (true);
5841 Editor::set_loop_from_edit_range (bool play)
5843 if (_session == 0) {
5850 if (!get_edit_op_range (start, end)) {
5854 set_loop_range (start, end, _("set loop range from edit range"));
5857 _session->request_locate (start, true);
5858 _session->request_play_loop (true);
5863 Editor::set_loop_from_region (bool play)
5865 framepos_t start = max_framepos;
5868 RegionSelection rs = get_regions_from_selection_and_entered ();
5874 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5875 if ((*i)->region()->position() < start) {
5876 start = (*i)->region()->position();
5878 if ((*i)->region()->last_frame() + 1 > end) {
5879 end = (*i)->region()->last_frame() + 1;
5883 set_loop_range (start, end, _("set loop range from region"));
5886 _session->request_locate (start, true);
5887 _session->request_play_loop (true);
5892 Editor::set_punch_from_selection ()
5894 if (_session == 0 || selection->time.empty()) {
5898 framepos_t start = selection->time[clicked_selection].start;
5899 framepos_t end = selection->time[clicked_selection].end;
5901 set_punch_range (start, end, _("set punch range from selection"));
5905 Editor::set_punch_from_edit_range ()
5907 if (_session == 0) {
5914 if (!get_edit_op_range (start, end)) {
5918 set_punch_range (start, end, _("set punch range from edit range"));
5922 Editor::set_punch_from_region ()
5924 framepos_t start = max_framepos;
5927 RegionSelection rs = get_regions_from_selection_and_entered ();
5933 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5934 if ((*i)->region()->position() < start) {
5935 start = (*i)->region()->position();
5937 if ((*i)->region()->last_frame() + 1 > end) {
5938 end = (*i)->region()->last_frame() + 1;
5942 set_punch_range (start, end, _("set punch range from region"));
5946 Editor::pitch_shift_region ()
5948 RegionSelection rs = get_regions_from_selection_and_entered ();
5950 RegionSelection audio_rs;
5951 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5952 if (dynamic_cast<AudioRegionView*> (*i)) {
5953 audio_rs.push_back (*i);
5957 if (audio_rs.empty()) {
5961 pitch_shift (audio_rs, 1.2);
5965 Editor::transpose_region ()
5967 RegionSelection rs = get_regions_from_selection_and_entered ();
5969 list<MidiRegionView*> midi_region_views;
5970 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5971 MidiRegionView* mrv = dynamic_cast<MidiRegionView*> (*i);
5973 midi_region_views.push_back (mrv);
5978 int const r = d.run ();
5979 if (r != RESPONSE_ACCEPT) {
5983 for (list<MidiRegionView*>::iterator i = midi_region_views.begin(); i != midi_region_views.end(); ++i) {
5984 (*i)->midi_region()->transpose (d.semitones ());
5989 Editor::set_tempo_from_region ()
5991 RegionSelection rs = get_regions_from_selection_and_entered ();
5993 if (!_session || rs.empty()) {
5997 RegionView* rv = rs.front();
5999 define_one_bar (rv->region()->position(), rv->region()->last_frame() + 1);
6003 Editor::use_range_as_bar ()
6005 framepos_t start, end;
6006 if (get_edit_op_range (start, end)) {
6007 define_one_bar (start, end);
6012 Editor::define_one_bar (framepos_t start, framepos_t end)
6014 framepos_t length = end - start;
6016 const Meter& m (_session->tempo_map().meter_at (start));
6018 /* length = 1 bar */
6020 /* now we want frames per beat.
6021 we have frames per bar, and beats per bar, so ...
6024 /* XXXX METER MATH */
6026 double frames_per_beat = length / m.divisions_per_bar();
6028 /* beats per minute = */
6030 double beats_per_minute = (_session->frame_rate() * 60.0) / frames_per_beat;
6032 /* now decide whether to:
6034 (a) set global tempo
6035 (b) add a new tempo marker
6039 const TempoSection& t (_session->tempo_map().tempo_section_at (start));
6041 bool do_global = false;
6043 if ((_session->tempo_map().n_tempos() == 1) && (_session->tempo_map().n_meters() == 1)) {
6045 /* only 1 tempo & 1 meter: ask if the user wants to set the tempo
6046 at the start, or create a new marker
6049 vector<string> options;
6050 options.push_back (_("Cancel"));
6051 options.push_back (_("Add new marker"));
6052 options.push_back (_("Set global tempo"));
6055 _("Define one bar"),
6056 _("Do you want to set the global tempo or add a new tempo marker?"),
6060 c.set_default_response (2);
6076 /* more than 1 tempo and/or meter section already, go ahead do the "usual":
6077 if the marker is at the region starter, change it, otherwise add
6082 begin_reversible_command (_("set tempo from region"));
6083 XMLNode& before (_session->tempo_map().get_state());
6086 _session->tempo_map().change_initial_tempo (beats_per_minute, t.note_type());
6087 } else if (t.frame() == start) {
6088 _session->tempo_map().change_existing_tempo_at (start, beats_per_minute, t.note_type());
6090 Timecode::BBT_Time bbt;
6091 _session->tempo_map().bbt_time (start, bbt);
6092 _session->tempo_map().add_tempo (Tempo (beats_per_minute, t.note_type()), bbt);
6095 XMLNode& after (_session->tempo_map().get_state());
6097 _session->add_command (new MementoCommand<TempoMap>(_session->tempo_map(), &before, &after));
6098 commit_reversible_command ();
6102 Editor::split_region_at_transients ()
6104 AnalysisFeatureList positions;
6106 RegionSelection rs = get_regions_from_selection_and_entered ();
6108 if (!_session || rs.empty()) {
6112 _session->begin_reversible_command (_("split regions"));
6114 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ) {
6116 RegionSelection::iterator tmp;
6121 boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion> ((*i)->region());
6123 if (ar && (ar->get_transients (positions) == 0)) {
6124 split_region_at_points ((*i)->region(), positions, true);
6131 _session->commit_reversible_command ();
6136 Editor::split_region_at_points (boost::shared_ptr<Region> r, AnalysisFeatureList& positions, bool can_ferret, bool select_new)
6138 bool use_rhythmic_rodent = false;
6140 boost::shared_ptr<Playlist> pl = r->playlist();
6142 list<boost::shared_ptr<Region> > new_regions;
6148 if (positions.empty()) {
6153 if (positions.size() > 20 && can_ferret) {
6154 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);
6155 MessageDialog msg (msgstr,
6158 Gtk::BUTTONS_OK_CANCEL);
6161 msg.add_button (_("Call for the Ferret!"), RESPONSE_APPLY);
6162 msg.set_secondary_text (_("Press OK to continue with this split operation\nor ask the Ferret dialog to tune the analysis"));
6164 msg.set_secondary_text (_("Press OK to continue with this split operation"));
6167 msg.set_title (_("Excessive split?"));
6170 int response = msg.run();
6176 case RESPONSE_APPLY:
6177 use_rhythmic_rodent = true;
6184 if (use_rhythmic_rodent) {
6185 show_rhythm_ferret ();
6189 AnalysisFeatureList::const_iterator x;
6191 pl->clear_changes ();
6192 pl->clear_owned_changes ();
6194 x = positions.begin();
6196 if (x == positions.end()) {
6201 pl->remove_region (r);
6205 while (x != positions.end()) {
6207 /* deal with positons that are out of scope of present region bounds */
6208 if (*x <= 0 || *x > r->length()) {
6213 /* file start = original start + how far we from the initial position ?
6216 framepos_t file_start = r->start() + pos;
6218 /* length = next position - current position
6221 framepos_t len = (*x) - pos;
6223 /* XXX we do we really want to allow even single-sample regions?
6224 shouldn't we have some kind of lower limit on region size?
6233 if (RegionFactory::region_name (new_name, r->name())) {
6237 /* do NOT announce new regions 1 by one, just wait till they are all done */
6241 plist.add (ARDOUR::Properties::start, file_start);
6242 plist.add (ARDOUR::Properties::length, len);
6243 plist.add (ARDOUR::Properties::name, new_name);
6244 plist.add (ARDOUR::Properties::layer, 0);
6246 boost::shared_ptr<Region> nr = RegionFactory::create (r->sources(), plist, false);
6247 /* because we set annouce to false, manually add the new region to the
6250 RegionFactory::map_add (nr);
6252 pl->add_region (nr, r->position() + pos);
6255 new_regions.push_front(nr);
6264 RegionFactory::region_name (new_name, r->name());
6266 /* Add the final region */
6269 plist.add (ARDOUR::Properties::start, r->start() + pos);
6270 plist.add (ARDOUR::Properties::length, r->last_frame() - (r->position() + pos) + 1);
6271 plist.add (ARDOUR::Properties::name, new_name);
6272 plist.add (ARDOUR::Properties::layer, 0);
6274 boost::shared_ptr<Region> nr = RegionFactory::create (r->sources(), plist, false);
6275 /* because we set annouce to false, manually add the new region to the
6278 RegionFactory::map_add (nr);
6279 pl->add_region (nr, r->position() + pos);
6282 new_regions.push_front(nr);
6287 /* We might have removed regions, which alters other regions' layering_index,
6288 so we need to do a recursive diff here.
6290 vector<Command*> cmds;
6292 _session->add_commands (cmds);
6294 _session->add_command (new StatefulDiffCommand (pl));
6298 for (list<boost::shared_ptr<Region> >::iterator i = new_regions.begin(); i != new_regions.end(); ++i){
6299 set_selected_regionview_from_region_list ((*i), Selection::Add);
6305 Editor::place_transient()
6311 RegionSelection rs = get_regions_from_selection_and_edit_point ();
6317 framepos_t where = get_preferred_edit_position();
6319 _session->begin_reversible_command (_("place transient"));
6321 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6322 framepos_t position = (*r)->region()->position();
6323 (*r)->region()->add_transient(where - position);
6326 _session->commit_reversible_command ();
6330 Editor::remove_transient(ArdourCanvas::Item* item)
6336 ArdourCanvas::Line* _line = reinterpret_cast<ArdourCanvas::Line*> (item);
6339 AudioRegionView* _arv = reinterpret_cast<AudioRegionView*> (item->get_data ("regionview"));
6340 _arv->remove_transient (*(float*) _line->get_data ("position"));
6344 Editor::snap_regions_to_grid ()
6346 list <boost::shared_ptr<Playlist > > used_playlists;
6348 RegionSelection rs = get_regions_from_selection_and_entered ();
6350 if (!_session || rs.empty()) {
6354 _session->begin_reversible_command (_("snap regions to grid"));
6356 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6358 boost::shared_ptr<Playlist> pl = (*r)->region()->playlist();
6360 if (!pl->frozen()) {
6361 /* we haven't seen this playlist before */
6363 /* remember used playlists so we can thaw them later */
6364 used_playlists.push_back(pl);
6368 framepos_t start_frame = (*r)->region()->first_frame ();
6369 snap_to (start_frame);
6370 (*r)->region()->set_position (start_frame);
6373 while (used_playlists.size() > 0) {
6374 list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
6376 used_playlists.pop_front();
6379 _session->commit_reversible_command ();
6383 Editor::close_region_gaps ()
6385 list <boost::shared_ptr<Playlist > > used_playlists;
6387 RegionSelection rs = get_regions_from_selection_and_entered ();
6389 if (!_session || rs.empty()) {
6393 Dialog dialog (_("Close Region Gaps"));
6396 table.set_spacings (12);
6397 table.set_border_width (12);
6398 Label* l = manage (left_aligned_label (_("Crossfade length")));
6399 table.attach (*l, 0, 1, 0, 1);
6401 SpinButton spin_crossfade (1, 0);
6402 spin_crossfade.set_range (0, 15);
6403 spin_crossfade.set_increments (1, 1);
6404 spin_crossfade.set_value (5);
6405 table.attach (spin_crossfade, 1, 2, 0, 1);
6407 table.attach (*manage (new Label (_("ms"))), 2, 3, 0, 1);
6409 l = manage (left_aligned_label (_("Pull-back length")));
6410 table.attach (*l, 0, 1, 1, 2);
6412 SpinButton spin_pullback (1, 0);
6413 spin_pullback.set_range (0, 100);
6414 spin_pullback.set_increments (1, 1);
6415 spin_pullback.set_value(30);
6416 table.attach (spin_pullback, 1, 2, 1, 2);
6418 table.attach (*manage (new Label (_("ms"))), 2, 3, 1, 2);
6420 dialog.get_vbox()->pack_start (table);
6421 dialog.add_button (Stock::CANCEL, RESPONSE_CANCEL);
6422 dialog.add_button (_("Ok"), RESPONSE_ACCEPT);
6425 if (dialog.run () == RESPONSE_CANCEL) {
6429 framepos_t crossfade_len = spin_crossfade.get_value();
6430 framepos_t pull_back_frames = spin_pullback.get_value();
6432 crossfade_len = lrintf (crossfade_len * _session->frame_rate()/1000);
6433 pull_back_frames = lrintf (pull_back_frames * _session->frame_rate()/1000);
6435 /* Iterate over the region list and make adjacent regions overlap by crossfade_len_ms */
6437 _session->begin_reversible_command (_("close region gaps"));
6440 boost::shared_ptr<Region> last_region;
6442 rs.sort_by_position_and_track();
6444 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6446 boost::shared_ptr<Playlist> pl = (*r)->region()->playlist();
6448 if (!pl->frozen()) {
6449 /* we haven't seen this playlist before */
6451 /* remember used playlists so we can thaw them later */
6452 used_playlists.push_back(pl);
6456 framepos_t position = (*r)->region()->position();
6458 if (idx == 0 || position < last_region->position()){
6459 last_region = (*r)->region();
6464 (*r)->region()->trim_front( (position - pull_back_frames));
6465 last_region->trim_end( (position - pull_back_frames + crossfade_len));
6467 last_region = (*r)->region();
6472 while (used_playlists.size() > 0) {
6473 list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
6475 used_playlists.pop_front();
6478 _session->commit_reversible_command ();
6482 Editor::tab_to_transient (bool forward)
6484 AnalysisFeatureList positions;
6486 RegionSelection rs = get_regions_from_selection_and_entered ();
6492 framepos_t pos = _session->audible_frame ();
6494 if (!selection->tracks.empty()) {
6496 /* don't waste time searching for transients in duplicate playlists.
6499 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
6501 for (TrackViewList::iterator t = ts.begin(); t != ts.end(); ++t) {
6503 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*t);
6506 boost::shared_ptr<Track> tr = rtv->track();
6508 boost::shared_ptr<Playlist> pl = tr->playlist ();
6510 framepos_t result = pl->find_next_transient (pos, forward ? 1 : -1);
6513 positions.push_back (result);
6526 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6527 (*r)->region()->get_transients (positions);
6531 TransientDetector::cleanup_transients (positions, _session->frame_rate(), 3.0);
6534 AnalysisFeatureList::iterator x;
6536 for (x = positions.begin(); x != positions.end(); ++x) {
6542 if (x != positions.end ()) {
6543 _session->request_locate (*x);
6547 AnalysisFeatureList::reverse_iterator x;
6549 for (x = positions.rbegin(); x != positions.rend(); ++x) {
6555 if (x != positions.rend ()) {
6556 _session->request_locate (*x);
6562 Editor::playhead_forward_to_grid ()
6568 framepos_t pos = playhead_cursor->current_frame ();
6569 if (pos < max_framepos - 1) {
6571 snap_to_internal (pos, RoundUpAlways, false);
6572 _session->request_locate (pos);
6578 Editor::playhead_backward_to_grid ()
6584 framepos_t pos = playhead_cursor->current_frame ();
6587 snap_to_internal (pos, RoundDownAlways, false);
6588 _session->request_locate (pos);
6593 Editor::set_track_height (Height h)
6595 TrackSelection& ts (selection->tracks);
6597 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
6598 (*x)->set_height_enum (h);
6603 Editor::toggle_tracks_active ()
6605 TrackSelection& ts (selection->tracks);
6607 bool target = false;
6613 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
6614 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*x);
6618 target = !rtv->_route->active();
6621 rtv->_route->set_active (target, this);
6627 Editor::remove_tracks ()
6629 TrackSelection& ts (selection->tracks);
6635 vector<string> choices;
6639 const char* trackstr;
6641 vector<boost::shared_ptr<Route> > routes;
6642 bool special_bus = false;
6644 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
6645 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*x);
6649 if (rtv->is_track()) {
6654 routes.push_back (rtv->_route);
6656 if (rtv->route()->is_master() || rtv->route()->is_monitor()) {
6661 if (special_bus && !Config->get_allow_special_bus_removal()) {
6662 MessageDialog msg (_("That would be bad news ...."),
6666 msg.set_secondary_text (string_compose (_(
6667 "Removing the master or monitor bus is such a bad idea\n\
6668 that %1 is not going to allow it.\n\
6670 If you really want to do this sort of thing\n\
6671 edit your ardour.rc file to set the\n\
6672 \"allow-special-bus-removal\" option to be \"yes\""), PROGRAM_NAME));
6679 if (ntracks + nbusses == 0) {
6683 // XXX should be using gettext plural forms, maybe?
6685 trackstr = _("tracks");
6687 trackstr = _("track");
6691 busstr = _("busses");
6698 prompt = string_compose (_("Do you really want to remove %1 %2 and %3 %4?\n"
6699 "(You may also lose the playlists associated with the %2)\n\n"
6700 "This action cannot be undone, and the session file will be overwritten!"),
6701 ntracks, trackstr, nbusses, busstr);
6703 prompt = string_compose (_("Do you really want to remove %1 %2?\n"
6704 "(You may also lose the playlists associated with the %2)\n\n"
6705 "This action cannot be undone, and the session file will be overwritten!"),
6708 } else if (nbusses) {
6709 prompt = string_compose (_("Do you really want to remove %1 %2?\n\n"
6710 "This action cannot be undone, and the session file will be overwritten"),
6714 choices.push_back (_("No, do nothing."));
6715 if (ntracks + nbusses > 1) {
6716 choices.push_back (_("Yes, remove them."));
6718 choices.push_back (_("Yes, remove it."));
6723 title = string_compose (_("Remove %1"), trackstr);
6725 title = string_compose (_("Remove %1"), busstr);
6728 Choice prompter (title, prompt, choices);
6730 if (prompter.run () != 1) {
6735 Session::StateProtector sp (_session);
6736 DisplaySuspender ds;
6737 for (vector<boost::shared_ptr<Route> >::iterator x = routes.begin(); x != routes.end(); ++x) {
6738 _session->remove_route (*x);
6744 Editor::do_insert_time ()
6746 if (selection->tracks.empty()) {
6750 InsertTimeDialog d (*this);
6751 int response = d.run ();
6753 if (response != RESPONSE_OK) {
6757 if (d.distance() == 0) {
6761 InsertTimeOption opt = d.intersected_region_action ();
6764 get_preferred_edit_position(),
6770 d.move_glued_markers(),
6771 d.move_locked_markers(),
6777 Editor::insert_time (
6778 framepos_t pos, framecnt_t frames, InsertTimeOption opt,
6779 bool all_playlists, bool ignore_music_glue, bool markers_too, bool glued_markers_too, bool locked_markers_too, bool tempo_too
6782 bool commit = false;
6784 if (Config->get_edit_mode() == Lock) {
6788 begin_reversible_command (_("insert time"));
6790 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
6792 for (TrackViewList::iterator x = ts.begin(); x != ts.end(); ++x) {
6796 /* don't operate on any playlist more than once, which could
6797 * happen if "all playlists" is enabled, but there is more
6798 * than 1 track using playlists "from" a given track.
6801 set<boost::shared_ptr<Playlist> > pl;
6803 if (all_playlists) {
6804 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*x);
6806 vector<boost::shared_ptr<Playlist> > all = _session->playlists->playlists_for_track (rtav->track ());
6807 for (vector<boost::shared_ptr<Playlist> >::iterator p = all.begin(); p != all.end(); ++p) {
6812 if ((*x)->playlist ()) {
6813 pl.insert ((*x)->playlist ());
6817 for (set<boost::shared_ptr<Playlist> >::iterator i = pl.begin(); i != pl.end(); ++i) {
6819 (*i)->clear_changes ();
6820 (*i)->clear_owned_changes ();
6822 if (opt == SplitIntersected) {
6826 (*i)->shift (pos, frames, (opt == MoveIntersected), ignore_music_glue);
6828 vector<Command*> cmds;
6830 _session->add_commands (cmds);
6832 _session->add_command (new StatefulDiffCommand (*i));
6837 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*x);
6839 rtav->route ()->shift (pos, frames);
6847 XMLNode& before (_session->locations()->get_state());
6848 Locations::LocationList copy (_session->locations()->list());
6850 for (Locations::LocationList::iterator i = copy.begin(); i != copy.end(); ++i) {
6852 Locations::LocationList::const_iterator tmp;
6854 bool const was_locked = (*i)->locked ();
6855 if (locked_markers_too) {
6859 if ((*i)->position_lock_style() == AudioTime || glued_markers_too) {
6861 if ((*i)->start() >= pos) {
6862 (*i)->set_start ((*i)->start() + frames);
6863 if (!(*i)->is_mark()) {
6864 (*i)->set_end ((*i)->end() + frames);
6877 XMLNode& after (_session->locations()->get_state());
6878 _session->add_command (new MementoCommand<Locations>(*_session->locations(), &before, &after));
6883 _session->tempo_map().insert_time (pos, frames);
6887 commit_reversible_command ();
6892 Editor::fit_selected_tracks ()
6894 if (!selection->tracks.empty()) {
6895 fit_tracks (selection->tracks);
6899 /* no selected tracks - use tracks with selected regions */
6901 if (!selection->regions.empty()) {
6902 for (RegionSelection::iterator r = selection->regions.begin(); r != selection->regions.end(); ++r) {
6903 tvl.push_back (&(*r)->get_time_axis_view ());
6909 } else if (internal_editing()) {
6910 /* no selected tracks, or regions, but in internal edit mode, so follow the mouse and use
6913 if (entered_track) {
6914 tvl.push_back (entered_track);
6923 Editor::fit_tracks (TrackViewList & tracks)
6925 if (tracks.empty()) {
6929 uint32_t child_heights = 0;
6930 int visible_tracks = 0;
6932 for (TrackSelection::iterator t = tracks.begin(); t != tracks.end(); ++t) {
6934 if (!(*t)->marked_for_display()) {
6938 child_heights += (*t)->effective_height() - (*t)->current_height();
6942 /* compute the per-track height from:
6944 total canvas visible height -
6945 height that will be taken by visible children of selected
6946 tracks - height of the ruler/hscroll area
6948 uint32_t h = (uint32_t) floor ((trackviews_height() - child_heights) / visible_tracks);
6949 double first_y_pos = DBL_MAX;
6951 if (h < TimeAxisView::preset_height (HeightSmall)) {
6952 MessageDialog msg (*this, _("There are too many tracks to fit in the current window"));
6953 /* too small to be displayed */
6957 undo_visual_stack.push_back (current_visual_state (true));
6958 no_save_visual = true;
6960 /* build a list of all tracks, including children */
6963 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
6965 TimeAxisView::Children c = (*i)->get_child_list ();
6966 for (TimeAxisView::Children::iterator j = c.begin(); j != c.end(); ++j) {
6967 all.push_back (j->get());
6971 bool prev_was_selected = false;
6972 bool is_selected = tracks.contains (all.front());
6973 bool next_is_selected;
6975 for (TrackViewList::iterator t = all.begin(); t != all.end(); ++t) {
6977 TrackViewList::iterator next;
6982 if (next != all.end()) {
6983 next_is_selected = tracks.contains (*next);
6985 next_is_selected = false;
6988 if ((*t)->marked_for_display ()) {
6990 (*t)->set_height (h);
6991 first_y_pos = std::min ((*t)->y_position (), first_y_pos);
6993 if (prev_was_selected && next_is_selected) {
6994 hide_track_in_display (*t);
6999 prev_was_selected = is_selected;
7000 is_selected = next_is_selected;
7004 set the controls_layout height now, because waiting for its size
7005 request signal handler will cause the vertical adjustment setting to fail
7008 controls_layout.property_height () = _full_canvas_height;
7009 vertical_adjustment.set_value (first_y_pos);
7011 redo_visual_stack.push_back (current_visual_state (true));
7013 visible_tracks_selector.set_text (_("Sel"));
7017 Editor::save_visual_state (uint32_t n)
7019 while (visual_states.size() <= n) {
7020 visual_states.push_back (0);
7023 if (visual_states[n] != 0) {
7024 delete visual_states[n];
7027 visual_states[n] = current_visual_state (true);
7032 Editor::goto_visual_state (uint32_t n)
7034 if (visual_states.size() <= n) {
7038 if (visual_states[n] == 0) {
7042 use_visual_state (*visual_states[n]);
7046 Editor::start_visual_state_op (uint32_t n)
7048 save_visual_state (n);
7050 PopUp* pup = new PopUp (WIN_POS_MOUSE, 1000, true);
7052 snprintf (buf, sizeof (buf), _("Saved view %u"), n+1);
7053 pup->set_text (buf);
7058 Editor::cancel_visual_state_op (uint32_t n)
7060 goto_visual_state (n);
7064 Editor::toggle_region_mute ()
7066 if (_ignore_region_action) {
7070 RegionSelection rs = get_regions_from_selection_and_entered ();
7076 if (rs.size() > 1) {
7077 begin_reversible_command (_("mute regions"));
7079 begin_reversible_command (_("mute region"));
7082 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
7084 (*i)->region()->playlist()->clear_changes ();
7085 (*i)->region()->set_muted (!(*i)->region()->muted ());
7086 _session->add_command (new StatefulDiffCommand ((*i)->region()->playlist()));
7090 commit_reversible_command ();
7094 Editor::combine_regions ()
7096 /* foreach track with selected regions, take all selected regions
7097 and join them into a new region containing the subregions (as a
7101 typedef set<RouteTimeAxisView*> RTVS;
7104 if (selection->regions.empty()) {
7108 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
7109 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(&(*i)->get_time_axis_view());
7112 tracks.insert (rtv);
7116 begin_reversible_command (_("combine regions"));
7118 vector<RegionView*> new_selection;
7120 for (RTVS::iterator i = tracks.begin(); i != tracks.end(); ++i) {
7123 if ((rv = (*i)->combine_regions ()) != 0) {
7124 new_selection.push_back (rv);
7128 selection->clear_regions ();
7129 for (vector<RegionView*>::iterator i = new_selection.begin(); i != new_selection.end(); ++i) {
7130 selection->add (*i);
7133 commit_reversible_command ();
7137 Editor::uncombine_regions ()
7139 typedef set<RouteTimeAxisView*> RTVS;
7142 if (selection->regions.empty()) {
7146 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
7147 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(&(*i)->get_time_axis_view());
7150 tracks.insert (rtv);
7154 begin_reversible_command (_("uncombine regions"));
7156 for (RTVS::iterator i = tracks.begin(); i != tracks.end(); ++i) {
7157 (*i)->uncombine_regions ();
7160 commit_reversible_command ();
7164 Editor::toggle_midi_input_active (bool flip_others)
7167 boost::shared_ptr<RouteList> rl (new RouteList);
7169 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
7170 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
7176 boost::shared_ptr<MidiTrack> mt = rtav->midi_track();
7179 rl->push_back (rtav->route());
7180 onoff = !mt->input_active();
7184 _session->set_exclusive_input_active (rl, onoff, flip_others);
7191 lock_dialog = new Gtk::Dialog (string_compose (_("%1: Locked"), PROGRAM_NAME), true);
7193 Gtk::Image* padlock = manage (new Gtk::Image (ARDOUR_UI_UTILS::get_icon ("padlock_closed")));
7194 lock_dialog->get_vbox()->pack_start (*padlock);
7196 ArdourButton* b = manage (new ArdourButton);
7197 b->set_name ("lock button");
7198 b->set_text (_("Click to unlock"));
7199 b->signal_clicked.connect (sigc::mem_fun (*this, &Editor::unlock));
7200 lock_dialog->get_vbox()->pack_start (*b);
7202 lock_dialog->get_vbox()->show_all ();
7203 lock_dialog->set_size_request (200, 200);
7207 /* The global menu bar continues to be accessible to applications
7208 with modal dialogs, which means that we need to desensitize
7209 all items in the menu bar. Since those items are really just
7210 proxies for actions, that means disabling all actions.
7212 ActionManager::disable_all_actions ();
7214 lock_dialog->present ();
7220 lock_dialog->hide ();
7223 ActionManager::pop_action_state ();
7226 if (ARDOUR_UI::config()->get_lock_gui_after_seconds()) {
7227 start_lock_event_timing ();
7232 Editor::bring_in_callback (Gtk::Label* label, uint32_t n, uint32_t total, string name)
7234 Gtkmm2ext::UI::instance()->call_slot (invalidator (*this), boost::bind (&Editor::update_bring_in_message, this, label, n, total, name));
7238 Editor::update_bring_in_message (Gtk::Label* label, uint32_t n, uint32_t total, string name)
7240 label->set_text (string_compose ("Copying %1, %2 of %3", name, n, total));
7241 Gtkmm2ext::UI::instance()->flush_pending ();
7245 Editor::bring_all_sources_into_session ()
7252 ArdourDialog w (_("Moving embedded files into session folder"));
7253 w.get_vbox()->pack_start (msg);
7256 /* flush all pending GUI events because we're about to start copying
7260 Gtkmm2ext::UI::instance()->flush_pending ();
7264 _session->bring_all_sources_into_session (boost::bind (&Editor::bring_in_callback, this, &msg, _1, _2, _3));