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 latest_regionviews.clear ();
224 vector<sigc::connection> region_added_connections;
226 for (list<RouteTimeAxisView*>::iterator i = used_trackviews.begin(); i != used_trackviews.end(); ++i) {
227 region_added_connections.push_back ((*i)->view()->RegionViewAdded.connect (sigc::mem_fun(*this, &Editor::collect_new_region_view)));
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) {
241 EditorThaw(); /* Emit Signal */
244 if (ARDOUR::Profile->get_mixbus()) {
245 //IFF we were working on selected regions, try to reinstate the other region selections that existed before the freeze/thaw.
246 _ignore_follow_edits = true; //a split will change the region selection in mysterious ways; its not practical or wanted to follow this edit
247 if( working_on_selection ) {
248 selection->add ( pre_selected_regions );
249 selection->add (latest_regionviews); //these are the new regions created after the split
251 _ignore_follow_edits = false;
253 _ignore_follow_edits = true;
254 if( working_on_selection ) {
255 selection->add (latest_regionviews); //these are the new regions created after the split
257 _ignore_follow_edits = false;
260 commit_reversible_command ();
263 /** Move one extreme of the current range selection. If more than one range is selected,
264 * the start of the earliest range or the end of the latest range is moved.
266 * @param move_end true to move the end of the current range selection, false to move
268 * @param next true to move the extreme to the next region boundary, false to move to
272 Editor::move_range_selection_start_or_end_to_region_boundary (bool move_end, bool next)
274 if (selection->time.start() == selection->time.end_frame()) {
278 framepos_t start = selection->time.start ();
279 framepos_t end = selection->time.end_frame ();
281 /* the position of the thing we may move */
282 framepos_t pos = move_end ? end : start;
283 int dir = next ? 1 : -1;
285 /* so we don't find the current region again */
286 if (dir > 0 || pos > 0) {
290 framepos_t const target = get_region_boundary (pos, dir, true, false);
305 begin_reversible_command (_("alter selection"));
306 selection->set_preserving_all_ranges (start, end);
307 commit_reversible_command ();
311 Editor::nudge_forward_release (GdkEventButton* ev)
313 if (ev->state & Keyboard::PrimaryModifier) {
314 nudge_forward (false, true);
316 nudge_forward (false, false);
322 Editor::nudge_backward_release (GdkEventButton* ev)
324 if (ev->state & Keyboard::PrimaryModifier) {
325 nudge_backward (false, true);
327 nudge_backward (false, false);
334 Editor::nudge_forward (bool next, bool force_playhead)
337 framepos_t next_distance;
343 RegionSelection rs = get_regions_from_selection_and_entered ();
345 if (!force_playhead && !rs.empty()) {
347 begin_reversible_command (_("nudge regions forward"));
349 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
350 boost::shared_ptr<Region> r ((*i)->region());
352 distance = get_nudge_distance (r->position(), next_distance);
355 distance = next_distance;
359 r->set_position (r->position() + distance);
360 _session->add_command (new StatefulDiffCommand (r));
363 commit_reversible_command ();
366 } else if (!force_playhead && !selection->markers.empty()) {
370 begin_reversible_command (_("nudge location forward"));
372 for (MarkerSelection::iterator i = selection->markers.begin(); i != selection->markers.end(); ++i) {
374 Location* loc = find_location_from_marker ((*i), is_start);
378 XMLNode& before (loc->get_state());
381 distance = get_nudge_distance (loc->start(), next_distance);
383 distance = next_distance;
385 if (max_framepos - distance > loc->start() + loc->length()) {
386 loc->set_start (loc->start() + distance);
388 loc->set_start (max_framepos - loc->length());
391 distance = get_nudge_distance (loc->end(), next_distance);
393 distance = next_distance;
395 if (max_framepos - distance > loc->end()) {
396 loc->set_end (loc->end() + distance);
398 loc->set_end (max_framepos);
401 XMLNode& after (loc->get_state());
402 _session->add_command (new MementoCommand<Location>(*loc, &before, &after));
406 commit_reversible_command ();
409 distance = get_nudge_distance (playhead_cursor->current_frame (), next_distance);
410 _session->request_locate (playhead_cursor->current_frame () + distance);
415 Editor::nudge_backward (bool next, bool force_playhead)
418 framepos_t next_distance;
424 RegionSelection rs = get_regions_from_selection_and_entered ();
426 if (!force_playhead && !rs.empty()) {
428 begin_reversible_command (_("nudge regions backward"));
430 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
431 boost::shared_ptr<Region> r ((*i)->region());
433 distance = get_nudge_distance (r->position(), next_distance);
436 distance = next_distance;
441 if (r->position() > distance) {
442 r->set_position (r->position() - distance);
446 _session->add_command (new StatefulDiffCommand (r));
449 commit_reversible_command ();
451 } else if (!force_playhead && !selection->markers.empty()) {
455 begin_reversible_command (_("nudge location forward"));
457 for (MarkerSelection::iterator i = selection->markers.begin(); i != selection->markers.end(); ++i) {
459 Location* loc = find_location_from_marker ((*i), is_start);
463 XMLNode& before (loc->get_state());
466 distance = get_nudge_distance (loc->start(), next_distance);
468 distance = next_distance;
470 if (distance < loc->start()) {
471 loc->set_start (loc->start() - distance);
476 distance = get_nudge_distance (loc->end(), next_distance);
479 distance = next_distance;
482 if (distance < loc->end() - loc->length()) {
483 loc->set_end (loc->end() - distance);
485 loc->set_end (loc->length());
489 XMLNode& after (loc->get_state());
490 _session->add_command (new MementoCommand<Location>(*loc, &before, &after));
494 commit_reversible_command ();
498 distance = get_nudge_distance (playhead_cursor->current_frame (), next_distance);
500 if (playhead_cursor->current_frame () > distance) {
501 _session->request_locate (playhead_cursor->current_frame () - distance);
503 _session->goto_start();
509 Editor::nudge_forward_capture_offset ()
511 RegionSelection rs = get_regions_from_selection_and_entered ();
513 if (!_session || rs.empty()) {
517 begin_reversible_command (_("nudge forward"));
519 framepos_t const distance = _session->worst_output_latency();
521 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
522 boost::shared_ptr<Region> r ((*i)->region());
525 r->set_position (r->position() + distance);
526 _session->add_command(new StatefulDiffCommand (r));
529 commit_reversible_command ();
533 Editor::nudge_backward_capture_offset ()
535 RegionSelection rs = get_regions_from_selection_and_entered ();
537 if (!_session || rs.empty()) {
541 begin_reversible_command (_("nudge backward"));
543 framepos_t const distance = _session->worst_output_latency();
545 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
546 boost::shared_ptr<Region> r ((*i)->region());
550 if (r->position() > distance) {
551 r->set_position (r->position() - distance);
555 _session->add_command(new StatefulDiffCommand (r));
558 commit_reversible_command ();
561 struct RegionSelectionPositionSorter {
562 bool operator() (RegionView* a, RegionView* b) {
563 return a->region()->position() < b->region()->position();
568 Editor::sequence_regions ()
571 framepos_t r_end_prev;
579 RegionSelection rs = get_regions_from_selection_and_entered ();
580 rs.sort(RegionSelectionPositionSorter());
584 begin_reversible_command (_("sequence regions"));
585 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
586 boost::shared_ptr<Region> r ((*i)->region());
594 if(r->position_locked())
601 r->set_position(r_end_prev);
604 _session->add_command (new StatefulDiffCommand (r));
606 r_end=r->position() + r->length();
610 commit_reversible_command ();
618 Editor::move_to_start ()
620 _session->goto_start ();
624 Editor::move_to_end ()
627 _session->request_locate (_session->current_end_frame());
631 Editor::build_region_boundary_cache ()
634 vector<RegionPoint> interesting_points;
635 boost::shared_ptr<Region> r;
636 TrackViewList tracks;
639 region_boundary_cache.clear ();
645 switch (_snap_type) {
646 case SnapToRegionStart:
647 interesting_points.push_back (Start);
649 case SnapToRegionEnd:
650 interesting_points.push_back (End);
652 case SnapToRegionSync:
653 interesting_points.push_back (SyncPoint);
655 case SnapToRegionBoundary:
656 interesting_points.push_back (Start);
657 interesting_points.push_back (End);
660 fatal << string_compose (_("build_region_boundary_cache called with snap_type = %1"), _snap_type) << endmsg;
661 abort(); /*NOTREACHED*/
665 TimeAxisView *ontrack = 0;
668 if (!selection->tracks.empty()) {
669 tlist = selection->tracks.filter_to_unique_playlists ();
671 tlist = track_views.filter_to_unique_playlists ();
674 while (pos < _session->current_end_frame() && !at_end) {
677 framepos_t lpos = max_framepos;
679 for (vector<RegionPoint>::iterator p = interesting_points.begin(); p != interesting_points.end(); ++p) {
681 if ((r = find_next_region (pos, *p, 1, tlist, &ontrack)) == 0) {
682 if (*p == interesting_points.back()) {
685 /* move to next point type */
691 rpos = r->first_frame();
695 rpos = r->last_frame();
699 rpos = r->sync_position ();
707 RouteTimeAxisView *rtav;
709 if (ontrack != 0 && (rtav = dynamic_cast<RouteTimeAxisView*>(ontrack)) != 0 ) {
710 if (rtav->track() != 0) {
711 speed = rtav->track()->speed();
715 rpos = track_frame_to_session_frame (rpos, speed);
721 /* prevent duplicates, but we don't use set<> because we want to be able
725 vector<framepos_t>::iterator ri;
727 for (ri = region_boundary_cache.begin(); ri != region_boundary_cache.end(); ++ri) {
733 if (ri == region_boundary_cache.end()) {
734 region_boundary_cache.push_back (rpos);
741 /* finally sort to be sure that the order is correct */
743 sort (region_boundary_cache.begin(), region_boundary_cache.end());
746 boost::shared_ptr<Region>
747 Editor::find_next_region (framepos_t frame, RegionPoint point, int32_t dir, TrackViewList& tracks, TimeAxisView **ontrack)
749 TrackViewList::iterator i;
750 framepos_t closest = max_framepos;
751 boost::shared_ptr<Region> ret;
755 framepos_t track_frame;
756 RouteTimeAxisView *rtav;
758 for (i = tracks.begin(); i != tracks.end(); ++i) {
761 boost::shared_ptr<Region> r;
764 if ( (rtav = dynamic_cast<RouteTimeAxisView*>(*i)) != 0 ) {
765 if (rtav->track()!=0)
766 track_speed = rtav->track()->speed();
769 track_frame = session_frame_to_track_frame(frame, track_speed);
771 if ((r = (*i)->find_next_region (track_frame, point, dir)) == 0) {
777 rpos = r->first_frame ();
781 rpos = r->last_frame ();
785 rpos = r->sync_position ();
789 // rpos is a "track frame", converting it to "_session frame"
790 rpos = track_frame_to_session_frame(rpos, track_speed);
793 distance = rpos - frame;
795 distance = frame - rpos;
798 if (distance < closest) {
810 Editor::find_next_region_boundary (framepos_t pos, int32_t dir, const TrackViewList& tracks)
812 framecnt_t distance = max_framepos;
813 framepos_t current_nearest = -1;
815 for (TrackViewList::const_iterator i = tracks.begin(); i != tracks.end(); ++i) {
816 framepos_t contender;
819 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*i);
825 if ((contender = rtv->find_next_region_boundary (pos, dir)) < 0) {
829 d = ::llabs (pos - contender);
832 current_nearest = contender;
837 return current_nearest;
841 Editor::get_region_boundary (framepos_t pos, int32_t dir, bool with_selection, bool only_onscreen)
846 if (with_selection && Config->get_region_boundaries_from_selected_tracks()) {
848 if (!selection->tracks.empty()) {
850 target = find_next_region_boundary (pos, dir, selection->tracks);
854 if (only_onscreen || Config->get_region_boundaries_from_onscreen_tracks()) {
855 get_onscreen_tracks (tvl);
856 target = find_next_region_boundary (pos, dir, tvl);
858 target = find_next_region_boundary (pos, dir, track_views);
864 if (only_onscreen || Config->get_region_boundaries_from_onscreen_tracks()) {
865 get_onscreen_tracks (tvl);
866 target = find_next_region_boundary (pos, dir, tvl);
868 target = find_next_region_boundary (pos, dir, track_views);
876 Editor::cursor_to_region_boundary (bool with_selection, int32_t dir)
878 framepos_t pos = playhead_cursor->current_frame ();
885 // so we don't find the current region again..
886 if (dir > 0 || pos > 0) {
890 if ((target = get_region_boundary (pos, dir, with_selection, false)) < 0) {
894 _session->request_locate (target);
898 Editor::cursor_to_next_region_boundary (bool with_selection)
900 cursor_to_region_boundary (with_selection, 1);
904 Editor::cursor_to_previous_region_boundary (bool with_selection)
906 cursor_to_region_boundary (with_selection, -1);
910 Editor::cursor_to_region_point (EditorCursor* cursor, RegionPoint point, int32_t dir)
912 boost::shared_ptr<Region> r;
913 framepos_t pos = cursor->current_frame ();
919 TimeAxisView *ontrack = 0;
921 // so we don't find the current region again..
925 if (!selection->tracks.empty()) {
927 r = find_next_region (pos, point, dir, selection->tracks, &ontrack);
929 } else if (clicked_axisview) {
932 t.push_back (clicked_axisview);
934 r = find_next_region (pos, point, dir, t, &ontrack);
938 r = find_next_region (pos, point, dir, track_views, &ontrack);
947 pos = r->first_frame ();
951 pos = r->last_frame ();
955 pos = r->sync_position ();
960 RouteTimeAxisView *rtav;
962 if ( ontrack != 0 && (rtav = dynamic_cast<RouteTimeAxisView*>(ontrack)) != 0 ) {
963 if (rtav->track() != 0) {
964 speed = rtav->track()->speed();
968 pos = track_frame_to_session_frame(pos, speed);
970 if (cursor == playhead_cursor) {
971 _session->request_locate (pos);
973 cursor->set_position (pos);
978 Editor::cursor_to_next_region_point (EditorCursor* cursor, RegionPoint point)
980 cursor_to_region_point (cursor, point, 1);
984 Editor::cursor_to_previous_region_point (EditorCursor* cursor, RegionPoint point)
986 cursor_to_region_point (cursor, point, -1);
990 Editor::cursor_to_selection_start (EditorCursor *cursor)
994 switch (mouse_mode) {
996 if (!selection->regions.empty()) {
997 pos = selection->regions.start();
1002 if (!selection->time.empty()) {
1003 pos = selection->time.start ();
1011 if (cursor == playhead_cursor) {
1012 _session->request_locate (pos);
1014 cursor->set_position (pos);
1019 Editor::cursor_to_selection_end (EditorCursor *cursor)
1023 switch (mouse_mode) {
1025 if (!selection->regions.empty()) {
1026 pos = selection->regions.end_frame();
1031 if (!selection->time.empty()) {
1032 pos = selection->time.end_frame ();
1040 if (cursor == playhead_cursor) {
1041 _session->request_locate (pos);
1043 cursor->set_position (pos);
1048 Editor::selected_marker_to_region_boundary (bool with_selection, int32_t dir)
1058 if (selection->markers.empty()) {
1062 if (!mouse_frame (mouse, ignored)) {
1066 add_location_mark (mouse);
1069 if ((loc = find_location_from_marker (selection->markers.front(), ignored)) == 0) {
1073 framepos_t pos = loc->start();
1075 // so we don't find the current region again..
1076 if (dir > 0 || pos > 0) {
1080 if ((target = get_region_boundary (pos, dir, with_selection, false)) < 0) {
1084 loc->move_to (target);
1088 Editor::selected_marker_to_next_region_boundary (bool with_selection)
1090 selected_marker_to_region_boundary (with_selection, 1);
1094 Editor::selected_marker_to_previous_region_boundary (bool with_selection)
1096 selected_marker_to_region_boundary (with_selection, -1);
1100 Editor::selected_marker_to_region_point (RegionPoint point, int32_t dir)
1102 boost::shared_ptr<Region> r;
1107 if (!_session || selection->markers.empty()) {
1111 if ((loc = find_location_from_marker (selection->markers.front(), ignored)) == 0) {
1115 TimeAxisView *ontrack = 0;
1119 // so we don't find the current region again..
1123 if (!selection->tracks.empty()) {
1125 r = find_next_region (pos, point, dir, selection->tracks, &ontrack);
1129 r = find_next_region (pos, point, dir, track_views, &ontrack);
1138 pos = r->first_frame ();
1142 pos = r->last_frame ();
1146 pos = r->adjust_to_sync (r->first_frame());
1151 RouteTimeAxisView *rtav;
1153 if (ontrack != 0 && (rtav = dynamic_cast<RouteTimeAxisView*>(ontrack)) != 0) {
1154 if (rtav->track() != 0) {
1155 speed = rtav->track()->speed();
1159 pos = track_frame_to_session_frame(pos, speed);
1165 Editor::selected_marker_to_next_region_point (RegionPoint point)
1167 selected_marker_to_region_point (point, 1);
1171 Editor::selected_marker_to_previous_region_point (RegionPoint point)
1173 selected_marker_to_region_point (point, -1);
1177 Editor::selected_marker_to_selection_start ()
1183 if (!_session || selection->markers.empty()) {
1187 if ((loc = find_location_from_marker (selection->markers.front(), ignored)) == 0) {
1191 switch (mouse_mode) {
1193 if (!selection->regions.empty()) {
1194 pos = selection->regions.start();
1199 if (!selection->time.empty()) {
1200 pos = selection->time.start ();
1212 Editor::selected_marker_to_selection_end ()
1218 if (!_session || selection->markers.empty()) {
1222 if ((loc = find_location_from_marker (selection->markers.front(), ignored)) == 0) {
1226 switch (mouse_mode) {
1228 if (!selection->regions.empty()) {
1229 pos = selection->regions.end_frame();
1234 if (!selection->time.empty()) {
1235 pos = selection->time.end_frame ();
1247 Editor::scroll_playhead (bool forward)
1249 framepos_t pos = playhead_cursor->current_frame ();
1250 framecnt_t delta = (framecnt_t) floor (current_page_samples() / 0.8);
1253 if (pos == max_framepos) {
1257 if (pos < max_framepos - delta) {
1276 _session->request_locate (pos);
1280 Editor::cursor_align (bool playhead_to_edit)
1286 if (playhead_to_edit) {
1288 if (selection->markers.empty()) {
1292 _session->request_locate (selection->markers.front()->position(), _session->transport_rolling());
1295 /* move selected markers to playhead */
1297 for (MarkerSelection::iterator i = selection->markers.begin(); i != selection->markers.end(); ++i) {
1300 Location* loc = find_location_from_marker (*i, ignored);
1302 if (loc->is_mark()) {
1303 loc->set_start (playhead_cursor->current_frame ());
1305 loc->set (playhead_cursor->current_frame (),
1306 playhead_cursor->current_frame () + loc->length());
1313 Editor::scroll_backward (float pages)
1315 framepos_t const one_page = (framepos_t) rint (_visible_canvas_width * samples_per_pixel);
1316 framepos_t const cnt = (framepos_t) floor (pages * one_page);
1319 if (leftmost_frame < cnt) {
1322 frame = leftmost_frame - cnt;
1325 reset_x_origin (frame);
1329 Editor::scroll_forward (float pages)
1331 framepos_t const one_page = (framepos_t) rint (_visible_canvas_width * samples_per_pixel);
1332 framepos_t const cnt = (framepos_t) floor (pages * one_page);
1335 if (max_framepos - cnt < leftmost_frame) {
1336 frame = max_framepos - cnt;
1338 frame = leftmost_frame + cnt;
1341 reset_x_origin (frame);
1345 Editor::scroll_tracks_down ()
1347 double vert_value = vertical_adjustment.get_value() + vertical_adjustment.get_page_size();
1348 if (vert_value > vertical_adjustment.get_upper() - _visible_canvas_height) {
1349 vert_value = vertical_adjustment.get_upper() - _visible_canvas_height;
1352 vertical_adjustment.set_value (vert_value);
1356 Editor::scroll_tracks_up ()
1358 vertical_adjustment.set_value (vertical_adjustment.get_value() - vertical_adjustment.get_page_size());
1362 Editor::scroll_tracks_down_line ()
1364 double vert_value = vertical_adjustment.get_value() + 60;
1366 if (vert_value > vertical_adjustment.get_upper() - _visible_canvas_height) {
1367 vert_value = vertical_adjustment.get_upper() - _visible_canvas_height;
1370 vertical_adjustment.set_value (vert_value);
1374 Editor::scroll_tracks_up_line ()
1376 reset_y_origin (vertical_adjustment.get_value() - 60);
1380 Editor::scroll_down_one_track ()
1382 TrackViewList::reverse_iterator next = track_views.rend();
1383 std::pair<TimeAxisView*,double> res;
1384 const double top_of_trackviews = vertical_adjustment.get_value();
1386 for (TrackViewList::reverse_iterator t = track_views.rbegin(); t != track_views.rend(); ++t) {
1387 if ((*t)->hidden()) {
1392 /* If this is the upper-most visible trackview, we want to display
1393 the one above it (next)
1396 res = (*t)->covers_y_position (top_of_trackviews);
1404 /* move to the track below the first one that covers the */
1406 if (next != track_views.rend()) {
1407 ensure_time_axis_view_is_visible (**next, true);
1415 Editor::scroll_up_one_track ()
1417 TrackViewList::iterator prev = track_views.end();
1418 std::pair<TimeAxisView*,double> res;
1419 double top_of_trackviews = vertical_adjustment.get_value ();
1421 for (TrackViewList::iterator t = track_views.begin(); t != track_views.end(); ++t) {
1423 if ((*t)->hidden()) {
1427 /* find the trackview at the top of the trackview group */
1428 res = (*t)->covers_y_position (top_of_trackviews);
1437 if (prev != track_views.end()) {
1438 ensure_time_axis_view_is_visible (**prev, true);
1448 Editor::tav_zoom_step (bool coarser)
1450 DisplaySuspender ds;
1454 if (selection->tracks.empty()) {
1457 ts = &selection->tracks;
1460 for (TrackViewList::iterator i = ts->begin(); i != ts->end(); ++i) {
1461 TimeAxisView *tv = (static_cast<TimeAxisView*>(*i));
1462 tv->step_height (coarser);
1467 Editor::tav_zoom_smooth (bool coarser, bool force_all)
1469 DisplaySuspender ds;
1473 if (selection->tracks.empty() || force_all) {
1476 ts = &selection->tracks;
1479 for (TrackViewList::iterator i = ts->begin(); i != ts->end(); ++i) {
1480 TimeAxisView *tv = (static_cast<TimeAxisView*>(*i));
1481 uint32_t h = tv->current_height ();
1486 if (h >= TimeAxisView::preset_height (HeightSmall)) {
1491 tv->set_height (h + 5);
1498 Editor::temporal_zoom_step (bool coarser)
1500 ENSURE_GUI_THREAD (*this, &Editor::temporal_zoom_step, coarser)
1502 framecnt_t nspp = samples_per_pixel;
1510 temporal_zoom (nspp);
1514 Editor::temporal_zoom (framecnt_t fpp)
1520 framepos_t current_page = current_page_samples();
1521 framepos_t current_leftmost = leftmost_frame;
1522 framepos_t current_rightmost;
1523 framepos_t current_center;
1524 framepos_t new_page_size;
1525 framepos_t half_page_size;
1526 framepos_t leftmost_after_zoom = 0;
1528 bool in_track_canvas;
1532 if (fpp == samples_per_pixel) {
1536 // Imposing an arbitrary limit to zoom out as too much zoom out produces
1537 // segfaults for lack of memory. If somebody decides this is not high enough I
1538 // believe it can be raisen to higher values but some limit must be in place.
1540 // This constant represents 1 day @ 48kHz on a 1600 pixel wide display
1541 // all of which is used for the editor track displays. The whole day
1542 // would be 4147200000 samples, so 2592000 samples per pixel.
1544 nfpp = min (fpp, (framecnt_t) 2592000);
1545 nfpp = max ((framecnt_t) 1, nfpp);
1547 new_page_size = (framepos_t) floor (_visible_canvas_width * nfpp);
1548 half_page_size = new_page_size / 2;
1550 switch (zoom_focus) {
1552 leftmost_after_zoom = current_leftmost;
1555 case ZoomFocusRight:
1556 current_rightmost = leftmost_frame + current_page;
1557 if (current_rightmost < new_page_size) {
1558 leftmost_after_zoom = 0;
1560 leftmost_after_zoom = current_rightmost - new_page_size;
1564 case ZoomFocusCenter:
1565 current_center = current_leftmost + (current_page/2);
1566 if (current_center < half_page_size) {
1567 leftmost_after_zoom = 0;
1569 leftmost_after_zoom = current_center - half_page_size;
1573 case ZoomFocusPlayhead:
1574 /* centre playhead */
1575 l = playhead_cursor->current_frame () - (new_page_size * 0.5);
1578 leftmost_after_zoom = 0;
1579 } else if (l > max_framepos) {
1580 leftmost_after_zoom = max_framepos - new_page_size;
1582 leftmost_after_zoom = (framepos_t) l;
1586 case ZoomFocusMouse:
1587 /* try to keep the mouse over the same point in the display */
1589 if (!mouse_frame (where, in_track_canvas)) {
1590 /* use playhead instead */
1591 where = playhead_cursor->current_frame ();
1593 if (where < half_page_size) {
1594 leftmost_after_zoom = 0;
1596 leftmost_after_zoom = where - half_page_size;
1601 l = - ((new_page_size * ((where - current_leftmost)/(double)current_page)) - where);
1604 leftmost_after_zoom = 0;
1605 } else if (l > max_framepos) {
1606 leftmost_after_zoom = max_framepos - new_page_size;
1608 leftmost_after_zoom = (framepos_t) l;
1615 /* try to keep the edit point in the same place */
1616 where = get_preferred_edit_position ();
1620 double l = - ((new_page_size * ((where - current_leftmost)/(double)current_page)) - where);
1623 leftmost_after_zoom = 0;
1624 } else if (l > max_framepos) {
1625 leftmost_after_zoom = max_framepos - new_page_size;
1627 leftmost_after_zoom = (framepos_t) l;
1631 /* edit point not defined */
1638 // leftmost_after_zoom = min (leftmost_after_zoom, _session->current_end_frame());
1640 reposition_and_zoom (leftmost_after_zoom, nfpp);
1644 Editor::calc_extra_zoom_edges(framepos_t &start, framepos_t &end)
1646 /* this func helps make sure we leave a little space
1647 at each end of the editor so that the zoom doesn't fit the region
1648 precisely to the screen.
1651 GdkScreen* screen = gdk_screen_get_default ();
1652 const gint pixwidth = gdk_screen_get_width (screen);
1653 const gint mmwidth = gdk_screen_get_width_mm (screen);
1654 const double pix_per_mm = (double) pixwidth/ (double) mmwidth;
1655 const double one_centimeter_in_pixels = pix_per_mm * 10.0;
1657 const framepos_t range = end - start;
1658 const framecnt_t new_fpp = (framecnt_t) ceil ((double) range / (double) _visible_canvas_width);
1659 const framepos_t extra_samples = (framepos_t) floor (one_centimeter_in_pixels * new_fpp);
1661 if (start > extra_samples) {
1662 start -= extra_samples;
1667 if (max_framepos - extra_samples > end) {
1668 end += extra_samples;
1675 Editor::temporal_zoom_region (bool both_axes)
1677 framepos_t start = max_framepos;
1679 set<TimeAxisView*> tracks;
1681 RegionSelection rs = get_regions_from_selection_and_entered ();
1687 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
1689 if ((*i)->region()->position() < start) {
1690 start = (*i)->region()->position();
1693 if ((*i)->region()->last_frame() + 1 > end) {
1694 end = (*i)->region()->last_frame() + 1;
1697 tracks.insert (&((*i)->get_time_axis_view()));
1700 if ((start == 0 && end == 0) || end < start) {
1704 calc_extra_zoom_edges (start, end);
1706 /* if we're zooming on both axes we need to save track heights etc.
1709 undo_visual_stack.push_back (current_visual_state (both_axes));
1711 PBD::Unwinder<bool> nsv (no_save_visual, true);
1713 temporal_zoom_by_frame (start, end);
1716 uint32_t per_track_height = (uint32_t) floor ((_visible_canvas_height - 10.0) / tracks.size());
1718 /* set visible track heights appropriately */
1720 for (set<TimeAxisView*>::iterator t = tracks.begin(); t != tracks.end(); ++t) {
1721 (*t)->set_height (per_track_height);
1724 /* hide irrelevant tracks */
1726 DisplaySuspender ds;
1728 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1729 if (find (tracks.begin(), tracks.end(), (*i)) == tracks.end()) {
1730 hide_track_in_display (*i);
1734 vertical_adjustment.set_value (0.0);
1737 redo_visual_stack.push_back (current_visual_state (both_axes));
1741 Editor::zoom_to_region (bool both_axes)
1743 temporal_zoom_region (both_axes);
1747 Editor::temporal_zoom_selection (bool both_axes)
1749 if (!selection) return;
1751 //if a range is selected, zoom to that
1752 if (!selection->time.empty()) {
1754 framepos_t start = selection->time.start();
1755 framepos_t end = selection->time.end_frame();
1757 calc_extra_zoom_edges(start, end);
1759 temporal_zoom_by_frame (start, end);
1762 fit_selected_tracks();
1765 temporal_zoom_region (both_axes);
1772 Editor::temporal_zoom_session ()
1774 ENSURE_GUI_THREAD (*this, &Editor::temporal_zoom_session)
1777 framecnt_t start = _session->current_start_frame();
1778 framecnt_t end = _session->current_end_frame();
1780 if (_session->actively_recording () ) {
1781 framepos_t cur = playhead_cursor->current_frame ();
1783 /* recording beyond the end marker; zoom out
1784 * by 5 seconds more so that if 'follow
1785 * playhead' is active we don't immediately
1788 end = cur + _session->frame_rate() * 5;
1792 if ((start == 0 && end == 0) || end < start) {
1796 calc_extra_zoom_edges(start, end);
1798 temporal_zoom_by_frame (start, end);
1803 Editor::temporal_zoom_by_frame (framepos_t start, framepos_t end)
1805 if (!_session) return;
1807 if ((start == 0 && end == 0) || end < start) {
1811 framepos_t range = end - start;
1813 const framecnt_t new_fpp = (framecnt_t) ceil ((double) range / (double) _visible_canvas_width);
1815 framepos_t new_page = range;
1816 framepos_t middle = (framepos_t) floor ((double) start + ((double) range / 2.0f));
1817 framepos_t new_leftmost = (framepos_t) floor ((double) middle - ((double) new_page / 2.0f));
1819 if (new_leftmost > middle) {
1823 if (new_leftmost < 0) {
1827 reposition_and_zoom (new_leftmost, new_fpp);
1831 Editor::temporal_zoom_to_frame (bool coarser, framepos_t frame)
1837 framecnt_t range_before = frame - leftmost_frame;
1841 if (samples_per_pixel <= 1) {
1844 new_spp = samples_per_pixel + (samples_per_pixel/2);
1846 range_before += range_before/2;
1848 if (samples_per_pixel >= 1) {
1849 new_spp = samples_per_pixel - (samples_per_pixel/2);
1851 /* could bail out here since we cannot zoom any finer,
1852 but leave that to the equality test below
1854 new_spp = samples_per_pixel;
1857 range_before -= range_before/2;
1860 if (new_spp == samples_per_pixel) {
1864 /* zoom focus is automatically taken as @param frame when this
1868 framepos_t new_leftmost = frame - (framepos_t)range_before;
1870 if (new_leftmost > frame) {
1874 if (new_leftmost < 0) {
1878 reposition_and_zoom (new_leftmost, new_spp);
1883 Editor::choose_new_marker_name(string &name) {
1885 if (!Config->get_name_new_markers()) {
1886 /* don't prompt user for a new name */
1890 ArdourPrompter dialog (true);
1892 dialog.set_prompt (_("New Name:"));
1894 dialog.set_title (_("New Location Marker"));
1896 dialog.set_name ("MarkNameWindow");
1897 dialog.set_size_request (250, -1);
1898 dialog.set_position (Gtk::WIN_POS_MOUSE);
1900 dialog.add_button (Stock::OK, RESPONSE_ACCEPT);
1901 dialog.set_initial_text (name);
1905 switch (dialog.run ()) {
1906 case RESPONSE_ACCEPT:
1912 dialog.get_result(name);
1919 Editor::add_location_from_selection ()
1923 if (selection->time.empty()) {
1927 if (_session == 0 || clicked_axisview == 0) {
1931 framepos_t start = selection->time[clicked_selection].start;
1932 framepos_t end = selection->time[clicked_selection].end;
1934 _session->locations()->next_available_name(rangename,"selection");
1935 Location *location = new Location (*_session, start, end, rangename, Location::IsRangeMarker);
1937 begin_reversible_command (_("add marker"));
1939 XMLNode &before = _session->locations()->get_state();
1940 _session->locations()->add (location, true);
1941 XMLNode &after = _session->locations()->get_state();
1942 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
1944 commit_reversible_command ();
1948 Editor::add_location_mark (framepos_t where)
1952 select_new_marker = true;
1954 _session->locations()->next_available_name(markername,"mark");
1955 if (!choose_new_marker_name(markername)) {
1958 Location *location = new Location (*_session, where, where, markername, Location::IsMark);
1959 begin_reversible_command (_("add marker"));
1961 XMLNode &before = _session->locations()->get_state();
1962 _session->locations()->add (location, true);
1963 XMLNode &after = _session->locations()->get_state();
1964 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
1966 commit_reversible_command ();
1970 Editor::add_location_from_playhead_cursor ()
1972 add_location_mark (_session->audible_frame());
1976 Editor::remove_location_at_playhead_cursor ()
1981 begin_reversible_command (_("remove marker"));
1983 XMLNode &before = _session->locations()->get_state();
1984 bool removed = false;
1986 //find location(s) at this time
1987 Locations::LocationList locs;
1988 _session->locations()->find_all_between (_session->audible_frame(), _session->audible_frame()+1, locs, Location::Flags(0));
1989 for (Locations::LocationList::iterator i = locs.begin(); i != locs.end(); ++i) {
1990 if ((*i)->is_mark()) {
1991 _session->locations()->remove (*i);
1998 XMLNode &after = _session->locations()->get_state();
1999 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2001 commit_reversible_command ();
2006 /** Add a range marker around each selected region */
2008 Editor::add_locations_from_region ()
2010 RegionSelection rs = get_regions_from_selection_and_entered ();
2016 begin_reversible_command (selection->regions.size () > 1 ? _("add markers") : _("add marker"));
2018 XMLNode &before = _session->locations()->get_state();
2020 for (RegionSelection::iterator i = rs.begin (); i != rs.end (); ++i) {
2022 boost::shared_ptr<Region> region = (*i)->region ();
2024 Location *location = new Location (*_session, region->position(), region->last_frame(), region->name(), Location::IsRangeMarker);
2026 _session->locations()->add (location, true);
2029 XMLNode &after = _session->locations()->get_state();
2030 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2032 commit_reversible_command ();
2035 /** Add a single range marker around all selected regions */
2037 Editor::add_location_from_region ()
2039 RegionSelection rs = get_regions_from_selection_and_entered ();
2045 begin_reversible_command (_("add marker"));
2047 XMLNode &before = _session->locations()->get_state();
2051 if (rs.size() > 1) {
2052 _session->locations()->next_available_name(markername, "regions");
2054 RegionView* rv = *(rs.begin());
2055 boost::shared_ptr<Region> region = rv->region();
2056 markername = region->name();
2059 if (!choose_new_marker_name(markername)) {
2063 // single range spanning all selected
2064 Location *location = new Location (*_session, selection->regions.start(), selection->regions.end_frame(), markername, Location::IsRangeMarker);
2065 _session->locations()->add (location, true);
2067 XMLNode &after = _session->locations()->get_state();
2068 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2070 commit_reversible_command ();
2076 Editor::jump_forward_to_mark ()
2082 framepos_t pos = _session->locations()->first_mark_after (playhead_cursor->current_frame());
2088 _session->request_locate (pos, _session->transport_rolling());
2092 Editor::jump_backward_to_mark ()
2098 framepos_t pos = _session->locations()->first_mark_before (playhead_cursor->current_frame());
2104 _session->request_locate (pos, _session->transport_rolling());
2110 framepos_t const pos = _session->audible_frame ();
2113 _session->locations()->next_available_name (markername, "mark");
2115 if (!choose_new_marker_name (markername)) {
2119 _session->locations()->add (new Location (*_session, pos, 0, markername, Location::IsMark), true);
2123 Editor::clear_markers ()
2126 begin_reversible_command (_("clear markers"));
2128 XMLNode &before = _session->locations()->get_state();
2129 _session->locations()->clear_markers ();
2130 XMLNode &after = _session->locations()->get_state();
2131 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2133 commit_reversible_command ();
2138 Editor::clear_ranges ()
2141 begin_reversible_command (_("clear ranges"));
2143 XMLNode &before = _session->locations()->get_state();
2145 _session->locations()->clear_ranges ();
2147 XMLNode &after = _session->locations()->get_state();
2148 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2150 commit_reversible_command ();
2155 Editor::clear_locations ()
2157 begin_reversible_command (_("clear locations"));
2159 XMLNode &before = _session->locations()->get_state();
2160 _session->locations()->clear ();
2161 XMLNode &after = _session->locations()->get_state();
2162 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2164 commit_reversible_command ();
2168 Editor::unhide_markers ()
2170 for (LocationMarkerMap::iterator i = location_markers.begin(); i != location_markers.end(); ++i) {
2171 Location *l = (*i).first;
2172 if (l->is_hidden() && l->is_mark()) {
2173 l->set_hidden(false, this);
2179 Editor::unhide_ranges ()
2181 for (LocationMarkerMap::iterator i = location_markers.begin(); i != location_markers.end(); ++i) {
2182 Location *l = (*i).first;
2183 if (l->is_hidden() && l->is_range_marker()) {
2184 l->set_hidden(false, this);
2189 /* INSERT/REPLACE */
2192 Editor::insert_region_list_selection (float times)
2194 RouteTimeAxisView *tv = 0;
2195 boost::shared_ptr<Playlist> playlist;
2197 if (clicked_routeview != 0) {
2198 tv = clicked_routeview;
2199 } else if (!selection->tracks.empty()) {
2200 if ((tv = dynamic_cast<RouteTimeAxisView*>(selection->tracks.front())) == 0) {
2203 } else if (entered_track != 0) {
2204 if ((tv = dynamic_cast<RouteTimeAxisView*>(entered_track)) == 0) {
2211 if ((playlist = tv->playlist()) == 0) {
2215 boost::shared_ptr<Region> region = _regions->get_single_selection ();
2220 begin_reversible_command (_("insert region"));
2221 playlist->clear_changes ();
2222 playlist->add_region ((RegionFactory::create (region, true)), get_preferred_edit_position(), times);
2223 if (Config->get_edit_mode() == Ripple)
2224 playlist->ripple (get_preferred_edit_position(), region->length() * times, boost::shared_ptr<Region>());
2226 _session->add_command(new StatefulDiffCommand (playlist));
2227 commit_reversible_command ();
2230 /* BUILT-IN EFFECTS */
2233 Editor::reverse_selection ()
2238 /* GAIN ENVELOPE EDITING */
2241 Editor::edit_envelope ()
2248 Editor::transition_to_rolling (bool fwd)
2254 if (_session->config.get_external_sync()) {
2255 switch (Config->get_sync_source()) {
2259 /* transport controlled by the master */
2264 if (_session->is_auditioning()) {
2265 _session->cancel_audition ();
2269 _session->request_transport_speed (fwd ? 1.0f : -1.0f);
2273 Editor::play_from_start ()
2275 _session->request_locate (_session->current_start_frame(), true);
2279 Editor::play_from_edit_point ()
2281 _session->request_locate (get_preferred_edit_position(), true);
2285 Editor::play_from_edit_point_and_return ()
2287 framepos_t start_frame;
2288 framepos_t return_frame;
2290 start_frame = get_preferred_edit_position (true);
2292 if (_session->transport_rolling()) {
2293 _session->request_locate (start_frame, false);
2297 /* don't reset the return frame if its already set */
2299 if ((return_frame = _session->requested_return_frame()) < 0) {
2300 return_frame = _session->audible_frame();
2303 if (start_frame >= 0) {
2304 _session->request_roll_at_and_return (start_frame, return_frame);
2309 Editor::play_selection ()
2311 if (selection->time.empty()) {
2315 _session->request_play_range (&selection->time, true);
2319 Editor::get_preroll ()
2321 return 1.0 /*Config->get_edit_preroll_seconds()*/ * _session->frame_rate();
2326 Editor::maybe_locate_with_edit_preroll ( framepos_t location )
2328 if ( _session->transport_rolling() || !Config->get_follow_edits() || _ignore_follow_edits )
2331 location -= get_preroll();
2333 //don't try to locate before the beginning of time
2337 //if follow_playhead is on, keep the playhead on the screen
2338 if ( _follow_playhead )
2339 if ( location < leftmost_frame )
2340 location = leftmost_frame;
2342 _session->request_locate( location );
2346 Editor::play_with_preroll ()
2348 if (selection->time.empty()) {
2351 framepos_t preroll = get_preroll();
2353 framepos_t start = 0;
2354 if (selection->time[clicked_selection].start > preroll)
2355 start = selection->time[clicked_selection].start - preroll;
2357 framepos_t end = selection->time[clicked_selection].end + preroll;
2359 AudioRange ar (start, end, 0);
2360 list<AudioRange> lar;
2363 _session->request_play_range (&lar, true);
2368 Editor::play_location (Location& location)
2370 if (location.start() <= location.end()) {
2374 _session->request_bounded_roll (location.start(), location.end());
2378 Editor::loop_location (Location& location)
2380 if (location.start() <= location.end()) {
2386 if ((tll = transport_loop_location()) != 0) {
2387 tll->set (location.start(), location.end());
2389 // enable looping, reposition and start rolling
2390 _session->request_locate (tll->start(), true);
2391 _session->request_play_loop (true);
2396 Editor::do_layer_operation (LayerOperation op)
2398 if (selection->regions.empty ()) {
2402 bool const multiple = selection->regions.size() > 1;
2406 begin_reversible_command (_("raise regions"));
2408 begin_reversible_command (_("raise region"));
2414 begin_reversible_command (_("raise regions to top"));
2416 begin_reversible_command (_("raise region to top"));
2422 begin_reversible_command (_("lower regions"));
2424 begin_reversible_command (_("lower region"));
2430 begin_reversible_command (_("lower regions to bottom"));
2432 begin_reversible_command (_("lower region"));
2437 set<boost::shared_ptr<Playlist> > playlists = selection->regions.playlists ();
2438 for (set<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
2439 (*i)->clear_owned_changes ();
2442 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
2443 boost::shared_ptr<Region> r = (*i)->region ();
2455 r->lower_to_bottom ();
2459 for (set<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
2460 vector<Command*> cmds;
2462 _session->add_commands (cmds);
2465 commit_reversible_command ();
2469 Editor::raise_region ()
2471 do_layer_operation (Raise);
2475 Editor::raise_region_to_top ()
2477 do_layer_operation (RaiseToTop);
2481 Editor::lower_region ()
2483 do_layer_operation (Lower);
2487 Editor::lower_region_to_bottom ()
2489 do_layer_operation (LowerToBottom);
2492 /** Show the region editor for the selected regions */
2494 Editor::show_region_properties ()
2496 selection->foreach_regionview (&RegionView::show_region_editor);
2499 /** Show the midi list editor for the selected MIDI regions */
2501 Editor::show_midi_list_editor ()
2503 selection->foreach_midi_regionview (&MidiRegionView::show_list_editor);
2507 Editor::rename_region ()
2509 RegionSelection rs = get_regions_from_selection_and_entered ();
2515 ArdourDialog d (*this, _("Rename Region"), true, false);
2517 Label label (_("New name:"));
2520 hbox.set_spacing (6);
2521 hbox.pack_start (label, false, false);
2522 hbox.pack_start (entry, true, true);
2524 d.get_vbox()->set_border_width (12);
2525 d.get_vbox()->pack_start (hbox, false, false);
2527 d.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
2528 d.add_button(Gtk::Stock::OK, Gtk::RESPONSE_OK);
2530 d.set_size_request (300, -1);
2532 entry.set_text (rs.front()->region()->name());
2533 entry.select_region (0, -1);
2535 entry.signal_activate().connect (sigc::bind (sigc::mem_fun (d, &Dialog::response), RESPONSE_OK));
2541 int const ret = d.run();
2545 if (ret != RESPONSE_OK) {
2549 std::string str = entry.get_text();
2550 strip_whitespace_edges (str);
2552 rs.front()->region()->set_name (str);
2553 _regions->redisplay ();
2558 Editor::audition_playlist_region_via_route (boost::shared_ptr<Region> region, Route& route)
2560 if (_session->is_auditioning()) {
2561 _session->cancel_audition ();
2564 // note: some potential for creativity here, because region doesn't
2565 // have to belong to the playlist that Route is handling
2567 // bool was_soloed = route.soloed();
2569 route.set_solo (true, this);
2571 _session->request_bounded_roll (region->position(), region->position() + region->length());
2573 /* XXX how to unset the solo state ? */
2576 /** Start an audition of the first selected region */
2578 Editor::play_edit_range ()
2580 framepos_t start, end;
2582 if (get_edit_op_range (start, end)) {
2583 _session->request_bounded_roll (start, end);
2588 Editor::play_selected_region ()
2590 framepos_t start = max_framepos;
2593 RegionSelection rs = get_regions_from_selection_and_entered ();
2599 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
2600 if ((*i)->region()->position() < start) {
2601 start = (*i)->region()->position();
2603 if ((*i)->region()->last_frame() + 1 > end) {
2604 end = (*i)->region()->last_frame() + 1;
2608 _session->request_bounded_roll (start, end);
2612 Editor::audition_playlist_region_standalone (boost::shared_ptr<Region> region)
2614 _session->audition_region (region);
2618 Editor::region_from_selection ()
2620 if (clicked_axisview == 0) {
2624 if (selection->time.empty()) {
2628 framepos_t start = selection->time[clicked_selection].start;
2629 framepos_t end = selection->time[clicked_selection].end;
2631 TrackViewList tracks = get_tracks_for_range_action ();
2633 framepos_t selection_cnt = end - start + 1;
2635 for (TrackSelection::iterator i = tracks.begin(); i != tracks.end(); ++i) {
2636 boost::shared_ptr<Region> current;
2637 boost::shared_ptr<Playlist> pl;
2638 framepos_t internal_start;
2641 if ((pl = (*i)->playlist()) == 0) {
2645 if ((current = pl->top_region_at (start)) == 0) {
2649 internal_start = start - current->position();
2650 RegionFactory::region_name (new_name, current->name(), true);
2654 plist.add (ARDOUR::Properties::start, current->start() + internal_start);
2655 plist.add (ARDOUR::Properties::length, selection_cnt);
2656 plist.add (ARDOUR::Properties::name, new_name);
2657 plist.add (ARDOUR::Properties::layer, 0);
2659 boost::shared_ptr<Region> region (RegionFactory::create (current, plist));
2664 Editor::create_region_from_selection (vector<boost::shared_ptr<Region> >& new_regions)
2666 if (selection->time.empty() || selection->tracks.empty()) {
2670 framepos_t start = selection->time[clicked_selection].start;
2671 framepos_t end = selection->time[clicked_selection].end;
2673 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
2674 sort_track_selection (ts);
2676 for (TrackSelection::iterator i = ts.begin(); i != ts.end(); ++i) {
2677 boost::shared_ptr<Region> current;
2678 boost::shared_ptr<Playlist> playlist;
2679 framepos_t internal_start;
2682 if ((playlist = (*i)->playlist()) == 0) {
2686 if ((current = playlist->top_region_at(start)) == 0) {
2690 internal_start = start - current->position();
2691 RegionFactory::region_name (new_name, current->name(), true);
2695 plist.add (ARDOUR::Properties::start, current->start() + internal_start);
2696 plist.add (ARDOUR::Properties::length, end - start + 1);
2697 plist.add (ARDOUR::Properties::name, new_name);
2699 new_regions.push_back (RegionFactory::create (current, plist));
2704 Editor::split_multichannel_region ()
2706 RegionSelection rs = get_regions_from_selection_and_entered ();
2712 vector< boost::shared_ptr<Region> > v;
2714 for (list<RegionView*>::iterator x = rs.begin(); x != rs.end(); ++x) {
2715 (*x)->region()->separate_by_channel (*_session, v);
2720 Editor::new_region_from_selection ()
2722 region_from_selection ();
2723 cancel_selection ();
2727 add_if_covered (RegionView* rv, const AudioRange* ar, RegionSelection* rs)
2729 switch (rv->region()->coverage (ar->start, ar->end - 1)) {
2730 // n.b. -1 because AudioRange::end is one past the end, but coverage expects inclusive ranges
2731 case Evoral::OverlapNone:
2739 * - selected tracks, or if there are none...
2740 * - tracks containing selected regions, or if there are none...
2745 Editor::get_tracks_for_range_action () const
2749 if (selection->tracks.empty()) {
2751 /* use tracks with selected regions */
2753 RegionSelection rs = selection->regions;
2755 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
2756 TimeAxisView* tv = &(*i)->get_time_axis_view();
2758 if (!t.contains (tv)) {
2764 /* no regions and no tracks: use all tracks */
2770 t = selection->tracks;
2773 return t.filter_to_unique_playlists();
2777 Editor::separate_regions_between (const TimeSelection& ts)
2779 bool in_command = false;
2780 boost::shared_ptr<Playlist> playlist;
2781 RegionSelection new_selection;
2783 TrackViewList tmptracks = get_tracks_for_range_action ();
2784 sort_track_selection (tmptracks);
2786 for (TrackSelection::iterator i = tmptracks.begin(); i != tmptracks.end(); ++i) {
2788 RouteTimeAxisView* rtv;
2790 if ((rtv = dynamic_cast<RouteTimeAxisView*> ((*i))) != 0) {
2792 if (rtv->is_track()) {
2794 /* no edits to destructive tracks */
2796 if (rtv->track()->destructive()) {
2800 if ((playlist = rtv->playlist()) != 0) {
2802 playlist->clear_changes ();
2804 /* XXX need to consider musical time selections here at some point */
2806 double speed = rtv->track()->speed();
2809 for (list<AudioRange>::const_iterator t = ts.begin(); t != ts.end(); ++t) {
2811 sigc::connection c = rtv->view()->RegionViewAdded.connect (
2812 sigc::mem_fun(*this, &Editor::collect_new_region_view));
2814 latest_regionviews.clear ();
2816 playlist->partition ((framepos_t)((*t).start * speed),
2817 (framepos_t)((*t).end * speed), false);
2821 if (!latest_regionviews.empty()) {
2823 rtv->view()->foreach_regionview (sigc::bind (
2824 sigc::ptr_fun (add_if_covered),
2825 &(*t), &new_selection));
2828 begin_reversible_command (_("separate"));
2832 /* pick up changes to existing regions */
2834 vector<Command*> cmds;
2835 playlist->rdiff (cmds);
2836 _session->add_commands (cmds);
2838 /* pick up changes to the playlist itself (adds/removes)
2841 _session->add_command(new StatefulDiffCommand (playlist));
2850 // selection->set (new_selection);
2852 commit_reversible_command ();
2856 struct PlaylistState {
2857 boost::shared_ptr<Playlist> playlist;
2861 /** Take tracks from get_tracks_for_range_action and cut any regions
2862 * on those tracks so that the tracks are empty over the time
2866 Editor::separate_region_from_selection ()
2868 /* preferentially use *all* ranges in the time selection if we're in range mode
2869 to allow discontiguous operation, since get_edit_op_range() currently
2870 returns a single range.
2873 if (!selection->time.empty()) {
2875 separate_regions_between (selection->time);
2882 if (get_edit_op_range (start, end)) {
2884 AudioRange ar (start, end, 1);
2888 separate_regions_between (ts);
2894 Editor::separate_region_from_punch ()
2896 Location* loc = _session->locations()->auto_punch_location();
2898 separate_regions_using_location (*loc);
2903 Editor::separate_region_from_loop ()
2905 Location* loc = _session->locations()->auto_loop_location();
2907 separate_regions_using_location (*loc);
2912 Editor::separate_regions_using_location (Location& loc)
2914 if (loc.is_mark()) {
2918 AudioRange ar (loc.start(), loc.end(), 1);
2923 separate_regions_between (ts);
2926 /** Separate regions under the selected region */
2928 Editor::separate_under_selected_regions ()
2930 vector<PlaylistState> playlists;
2934 rs = get_regions_from_selection_and_entered();
2936 if (!_session || rs.empty()) {
2940 begin_reversible_command (_("separate region under"));
2942 list<boost::shared_ptr<Region> > regions_to_remove;
2944 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
2945 // we can't just remove the region(s) in this loop because
2946 // this removes them from the RegionSelection, and they thus
2947 // disappear from underneath the iterator, and the ++i above
2948 // SEGVs in a puzzling fashion.
2950 // so, first iterate over the regions to be removed from rs and
2951 // add them to the regions_to_remove list, and then
2952 // iterate over the list to actually remove them.
2954 regions_to_remove.push_back ((*i)->region());
2957 for (list<boost::shared_ptr<Region> >::iterator rl = regions_to_remove.begin(); rl != regions_to_remove.end(); ++rl) {
2959 boost::shared_ptr<Playlist> playlist = (*rl)->playlist();
2962 // is this check necessary?
2966 vector<PlaylistState>::iterator i;
2968 //only take state if this is a new playlist.
2969 for (i = playlists.begin(); i != playlists.end(); ++i) {
2970 if ((*i).playlist == playlist) {
2975 if (i == playlists.end()) {
2977 PlaylistState before;
2978 before.playlist = playlist;
2979 before.before = &playlist->get_state();
2981 playlist->freeze ();
2982 playlists.push_back(before);
2985 //Partition on the region bounds
2986 playlist->partition ((*rl)->first_frame() - 1, (*rl)->last_frame() + 1, true);
2988 //Re-add region that was just removed due to the partition operation
2989 playlist->add_region( (*rl), (*rl)->first_frame() );
2992 vector<PlaylistState>::iterator pl;
2994 for (pl = playlists.begin(); pl != playlists.end(); ++pl) {
2995 (*pl).playlist->thaw ();
2996 _session->add_command(new MementoCommand<Playlist>(*(*pl).playlist, (*pl).before, &(*pl).playlist->get_state()));
2999 commit_reversible_command ();
3003 Editor::crop_region_to_selection ()
3005 if (!selection->time.empty()) {
3007 crop_region_to (selection->time.start(), selection->time.end_frame());
3014 if (get_edit_op_range (start, end)) {
3015 crop_region_to (start, end);
3022 Editor::crop_region_to (framepos_t start, framepos_t end)
3024 vector<boost::shared_ptr<Playlist> > playlists;
3025 boost::shared_ptr<Playlist> playlist;
3028 if (selection->tracks.empty()) {
3029 ts = track_views.filter_to_unique_playlists();
3031 ts = selection->tracks.filter_to_unique_playlists ();
3034 sort_track_selection (ts);
3036 for (TrackSelection::iterator i = ts.begin(); i != ts.end(); ++i) {
3038 RouteTimeAxisView* rtv;
3040 if ((rtv = dynamic_cast<RouteTimeAxisView*> ((*i))) != 0) {
3042 boost::shared_ptr<Track> t = rtv->track();
3044 if (t != 0 && ! t->destructive()) {
3046 if ((playlist = rtv->playlist()) != 0) {
3047 playlists.push_back (playlist);
3053 if (playlists.empty()) {
3057 framepos_t the_start;
3061 begin_reversible_command (_("trim to selection"));
3063 for (vector<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
3065 boost::shared_ptr<Region> region;
3069 if ((region = (*i)->top_region_at(the_start)) == 0) {
3073 /* now adjust lengths to that we do the right thing
3074 if the selection extends beyond the region
3077 the_start = max (the_start, (framepos_t) region->position());
3078 if (max_framepos - the_start < region->length()) {
3079 the_end = the_start + region->length() - 1;
3081 the_end = max_framepos;
3083 the_end = min (end, the_end);
3084 cnt = the_end - the_start + 1;
3086 region->clear_changes ();
3087 region->trim_to (the_start, cnt);
3088 _session->add_command (new StatefulDiffCommand (region));
3091 commit_reversible_command ();
3095 Editor::region_fill_track ()
3097 RegionSelection rs = get_regions_from_selection_and_entered ();
3099 if (!_session || rs.empty()) {
3103 framepos_t const end = _session->current_end_frame ();
3105 begin_reversible_command (Operations::region_fill);
3107 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3109 boost::shared_ptr<Region> region ((*i)->region());
3111 boost::shared_ptr<Playlist> pl = region->playlist();
3113 if (end <= region->last_frame()) {
3117 double times = (double) (end - region->last_frame()) / (double) region->length();
3123 pl->clear_changes ();
3124 pl->add_region (RegionFactory::create (region, true), region->last_frame(), times);
3125 _session->add_command (new StatefulDiffCommand (pl));
3128 commit_reversible_command ();
3132 Editor::region_fill_selection ()
3134 if (clicked_routeview == 0 || !clicked_routeview->is_audio_track()) {
3138 if (selection->time.empty()) {
3142 boost::shared_ptr<Region> region = _regions->get_single_selection ();
3147 framepos_t start = selection->time[clicked_selection].start;
3148 framepos_t end = selection->time[clicked_selection].end;
3150 boost::shared_ptr<Playlist> playlist;
3152 if (selection->tracks.empty()) {
3156 framepos_t selection_length = end - start;
3157 float times = (float)selection_length / region->length();
3159 begin_reversible_command (Operations::fill_selection);
3161 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
3163 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
3165 if ((playlist = (*i)->playlist()) == 0) {
3169 playlist->clear_changes ();
3170 playlist->add_region (RegionFactory::create (region, true), start, times);
3171 _session->add_command (new StatefulDiffCommand (playlist));
3174 commit_reversible_command ();
3178 Editor::set_region_sync_position ()
3180 set_sync_point (get_preferred_edit_position (), get_regions_from_selection_and_edit_point ());
3184 Editor::set_sync_point (framepos_t where, const RegionSelection& rs)
3186 bool in_command = false;
3188 for (RegionSelection::const_iterator r = rs.begin(); r != rs.end(); ++r) {
3190 if (!(*r)->region()->covers (where)) {
3194 boost::shared_ptr<Region> region ((*r)->region());
3197 begin_reversible_command (_("set sync point"));
3201 region->clear_changes ();
3202 region->set_sync_position (where);
3203 _session->add_command(new StatefulDiffCommand (region));
3207 commit_reversible_command ();
3211 /** Remove the sync positions of the selection */
3213 Editor::remove_region_sync ()
3215 RegionSelection rs = get_regions_from_selection_and_entered ();
3221 begin_reversible_command (_("remove region sync"));
3223 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3225 (*i)->region()->clear_changes ();
3226 (*i)->region()->clear_sync_position ();
3227 _session->add_command(new StatefulDiffCommand ((*i)->region()));
3230 commit_reversible_command ();
3234 Editor::naturalize_region ()
3236 RegionSelection rs = get_regions_from_selection_and_entered ();
3242 if (rs.size() > 1) {
3243 begin_reversible_command (_("move regions to original position"));
3245 begin_reversible_command (_("move region to original position"));
3248 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3249 (*i)->region()->clear_changes ();
3250 (*i)->region()->move_to_natural_position ();
3251 _session->add_command (new StatefulDiffCommand ((*i)->region()));
3254 commit_reversible_command ();
3258 Editor::align_regions (RegionPoint what)
3260 RegionSelection const rs = get_regions_from_selection_and_edit_point ();
3266 begin_reversible_command (_("align selection"));
3268 framepos_t const position = get_preferred_edit_position ();
3270 for (RegionSelection::const_iterator i = rs.begin(); i != rs.end(); ++i) {
3271 align_region_internal ((*i)->region(), what, position);
3274 commit_reversible_command ();
3277 struct RegionSortByTime {
3278 bool operator() (const RegionView* a, const RegionView* b) {
3279 return a->region()->position() < b->region()->position();
3284 Editor::align_regions_relative (RegionPoint point)
3286 RegionSelection const rs = get_regions_from_selection_and_edit_point ();
3292 framepos_t const position = get_preferred_edit_position ();
3294 framepos_t distance = 0;
3298 list<RegionView*> sorted;
3299 rs.by_position (sorted);
3301 boost::shared_ptr<Region> r ((*sorted.begin())->region());
3306 if (position > r->position()) {
3307 distance = position - r->position();
3309 distance = r->position() - position;
3315 if (position > r->last_frame()) {
3316 distance = position - r->last_frame();
3317 pos = r->position() + distance;
3319 distance = r->last_frame() - position;
3320 pos = r->position() - distance;
3326 pos = r->adjust_to_sync (position);
3327 if (pos > r->position()) {
3328 distance = pos - r->position();
3330 distance = r->position() - pos;
3336 if (pos == r->position()) {
3340 begin_reversible_command (_("align selection (relative)"));
3342 /* move first one specially */
3344 r->clear_changes ();
3345 r->set_position (pos);
3346 _session->add_command(new StatefulDiffCommand (r));
3348 /* move rest by the same amount */
3352 for (list<RegionView*>::iterator i = sorted.begin(); i != sorted.end(); ++i) {
3354 boost::shared_ptr<Region> region ((*i)->region());
3356 region->clear_changes ();
3359 region->set_position (region->position() + distance);
3361 region->set_position (region->position() - distance);
3364 _session->add_command(new StatefulDiffCommand (region));
3368 commit_reversible_command ();
3372 Editor::align_region (boost::shared_ptr<Region> region, RegionPoint point, framepos_t position)
3374 begin_reversible_command (_("align region"));
3375 align_region_internal (region, point, position);
3376 commit_reversible_command ();
3380 Editor::align_region_internal (boost::shared_ptr<Region> region, RegionPoint point, framepos_t position)
3382 region->clear_changes ();
3386 region->set_position (region->adjust_to_sync (position));
3390 if (position > region->length()) {
3391 region->set_position (position - region->length());
3396 region->set_position (position);
3400 _session->add_command(new StatefulDiffCommand (region));
3404 Editor::trim_region_front ()
3410 Editor::trim_region_back ()
3412 trim_region (false);
3416 Editor::trim_region (bool front)
3418 framepos_t where = get_preferred_edit_position();
3419 RegionSelection rs = get_regions_from_selection_and_edit_point ();
3425 begin_reversible_command (front ? _("trim front") : _("trim back"));
3427 for (list<RegionView*>::const_iterator i = rs.by_layer().begin(); i != rs.by_layer().end(); ++i) {
3428 if (!(*i)->region()->locked()) {
3430 (*i)->region()->clear_changes ();
3433 (*i)->region()->trim_front (where);
3434 maybe_locate_with_edit_preroll ( where );
3436 (*i)->region()->trim_end (where);
3437 maybe_locate_with_edit_preroll ( where );
3440 _session->add_command (new StatefulDiffCommand ((*i)->region()));
3444 commit_reversible_command ();
3447 /** Trim the end of the selected regions to the position of the edit cursor */
3449 Editor::trim_region_to_loop ()
3451 Location* loc = _session->locations()->auto_loop_location();
3455 trim_region_to_location (*loc, _("trim to loop"));
3459 Editor::trim_region_to_punch ()
3461 Location* loc = _session->locations()->auto_punch_location();
3465 trim_region_to_location (*loc, _("trim to punch"));
3469 Editor::trim_region_to_location (const Location& loc, const char* str)
3471 RegionSelection rs = get_regions_from_selection_and_entered ();
3473 begin_reversible_command (str);
3475 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
3476 RegionView* rv = (*x);
3478 /* require region to span proposed trim */
3479 switch (rv->region()->coverage (loc.start(), loc.end())) {
3480 case Evoral::OverlapInternal:
3486 RouteTimeAxisView* tav = dynamic_cast<RouteTimeAxisView*> (&rv->get_time_axis_view());
3495 if (tav->track() != 0) {
3496 speed = tav->track()->speed();
3499 start = session_frame_to_track_frame (loc.start(), speed);
3500 end = session_frame_to_track_frame (loc.end(), speed);
3502 rv->region()->clear_changes ();
3503 rv->region()->trim_to (start, (end - start));
3504 _session->add_command(new StatefulDiffCommand (rv->region()));
3507 commit_reversible_command ();
3511 Editor::trim_region_to_previous_region_end ()
3513 return trim_to_region(false);
3517 Editor::trim_region_to_next_region_start ()
3519 return trim_to_region(true);
3523 Editor::trim_to_region(bool forward)
3525 RegionSelection rs = get_regions_from_selection_and_entered ();
3527 begin_reversible_command (_("trim to region"));
3529 boost::shared_ptr<Region> next_region;
3531 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
3533 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*x);
3539 AudioTimeAxisView* atav = dynamic_cast<AudioTimeAxisView*> (&arv->get_time_axis_view());
3547 if (atav->track() != 0) {
3548 speed = atav->track()->speed();
3552 boost::shared_ptr<Region> region = arv->region();
3553 boost::shared_ptr<Playlist> playlist (region->playlist());
3555 region->clear_changes ();
3559 next_region = playlist->find_next_region (region->first_frame(), Start, 1);
3565 region->trim_end((framepos_t) ( (next_region->first_frame() - 1) * speed));
3566 arv->region_changed (PropertyChange (ARDOUR::Properties::length));
3570 next_region = playlist->find_next_region (region->first_frame(), Start, 0);
3576 region->trim_front((framepos_t) ((next_region->last_frame() + 1) * speed));
3578 arv->region_changed (ARDOUR::bounds_change);
3581 _session->add_command(new StatefulDiffCommand (region));
3584 commit_reversible_command ();
3588 Editor::unfreeze_route ()
3590 if (clicked_routeview == 0 || !clicked_routeview->is_track()) {
3594 clicked_routeview->track()->unfreeze ();
3598 Editor::_freeze_thread (void* arg)
3600 return static_cast<Editor*>(arg)->freeze_thread ();
3604 Editor::freeze_thread ()
3606 /* create event pool because we may need to talk to the session */
3607 SessionEvent::create_per_thread_pool ("freeze events", 64);
3608 /* create per-thread buffers for process() tree to use */
3609 clicked_routeview->audio_track()->freeze_me (*current_interthread_info);
3610 current_interthread_info->done = true;
3615 Editor::freeze_route ()
3621 /* stop transport before we start. this is important */
3623 _session->request_transport_speed (0.0);
3625 /* wait for just a little while, because the above call is asynchronous */
3627 Glib::usleep (250000);
3629 if (clicked_routeview == 0 || !clicked_routeview->is_audio_track()) {
3633 if (!clicked_routeview->track()->bounceable (clicked_routeview->track()->main_outs(), true)) {
3635 _("This track/bus cannot be frozen because the signal adds or loses channels before reaching the outputs.\n"
3636 "This is typically caused by plugins that generate stereo output from mono input or vice versa.")
3638 d.set_title (_("Cannot freeze"));
3643 if (clicked_routeview->track()->has_external_redirects()) {
3644 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"
3645 "Freezing will only process the signal as far as the first send/insert/return."),
3646 clicked_routeview->track()->name()), true, MESSAGE_INFO, BUTTONS_NONE, true);
3648 d.add_button (_("Freeze anyway"), Gtk::RESPONSE_OK);
3649 d.add_button (_("Don't freeze"), Gtk::RESPONSE_CANCEL);
3650 d.set_title (_("Freeze Limits"));
3652 int response = d.run ();
3655 case Gtk::RESPONSE_CANCEL:
3662 InterThreadInfo itt;
3663 current_interthread_info = &itt;
3665 InterthreadProgressWindow ipw (current_interthread_info, _("Freeze"), _("Cancel Freeze"));
3667 pthread_create_and_store (X_("freezer"), &itt.thread, _freeze_thread, this);
3669 set_canvas_cursor (_cursors->wait);
3671 while (!itt.done && !itt.cancel) {
3672 gtk_main_iteration ();
3675 current_interthread_info = 0;
3676 set_canvas_cursor (current_canvas_cursor);
3680 Editor::bounce_range_selection (bool replace, bool enable_processing)
3682 if (selection->time.empty()) {
3686 TrackSelection views = selection->tracks;
3688 for (TrackViewList::iterator i = views.begin(); i != views.end(); ++i) {
3690 if (enable_processing) {
3692 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*i);
3694 if (rtv && rtv->track() && replace && enable_processing && !rtv->track()->bounceable (rtv->track()->main_outs(), false)) {
3696 _("You can't perform this operation because the processing of the signal "
3697 "will cause one or more of the tracks to end up with a region with more channels than this track has inputs.\n\n"
3698 "You can do this without processing, which is a different operation.")
3700 d.set_title (_("Cannot bounce"));
3707 framepos_t start = selection->time[clicked_selection].start;
3708 framepos_t end = selection->time[clicked_selection].end;
3709 framepos_t cnt = end - start + 1;
3711 begin_reversible_command (_("bounce range"));
3713 for (TrackViewList::iterator i = views.begin(); i != views.end(); ++i) {
3715 RouteTimeAxisView* rtv;
3717 if ((rtv = dynamic_cast<RouteTimeAxisView*> (*i)) == 0) {
3721 boost::shared_ptr<Playlist> playlist;
3723 if ((playlist = rtv->playlist()) == 0) {
3727 InterThreadInfo itt;
3729 playlist->clear_changes ();
3730 playlist->clear_owned_changes ();
3732 boost::shared_ptr<Region> r;
3734 if (enable_processing) {
3735 r = rtv->track()->bounce_range (start, start+cnt, itt, rtv->track()->main_outs(), false);
3737 r = rtv->track()->bounce_range (start, start+cnt, itt, boost::shared_ptr<Processor>(), false);
3745 list<AudioRange> ranges;
3746 ranges.push_back (AudioRange (start, start+cnt, 0));
3747 playlist->cut (ranges); // discard result
3748 playlist->add_region (r, start);
3751 vector<Command*> cmds;
3752 playlist->rdiff (cmds);
3753 _session->add_commands (cmds);
3755 _session->add_command (new StatefulDiffCommand (playlist));
3758 commit_reversible_command ();
3761 /** Delete selected regions, automation points or a time range */
3765 //special case: if the user is pointing in the editor/mixer strip, they may be trying to delete a plugin.
3766 //we need this because the editor-mixer strip is in the editor window, so it doesn't get the bindings from the mix window
3767 bool deleted = false;
3768 if ( current_mixer_strip && current_mixer_strip == MixerStrip::entered_mixer_strip() )
3769 deleted = current_mixer_strip->delete_processors ();
3775 /** Cut selected regions, automation points or a time range */
3782 /** Copy selected regions, automation points or a time range */
3790 /** @return true if a Cut, Copy or Clear is possible */
3792 Editor::can_cut_copy () const
3794 if (!selection->time.empty() || !selection->regions.empty() || !selection->points.empty())
3801 /** Cut, copy or clear selected regions, automation points or a time range.
3802 * @param op Operation (Delete, Cut, Copy or Clear)
3805 Editor::cut_copy (CutCopyOp op)
3807 /* only cancel selection if cut/copy is successful.*/
3813 opname = _("delete");
3822 opname = _("clear");
3826 /* if we're deleting something, and the mouse is still pressed,
3827 the thing we started a drag for will be gone when we release
3828 the mouse button(s). avoid this. see part 2 at the end of
3832 if (op == Delete || op == Cut || op == Clear) {
3833 if (_drags->active ()) {
3838 if ( op != Delete ) //"Delete" doesn't change copy/paste buf
3839 cut_buffer->clear ();
3841 if (entered_marker) {
3843 /* cut/delete op while pointing at a marker */
3846 Location* loc = find_location_from_marker (entered_marker, ignored);
3848 if (_session && loc) {
3849 Glib::signal_idle().connect (sigc::bind (sigc::mem_fun(*this, &Editor::really_remove_marker), loc));
3856 if (internal_editing()) {
3858 switch (effective_mouse_mode()) {
3861 begin_reversible_command (opname + ' ' + X_("MIDI"));
3863 commit_reversible_command ();
3872 bool did_edit = false;
3874 if (!selection->regions.empty() || !selection->points.empty()) {
3875 begin_reversible_command (opname + ' ' + _("objects"));
3878 if (!selection->regions.empty()) {
3879 cut_copy_regions (op, selection->regions);
3881 if (op == Cut || op == Delete) {
3882 selection->clear_regions ();
3886 if (!selection->points.empty()) {
3887 cut_copy_points (op);
3889 if (op == Cut || op == Delete) {
3890 selection->clear_points ();
3893 } else if (selection->time.empty()) {
3894 framepos_t start, end;
3895 /* no time selection, see if we can get an edit range
3898 if (get_edit_op_range (start, end)) {
3899 selection->set (start, end);
3901 } else if (!selection->time.empty()) {
3902 begin_reversible_command (opname + ' ' + _("range"));
3905 cut_copy_ranges (op);
3907 if (op == Cut || op == Delete) {
3908 selection->clear_time ();
3913 /* reset repeated paste state */
3916 commit_reversible_command ();
3919 if (op == Delete || op == Cut || op == Clear) {
3924 struct AutomationRecord {
3925 AutomationRecord () : state (0) , line(NULL) {}
3926 AutomationRecord (XMLNode* s, const AutomationLine* l) : state (s) , line (l) {}
3928 XMLNode* state; ///< state before any operation
3929 const AutomationLine* line; ///< line this came from
3930 boost::shared_ptr<Evoral::ControlList> copy; ///< copied events for the cut buffer
3933 /** Cut, copy or clear selected automation points.
3934 * @param op Operation (Cut, Copy or Clear)
3937 Editor::cut_copy_points (Editing::CutCopyOp op, Evoral::MusicalTime earliest, bool midi)
3939 if (selection->points.empty ()) {
3943 /* XXX: not ideal, as there may be more than one track involved in the point selection */
3944 _last_cut_copy_source_track = &selection->points.front()->line().trackview;
3946 /* Keep a record of the AutomationLists that we end up using in this operation */
3947 typedef std::map<boost::shared_ptr<AutomationList>, AutomationRecord> Lists;
3950 /* Go through all selected points, making an AutomationRecord for each distinct AutomationList */
3951 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
3952 const AutomationLine& line = (*i)->line();
3953 const boost::shared_ptr<AutomationList> al = line.the_list();
3954 if (lists.find (al) == lists.end ()) {
3955 /* We haven't seen this list yet, so make a record for it. This includes
3956 taking a copy of its current state, in case this is needed for undo later.
3958 lists[al] = AutomationRecord (&al->get_state (), &line);
3962 if (op == Cut || op == Copy) {
3963 /* This operation will involve putting things in the cut buffer, so create an empty
3964 ControlList for each of our source lists to put the cut buffer data in.
3966 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
3967 i->second.copy = i->first->create (i->first->parameter (), i->first->descriptor());
3970 /* Add all selected points to the relevant copy ControlLists */
3971 framepos_t start = std::numeric_limits<framepos_t>::max();
3972 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
3973 boost::shared_ptr<AutomationList> al = (*i)->line().the_list();
3974 AutomationList::const_iterator j = (*i)->model();
3976 lists[al].copy->fast_simple_add ((*j)->when, (*j)->value);
3978 /* Update earliest MIDI start time in beats */
3979 earliest = std::min(earliest, Evoral::MusicalTime((*j)->when));
3981 /* Update earliest session start time in frames */
3982 start = std::min(start, (*i)->line().session_position(j));
3986 /* Snap start time backwards, so copy/paste is snap aligned. */
3988 if (earliest == Evoral::MusicalTime::max()) {
3989 earliest = Evoral::MusicalTime(); // Weird... don't offset
3991 earliest.round_down_to_beat();
3993 if (start == std::numeric_limits<double>::max()) {
3994 start = 0; // Weird... don't offset
3996 snap_to(start, RoundDownMaybe);
3999 const double line_offset = midi ? earliest.to_double() : start;
4000 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
4001 /* Correct this copy list so that it is relative to the earliest
4002 start time, so relative ordering between points is preserved
4003 when copying from several lists and the paste starts at the
4004 earliest copied piece of data. */
4005 for (AutomationList::iterator j = i->second.copy->begin(); j != i->second.copy->end(); ++j) {
4006 (*j)->when -= line_offset;
4009 /* And add it to the cut buffer */
4010 cut_buffer->add (i->second.copy);
4014 if (op == Delete || op == Cut) {
4015 /* This operation needs to remove things from the main AutomationList, so do that now */
4017 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
4018 i->first->freeze ();
4021 /* Remove each selected point from its AutomationList */
4022 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
4023 boost::shared_ptr<AutomationList> al = (*i)->line().the_list();
4024 al->erase ((*i)->model ());
4027 /* Thaw the lists and add undo records for them */
4028 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
4029 boost::shared_ptr<AutomationList> al = i->first;
4031 _session->add_command (new MementoCommand<AutomationList> (*al.get(), i->second.state, &(al->get_state ())));
4036 /** Cut, copy or clear selected automation points.
4037 * @param op Operation (Cut, Copy or Clear)
4040 Editor::cut_copy_midi (CutCopyOp op)
4042 Evoral::MusicalTime earliest = Evoral::MusicalTime::max();
4043 for (MidiRegionSelection::iterator i = selection->midi_regions.begin(); i != selection->midi_regions.end(); ++i) {
4044 MidiRegionView* mrv = dynamic_cast<MidiRegionView*>(*i);
4046 if (!mrv->selection().empty()) {
4047 earliest = std::min(earliest, (*mrv->selection().begin())->note()->time());
4049 mrv->cut_copy_clear (op);
4051 /* XXX: not ideal, as there may be more than one track involved in the selection */
4052 _last_cut_copy_source_track = &mrv->get_time_axis_view();
4056 if (!selection->points.empty()) {
4057 cut_copy_points (op, earliest, true);
4058 if (op == Cut || op == Delete) {
4059 selection->clear_points ();
4064 struct lt_playlist {
4065 bool operator () (const PlaylistState& a, const PlaylistState& b) {
4066 return a.playlist < b.playlist;
4070 struct PlaylistMapping {
4072 boost::shared_ptr<Playlist> pl;
4074 PlaylistMapping (TimeAxisView* tvp) : tv (tvp) {}
4077 /** Remove `clicked_regionview' */
4079 Editor::remove_clicked_region ()
4081 if (clicked_routeview == 0 || clicked_regionview == 0) {
4085 begin_reversible_command (_("remove region"));
4087 boost::shared_ptr<Playlist> playlist = clicked_routeview->playlist();
4089 playlist->clear_changes ();
4090 playlist->clear_owned_changes ();
4091 playlist->remove_region (clicked_regionview->region());
4092 if (Config->get_edit_mode() == Ripple)
4093 playlist->ripple (clicked_regionview->region()->position(), -clicked_regionview->region()->length(), boost::shared_ptr<Region>());
4095 /* We might have removed regions, which alters other regions' layering_index,
4096 so we need to do a recursive diff here.
4098 vector<Command*> cmds;
4099 playlist->rdiff (cmds);
4100 _session->add_commands (cmds);
4102 _session->add_command(new StatefulDiffCommand (playlist));
4103 commit_reversible_command ();
4107 /** Remove the selected regions */
4109 Editor::remove_selected_regions ()
4111 RegionSelection rs = get_regions_from_selection_and_entered ();
4113 if (!_session || rs.empty()) {
4117 begin_reversible_command (_("remove region"));
4119 list<boost::shared_ptr<Region> > regions_to_remove;
4121 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
4122 // we can't just remove the region(s) in this loop because
4123 // this removes them from the RegionSelection, and they thus
4124 // disappear from underneath the iterator, and the ++i above
4125 // SEGVs in a puzzling fashion.
4127 // so, first iterate over the regions to be removed from rs and
4128 // add them to the regions_to_remove list, and then
4129 // iterate over the list to actually remove them.
4131 regions_to_remove.push_back ((*i)->region());
4134 vector<boost::shared_ptr<Playlist> > playlists;
4136 for (list<boost::shared_ptr<Region> >::iterator rl = regions_to_remove.begin(); rl != regions_to_remove.end(); ++rl) {
4138 boost::shared_ptr<Playlist> playlist = (*rl)->playlist();
4141 // is this check necessary?
4145 /* get_regions_from_selection_and_entered() guarantees that
4146 the playlists involved are unique, so there is no need
4150 playlists.push_back (playlist);
4152 playlist->clear_changes ();
4153 playlist->clear_owned_changes ();
4154 playlist->freeze ();
4155 playlist->remove_region (*rl);
4156 if (Config->get_edit_mode() == Ripple)
4157 playlist->ripple ((*rl)->position(), -(*rl)->length(), boost::shared_ptr<Region>());
4161 vector<boost::shared_ptr<Playlist> >::iterator pl;
4163 for (pl = playlists.begin(); pl != playlists.end(); ++pl) {
4166 /* We might have removed regions, which alters other regions' layering_index,
4167 so we need to do a recursive diff here.
4169 vector<Command*> cmds;
4170 (*pl)->rdiff (cmds);
4171 _session->add_commands (cmds);
4173 _session->add_command(new StatefulDiffCommand (*pl));
4176 commit_reversible_command ();
4179 /** Cut, copy or clear selected regions.
4180 * @param op Operation (Cut, Copy or Clear)
4183 Editor::cut_copy_regions (CutCopyOp op, RegionSelection& rs)
4185 /* we can't use a std::map here because the ordering is important, and we can't trivially sort
4186 a map when we want ordered access to both elements. i think.
4189 vector<PlaylistMapping> pmap;
4191 framepos_t first_position = max_framepos;
4193 typedef set<boost::shared_ptr<Playlist> > FreezeList;
4194 FreezeList freezelist;
4196 /* get ordering correct before we cut/copy */
4198 rs.sort_by_position_and_track ();
4200 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
4202 first_position = min ((framepos_t) (*x)->region()->position(), first_position);
4204 if (op == Cut || op == Clear || op == Delete) {
4205 boost::shared_ptr<Playlist> pl = (*x)->region()->playlist();
4208 FreezeList::iterator fl;
4210 // only take state if this is a new playlist.
4211 for (fl = freezelist.begin(); fl != freezelist.end(); ++fl) {
4217 if (fl == freezelist.end()) {
4218 pl->clear_changes();
4219 pl->clear_owned_changes ();
4221 freezelist.insert (pl);
4226 TimeAxisView* tv = &(*x)->get_time_axis_view();
4227 vector<PlaylistMapping>::iterator z;
4229 for (z = pmap.begin(); z != pmap.end(); ++z) {
4230 if ((*z).tv == tv) {
4235 if (z == pmap.end()) {
4236 pmap.push_back (PlaylistMapping (tv));
4240 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ) {
4242 boost::shared_ptr<Playlist> pl = (*x)->region()->playlist();
4245 /* region not yet associated with a playlist (e.g. unfinished
4252 TimeAxisView& tv = (*x)->get_time_axis_view();
4253 boost::shared_ptr<Playlist> npl;
4254 RegionSelection::iterator tmp;
4261 vector<PlaylistMapping>::iterator z;
4263 for (z = pmap.begin(); z != pmap.end(); ++z) {
4264 if ((*z).tv == &tv) {
4269 assert (z != pmap.end());
4272 npl = PlaylistFactory::create (pl->data_type(), *_session, "cutlist", true);
4280 boost::shared_ptr<Region> r = (*x)->region();
4281 boost::shared_ptr<Region> _xx;
4287 pl->remove_region (r);
4288 if (Config->get_edit_mode() == Ripple)
4289 pl->ripple (r->position(), -r->length(), boost::shared_ptr<Region>());
4293 _xx = RegionFactory::create (r);
4294 npl->add_region (_xx, r->position() - first_position);
4295 pl->remove_region (r);
4296 if (Config->get_edit_mode() == Ripple)
4297 pl->ripple (r->position(), -r->length(), boost::shared_ptr<Region>());
4301 /* copy region before adding, so we're not putting same object into two different playlists */
4302 npl->add_region (RegionFactory::create (r), r->position() - first_position);
4306 pl->remove_region (r);
4307 if (Config->get_edit_mode() == Ripple)
4308 pl->ripple (r->position(), -r->length(), boost::shared_ptr<Region>());
4317 list<boost::shared_ptr<Playlist> > foo;
4319 /* the pmap is in the same order as the tracks in which selected regions occured */
4321 for (vector<PlaylistMapping>::iterator i = pmap.begin(); i != pmap.end(); ++i) {
4324 foo.push_back ((*i).pl);
4329 cut_buffer->set (foo);
4333 _last_cut_copy_source_track = 0;
4335 _last_cut_copy_source_track = pmap.front().tv;
4339 for (FreezeList::iterator pl = freezelist.begin(); pl != freezelist.end(); ++pl) {
4342 /* We might have removed regions, which alters other regions' layering_index,
4343 so we need to do a recursive diff here.
4345 vector<Command*> cmds;
4346 (*pl)->rdiff (cmds);
4347 _session->add_commands (cmds);
4349 _session->add_command (new StatefulDiffCommand (*pl));
4354 Editor::cut_copy_ranges (CutCopyOp op)
4356 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4358 /* Sort the track selection now, so that it if is used, the playlists
4359 selected by the calls below to cut_copy_clear are in the order that
4360 their tracks appear in the editor. This makes things like paste
4361 of ranges work properly.
4364 sort_track_selection (ts);
4367 if (!entered_track) {
4370 ts.push_back (entered_track);
4373 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4374 (*i)->cut_copy_clear (*selection, op);
4379 Editor::paste (float times, bool from_context)
4381 DEBUG_TRACE (DEBUG::CutNPaste, "paste to preferred edit pos\n");
4383 paste_internal (get_preferred_edit_position (false, from_context), times);
4387 Editor::mouse_paste ()
4392 if (!mouse_frame (where, ignored)) {
4397 paste_internal (where, 1);
4401 Editor::paste_internal (framepos_t position, float times)
4403 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("apparent paste position is %1\n", position));
4405 if (cut_buffer->empty(internal_editing())) {
4409 if (position == max_framepos) {
4410 position = get_preferred_edit_position();
4411 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("preferred edit position is %1\n", position));
4414 if (position == last_paste_pos) {
4415 /* repeated paste in the same position */
4418 /* paste in new location, reset repeated paste state */
4420 last_paste_pos = position;
4423 /* get everything in the correct order */
4426 if (!selection->tracks.empty()) {
4427 /* If there is a track selection, paste into exactly those tracks and
4428 only those tracks. This allows the user to be explicit and override
4429 the below "do the reasonable thing" logic. */
4430 ts = selection->tracks.filter_to_unique_playlists ();
4431 sort_track_selection (ts);
4433 /* Figure out which track to base the paste at. */
4434 TimeAxisView* base_track = NULL;
4435 if (_edit_point == Editing::EditAtMouse && entered_track) {
4436 /* With the mouse edit point, paste onto the track under the mouse. */
4437 base_track = entered_track;
4438 } else if (_edit_point == Editing::EditAtMouse && entered_regionview) {
4439 /* With the mouse edit point, paste onto the track of the region under the mouse. */
4440 base_track = &entered_regionview->get_time_axis_view();
4441 } else if (_last_cut_copy_source_track) {
4442 /* Paste to the track that the cut/copy came from (see mantis #333). */
4443 base_track = _last_cut_copy_source_track;
4445 /* This is "impossible" since we've copied... well, do nothing. */
4449 /* Walk up to parent if necessary, so base track is a route. */
4450 while (base_track->get_parent()) {
4451 base_track = base_track->get_parent();
4454 /* Add base track and all tracks below it. The paste logic will select
4455 the appropriate object types from the cut buffer in relative order. */
4456 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4457 if ((*i)->order() >= base_track->order()) {
4462 /* Sort tracks so the nth track of type T will pick the nth object of type T. */
4463 sort_track_selection (ts);
4465 /* Add automation children of each track in order, for pasting several lines. */
4466 for (TrackViewList::iterator i = ts.begin(); i != ts.end();) {
4467 /* Add any automation children for pasting several lines */
4468 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*i++);
4473 typedef RouteTimeAxisView::AutomationTracks ATracks;
4474 const ATracks& atracks = rtv->automation_tracks();
4475 for (ATracks::const_iterator a = atracks.begin(); a != atracks.end(); ++a) {
4476 i = ts.insert(i, a->second.get());
4481 /* We now have a list of trackviews starting at base_track, including
4482 automation children, in the order shown in the editor, e.g. R1,
4483 R1.A1, R1.A2, R2, R2.A1, ... */
4486 if (ts.size() == 1 && cut_buffer->lines.size() == 1 &&
4487 dynamic_cast<AutomationTimeAxisView*>(ts.front())) {
4488 /* Only one line copied, and one automation track selected. Do a
4489 "greedy" paste from one automation type to another. */
4491 begin_reversible_command (Operations::paste);
4493 PasteContext ctx(paste_count, times, ItemCounts(), true);
4494 ts.front()->paste (position, *cut_buffer, ctx);
4496 commit_reversible_command ();
4498 } else if (internal_editing ()) {
4500 /* undo/redo is handled by individual tracks/regions */
4503 get_regions_at (rs, position, ts);
4505 PasteContext ctx(paste_count, times, ItemCounts(), false);
4506 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
4507 MidiRegionView* mrv = dynamic_cast<MidiRegionView*> (*r);
4509 mrv->paste (position, *cut_buffer, ctx);
4515 /* we do redo (do you do voodoo?) */
4517 begin_reversible_command (Operations::paste);
4519 PasteContext ctx(paste_count, times, ItemCounts(), false);
4520 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4521 (*i)->paste (position, *cut_buffer, ctx);
4524 commit_reversible_command ();
4529 Editor::duplicate_some_regions (RegionSelection& regions, float times)
4531 boost::shared_ptr<Playlist> playlist;
4532 RegionSelection sel = regions; // clear (below) may clear the argument list if its the current region selection
4533 RegionSelection foo;
4535 framepos_t const start_frame = regions.start ();
4536 framepos_t const end_frame = regions.end_frame ();
4538 begin_reversible_command (Operations::duplicate_region);
4540 selection->clear_regions ();
4542 for (RegionSelection::iterator i = sel.begin(); i != sel.end(); ++i) {
4544 boost::shared_ptr<Region> r ((*i)->region());
4546 TimeAxisView& tv = (*i)->get_time_axis_view();
4547 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (&tv);
4548 latest_regionviews.clear ();
4549 sigc::connection c = rtv->view()->RegionViewAdded.connect (sigc::mem_fun(*this, &Editor::collect_new_region_view));
4551 playlist = (*i)->region()->playlist();
4552 playlist->clear_changes ();
4553 playlist->duplicate (r, end_frame + (r->first_frame() - start_frame), times);
4554 _session->add_command(new StatefulDiffCommand (playlist));
4558 foo.insert (foo.end(), latest_regionviews.begin(), latest_regionviews.end());
4562 selection->set (foo);
4565 commit_reversible_command ();
4569 Editor::duplicate_selection (float times)
4571 if (selection->time.empty() || selection->tracks.empty()) {
4575 boost::shared_ptr<Playlist> playlist;
4576 vector<boost::shared_ptr<Region> > new_regions;
4577 vector<boost::shared_ptr<Region> >::iterator ri;
4579 create_region_from_selection (new_regions);
4581 if (new_regions.empty()) {
4585 begin_reversible_command (_("duplicate selection"));
4587 ri = new_regions.begin();
4589 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4591 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4592 if ((playlist = (*i)->playlist()) == 0) {
4595 playlist->clear_changes ();
4596 playlist->duplicate (*ri, selection->time[clicked_selection].end, times);
4597 _session->add_command (new StatefulDiffCommand (playlist));
4600 if (ri == new_regions.end()) {
4605 commit_reversible_command ();
4608 /** Reset all selected points to the relevant default value */
4610 Editor::reset_point_selection ()
4612 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
4613 ARDOUR::AutomationList::iterator j = (*i)->model ();
4614 (*j)->value = (*i)->line().the_list()->default_value ();
4619 Editor::center_playhead ()
4621 float const page = _visible_canvas_width * samples_per_pixel;
4622 center_screen_internal (playhead_cursor->current_frame (), page);
4626 Editor::center_edit_point ()
4628 float const page = _visible_canvas_width * samples_per_pixel;
4629 center_screen_internal (get_preferred_edit_position(), page);
4632 /** Caller must begin and commit a reversible command */
4634 Editor::clear_playlist (boost::shared_ptr<Playlist> playlist)
4636 playlist->clear_changes ();
4638 _session->add_command (new StatefulDiffCommand (playlist));
4642 Editor::nudge_track (bool use_edit, bool forwards)
4644 boost::shared_ptr<Playlist> playlist;
4645 framepos_t distance;
4646 framepos_t next_distance;
4650 start = get_preferred_edit_position();
4655 if ((distance = get_nudge_distance (start, next_distance)) == 0) {
4659 if (selection->tracks.empty()) {
4663 begin_reversible_command (_("nudge track"));
4665 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4667 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4669 if ((playlist = (*i)->playlist()) == 0) {
4673 playlist->clear_changes ();
4674 playlist->clear_owned_changes ();
4676 playlist->nudge_after (start, distance, forwards);
4678 vector<Command*> cmds;
4680 playlist->rdiff (cmds);
4681 _session->add_commands (cmds);
4683 _session->add_command (new StatefulDiffCommand (playlist));
4686 commit_reversible_command ();
4690 Editor::remove_last_capture ()
4692 vector<string> choices;
4699 if (Config->get_verify_remove_last_capture()) {
4700 prompt = _("Do you really want to destroy the last capture?"
4701 "\n(This is destructive and cannot be undone)");
4703 choices.push_back (_("No, do nothing."));
4704 choices.push_back (_("Yes, destroy it."));
4706 Gtkmm2ext::Choice prompter (_("Destroy last capture"), prompt, choices);
4708 if (prompter.run () == 1) {
4709 _session->remove_last_capture ();
4710 _regions->redisplay ();
4714 _session->remove_last_capture();
4715 _regions->redisplay ();
4720 Editor::normalize_region ()
4726 RegionSelection rs = get_regions_from_selection_and_entered ();
4732 NormalizeDialog dialog (rs.size() > 1);
4734 if (dialog.run () == RESPONSE_CANCEL) {
4738 set_canvas_cursor (_cursors->wait);
4741 /* XXX: should really only count audio regions here */
4742 int const regions = rs.size ();
4744 /* Make a list of the selected audio regions' maximum amplitudes, and also
4745 obtain the maximum amplitude of them all.
4747 list<double> max_amps;
4749 for (RegionSelection::const_iterator i = rs.begin(); i != rs.end(); ++i) {
4750 AudioRegionView const * arv = dynamic_cast<AudioRegionView const *> (*i);
4752 dialog.descend (1.0 / regions);
4753 double const a = arv->audio_region()->maximum_amplitude (&dialog);
4756 /* the user cancelled the operation */
4757 set_canvas_cursor (current_canvas_cursor);
4761 max_amps.push_back (a);
4762 max_amp = max (max_amp, a);
4767 begin_reversible_command (_("normalize"));
4769 list<double>::const_iterator a = max_amps.begin ();
4771 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
4772 AudioRegionView* const arv = dynamic_cast<AudioRegionView*> (*r);
4777 arv->region()->clear_changes ();
4779 double const amp = dialog.normalize_individually() ? *a : max_amp;
4781 arv->audio_region()->normalize (amp, dialog.target ());
4782 _session->add_command (new StatefulDiffCommand (arv->region()));
4787 commit_reversible_command ();
4788 set_canvas_cursor (current_canvas_cursor);
4793 Editor::reset_region_scale_amplitude ()
4799 RegionSelection rs = get_regions_from_selection_and_entered ();
4805 begin_reversible_command ("reset gain");
4807 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
4808 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
4811 arv->region()->clear_changes ();
4812 arv->audio_region()->set_scale_amplitude (1.0f);
4813 _session->add_command (new StatefulDiffCommand (arv->region()));
4816 commit_reversible_command ();
4820 Editor::adjust_region_gain (bool up)
4822 RegionSelection rs = get_regions_from_selection_and_entered ();
4824 if (!_session || rs.empty()) {
4828 begin_reversible_command ("adjust region gain");
4830 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
4831 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
4836 arv->region()->clear_changes ();
4838 double dB = accurate_coefficient_to_dB (arv->audio_region()->scale_amplitude ());
4846 arv->audio_region()->set_scale_amplitude (dB_to_coefficient (dB));
4847 _session->add_command (new StatefulDiffCommand (arv->region()));
4850 commit_reversible_command ();
4855 Editor::reverse_region ()
4861 Reverse rev (*_session);
4862 apply_filter (rev, _("reverse regions"));
4866 Editor::strip_region_silence ()
4872 RegionSelection rs = get_regions_from_selection_and_entered ();
4878 std::list<RegionView*> audio_only;
4880 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
4881 AudioRegionView* const arv = dynamic_cast<AudioRegionView*> (*i);
4883 audio_only.push_back (arv);
4887 StripSilenceDialog d (_session, audio_only);
4888 int const r = d.run ();
4892 if (r == Gtk::RESPONSE_OK) {
4893 ARDOUR::AudioIntervalMap silences;
4894 d.silences (silences);
4895 StripSilence s (*_session, silences, d.fade_length());
4896 apply_filter (s, _("strip silence"), &d);
4901 Editor::apply_midi_note_edit_op_to_region (MidiOperator& op, MidiRegionView& mrv)
4903 Evoral::Sequence<Evoral::MusicalTime>::Notes selected;
4904 mrv.selection_as_notelist (selected, true);
4906 vector<Evoral::Sequence<Evoral::MusicalTime>::Notes> v;
4907 v.push_back (selected);
4909 framepos_t pos_frames = mrv.midi_region()->position() - mrv.midi_region()->start();
4910 Evoral::MusicalTime pos_beats = _session->tempo_map().framewalk_to_beats(0, pos_frames);
4912 return op (mrv.midi_region()->model(), pos_beats, v);
4916 Editor::apply_midi_note_edit_op (MidiOperator& op)
4920 RegionSelection rs = get_regions_from_selection_and_entered ();
4926 begin_reversible_command (op.name ());
4928 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
4929 RegionSelection::iterator tmp = r;
4932 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*r);
4935 cmd = apply_midi_note_edit_op_to_region (op, *mrv);
4938 _session->add_command (cmd);
4945 commit_reversible_command ();
4949 Editor::fork_region ()
4951 RegionSelection rs = get_regions_from_selection_and_entered ();
4957 begin_reversible_command (_("Fork Region(s)"));
4959 set_canvas_cursor (_cursors->wait);
4962 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
4963 RegionSelection::iterator tmp = r;
4966 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*>(*r);
4970 boost::shared_ptr<Playlist> playlist = mrv->region()->playlist();
4971 boost::shared_ptr<MidiSource> new_source = _session->create_midi_source_by_stealing_name (mrv->midi_view()->track());
4972 boost::shared_ptr<MidiRegion> newregion = mrv->midi_region()->clone (new_source);
4974 playlist->clear_changes ();
4975 playlist->replace_region (mrv->region(), newregion, mrv->region()->position());
4976 _session->add_command(new StatefulDiffCommand (playlist));
4978 error << string_compose (_("Could not unlink %1"), mrv->region()->name()) << endmsg;
4985 commit_reversible_command ();
4987 set_canvas_cursor (current_canvas_cursor);
4991 Editor::quantize_region ()
4993 int selected_midi_region_cnt = 0;
4999 RegionSelection rs = get_regions_from_selection_and_entered ();
5005 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
5006 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*r);
5008 selected_midi_region_cnt++;
5012 if (selected_midi_region_cnt == 0) {
5016 QuantizeDialog* qd = new QuantizeDialog (*this);
5019 const int r = qd->run ();
5022 if (r == Gtk::RESPONSE_OK) {
5023 Quantize quant (qd->snap_start(), qd->snap_end(),
5024 qd->start_grid_size(), qd->end_grid_size(),
5025 qd->strength(), qd->swing(), qd->threshold());
5027 apply_midi_note_edit_op (quant);
5032 Editor::legatize_region (bool shrink_only)
5034 int selected_midi_region_cnt = 0;
5040 RegionSelection rs = get_regions_from_selection_and_entered ();
5046 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
5047 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*r);
5049 selected_midi_region_cnt++;
5053 if (selected_midi_region_cnt == 0) {
5057 Legatize legatize(shrink_only);
5058 apply_midi_note_edit_op (legatize);
5062 Editor::insert_patch_change (bool from_context)
5064 RegionSelection rs = get_regions_from_selection_and_entered ();
5070 const framepos_t p = get_preferred_edit_position (false, from_context);
5072 /* XXX: bit of a hack; use the MIDNAM from the first selected region;
5073 there may be more than one, but the PatchChangeDialog can only offer
5074 one set of patch menus.
5076 MidiRegionView* first = dynamic_cast<MidiRegionView*> (rs.front ());
5078 Evoral::PatchChange<Evoral::MusicalTime> empty (Evoral::MusicalTime(), 0, 0, 0);
5079 PatchChangeDialog d (0, _session, empty, first->instrument_info(), Gtk::Stock::ADD);
5081 if (d.run() == RESPONSE_CANCEL) {
5085 for (RegionSelection::iterator i = rs.begin (); i != rs.end(); ++i) {
5086 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*i);
5088 if (p >= mrv->region()->first_frame() && p <= mrv->region()->last_frame()) {
5089 mrv->add_patch_change (p - mrv->region()->position(), d.patch ());
5096 Editor::apply_filter (Filter& filter, string command, ProgressReporter* progress)
5098 RegionSelection rs = get_regions_from_selection_and_entered ();
5104 begin_reversible_command (command);
5106 set_canvas_cursor (_cursors->wait);
5110 int const N = rs.size ();
5112 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
5113 RegionSelection::iterator tmp = r;
5116 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
5118 boost::shared_ptr<Playlist> playlist = arv->region()->playlist();
5121 progress->descend (1.0 / N);
5124 if (arv->audio_region()->apply (filter, progress) == 0) {
5126 playlist->clear_changes ();
5127 playlist->clear_owned_changes ();
5129 if (filter.results.empty ()) {
5131 /* no regions returned; remove the old one */
5132 playlist->remove_region (arv->region ());
5136 std::vector<boost::shared_ptr<Region> >::iterator res = filter.results.begin ();
5138 /* first region replaces the old one */
5139 playlist->replace_region (arv->region(), *res, (*res)->position());
5143 while (res != filter.results.end()) {
5144 playlist->add_region (*res, (*res)->position());
5150 /* We might have removed regions, which alters other regions' layering_index,
5151 so we need to do a recursive diff here.
5153 vector<Command*> cmds;
5154 playlist->rdiff (cmds);
5155 _session->add_commands (cmds);
5157 _session->add_command(new StatefulDiffCommand (playlist));
5163 progress->ascend ();
5171 commit_reversible_command ();
5174 set_canvas_cursor (current_canvas_cursor);
5178 Editor::external_edit_region ()
5184 Editor::reset_region_gain_envelopes ()
5186 RegionSelection rs = get_regions_from_selection_and_entered ();
5188 if (!_session || rs.empty()) {
5192 begin_reversible_command (_("reset region gain"));
5194 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5195 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
5197 boost::shared_ptr<AutomationList> alist (arv->audio_region()->envelope());
5198 XMLNode& before (alist->get_state());
5200 arv->audio_region()->set_default_envelope ();
5201 _session->add_command (new MementoCommand<AutomationList>(*arv->audio_region()->envelope().get(), &before, &alist->get_state()));
5205 commit_reversible_command ();
5209 Editor::set_region_gain_visibility (RegionView* rv)
5211 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (rv);
5213 arv->update_envelope_visibility();
5218 Editor::set_gain_envelope_visibility ()
5224 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5225 AudioTimeAxisView* v = dynamic_cast<AudioTimeAxisView*>(*i);
5227 v->audio_view()->foreach_regionview (sigc::mem_fun (this, &Editor::set_region_gain_visibility));
5233 Editor::toggle_gain_envelope_active ()
5235 if (_ignore_region_action) {
5239 RegionSelection rs = get_regions_from_selection_and_entered ();
5241 if (!_session || rs.empty()) {
5245 begin_reversible_command (_("region gain envelope active"));
5247 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5248 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
5250 arv->region()->clear_changes ();
5251 arv->audio_region()->set_envelope_active (!arv->audio_region()->envelope_active());
5252 _session->add_command (new StatefulDiffCommand (arv->region()));
5256 commit_reversible_command ();
5260 Editor::toggle_region_lock ()
5262 if (_ignore_region_action) {
5266 RegionSelection rs = get_regions_from_selection_and_entered ();
5268 if (!_session || rs.empty()) {
5272 begin_reversible_command (_("toggle region lock"));
5274 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5275 (*i)->region()->clear_changes ();
5276 (*i)->region()->set_locked (!(*i)->region()->locked());
5277 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5280 commit_reversible_command ();
5284 Editor::toggle_region_video_lock ()
5286 if (_ignore_region_action) {
5290 RegionSelection rs = get_regions_from_selection_and_entered ();
5292 if (!_session || rs.empty()) {
5296 begin_reversible_command (_("Toggle Video Lock"));
5298 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5299 (*i)->region()->clear_changes ();
5300 (*i)->region()->set_video_locked (!(*i)->region()->video_locked());
5301 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5304 commit_reversible_command ();
5308 Editor::toggle_region_lock_style ()
5310 if (_ignore_region_action) {
5314 RegionSelection rs = get_regions_from_selection_and_entered ();
5316 if (!_session || rs.empty()) {
5320 begin_reversible_command (_("region lock style"));
5322 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5323 (*i)->region()->clear_changes ();
5324 PositionLockStyle const ns = (*i)->region()->position_lock_style() == AudioTime ? MusicTime : AudioTime;
5325 (*i)->region()->set_position_lock_style (ns);
5326 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5329 commit_reversible_command ();
5333 Editor::toggle_opaque_region ()
5335 if (_ignore_region_action) {
5339 RegionSelection rs = get_regions_from_selection_and_entered ();
5341 if (!_session || rs.empty()) {
5345 begin_reversible_command (_("change region opacity"));
5347 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5348 (*i)->region()->clear_changes ();
5349 (*i)->region()->set_opaque (!(*i)->region()->opaque());
5350 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5353 commit_reversible_command ();
5357 Editor::toggle_record_enable ()
5359 bool new_state = false;
5361 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5362 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5365 if (!rtav->is_track())
5369 new_state = !rtav->track()->record_enabled();
5373 rtav->track()->set_record_enabled (new_state, this);
5378 Editor::toggle_solo ()
5380 bool new_state = false;
5382 boost::shared_ptr<RouteList> rl (new RouteList);
5384 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5385 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5392 new_state = !rtav->route()->soloed ();
5396 rl->push_back (rtav->route());
5399 _session->set_solo (rl, new_state, Session::rt_cleanup, true);
5403 Editor::toggle_mute ()
5405 bool new_state = false;
5407 boost::shared_ptr<RouteList> rl (new RouteList);
5409 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5410 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5417 new_state = !rtav->route()->muted();
5421 rl->push_back (rtav->route());
5424 _session->set_mute (rl, new_state, Session::rt_cleanup, true);
5428 Editor::toggle_solo_isolate ()
5434 Editor::fade_range ()
5436 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
5438 begin_reversible_command (_("fade range"));
5440 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
5441 (*i)->fade_range (selection->time);
5444 commit_reversible_command ();
5449 Editor::set_fade_length (bool in)
5451 RegionSelection rs = get_regions_from_selection_and_entered ();
5457 /* we need a region to measure the offset from the start */
5459 RegionView* rv = rs.front ();
5461 framepos_t pos = get_preferred_edit_position();
5465 if (pos > rv->region()->last_frame() || pos < rv->region()->first_frame()) {
5466 /* edit point is outside the relevant region */
5471 if (pos <= rv->region()->position()) {
5475 len = pos - rv->region()->position();
5476 cmd = _("set fade in length");
5478 if (pos >= rv->region()->last_frame()) {
5482 len = rv->region()->last_frame() - pos;
5483 cmd = _("set fade out length");
5486 begin_reversible_command (cmd);
5488 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5489 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5495 boost::shared_ptr<AutomationList> alist;
5497 alist = tmp->audio_region()->fade_in();
5499 alist = tmp->audio_region()->fade_out();
5502 XMLNode &before = alist->get_state();
5505 tmp->audio_region()->set_fade_in_length (len);
5506 tmp->audio_region()->set_fade_in_active (true);
5508 tmp->audio_region()->set_fade_out_length (len);
5509 tmp->audio_region()->set_fade_out_active (true);
5512 XMLNode &after = alist->get_state();
5513 _session->add_command(new MementoCommand<AutomationList>(*alist, &before, &after));
5516 commit_reversible_command ();
5520 Editor::set_fade_in_shape (FadeShape shape)
5522 RegionSelection rs = get_regions_from_selection_and_entered ();
5528 begin_reversible_command (_("set fade in shape"));
5530 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5531 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5537 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_in();
5538 XMLNode &before = alist->get_state();
5540 tmp->audio_region()->set_fade_in_shape (shape);
5542 XMLNode &after = alist->get_state();
5543 _session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
5546 commit_reversible_command ();
5551 Editor::set_fade_out_shape (FadeShape shape)
5553 RegionSelection rs = get_regions_from_selection_and_entered ();
5559 begin_reversible_command (_("set fade out shape"));
5561 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5562 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5568 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_out();
5569 XMLNode &before = alist->get_state();
5571 tmp->audio_region()->set_fade_out_shape (shape);
5573 XMLNode &after = alist->get_state();
5574 _session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
5577 commit_reversible_command ();
5581 Editor::set_fade_in_active (bool yn)
5583 RegionSelection rs = get_regions_from_selection_and_entered ();
5589 begin_reversible_command (_("set fade in active"));
5591 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5592 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5599 boost::shared_ptr<AudioRegion> ar (tmp->audio_region());
5601 ar->clear_changes ();
5602 ar->set_fade_in_active (yn);
5603 _session->add_command (new StatefulDiffCommand (ar));
5606 commit_reversible_command ();
5610 Editor::set_fade_out_active (bool yn)
5612 RegionSelection rs = get_regions_from_selection_and_entered ();
5618 begin_reversible_command (_("set fade out active"));
5620 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5621 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5627 boost::shared_ptr<AudioRegion> ar (tmp->audio_region());
5629 ar->clear_changes ();
5630 ar->set_fade_out_active (yn);
5631 _session->add_command(new StatefulDiffCommand (ar));
5634 commit_reversible_command ();
5638 Editor::toggle_region_fades (int dir)
5640 if (_ignore_region_action) {
5644 boost::shared_ptr<AudioRegion> ar;
5647 RegionSelection rs = get_regions_from_selection_and_entered ();
5653 RegionSelection::iterator i;
5654 for (i = rs.begin(); i != rs.end(); ++i) {
5655 if ((ar = boost::dynamic_pointer_cast<AudioRegion>((*i)->region())) != 0) {
5657 yn = ar->fade_out_active ();
5659 yn = ar->fade_in_active ();
5665 if (i == rs.end()) {
5669 /* XXX should this undo-able? */
5671 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5672 if ((ar = boost::dynamic_pointer_cast<AudioRegion>((*i)->region())) == 0) {
5675 if (dir == 1 || dir == 0) {
5676 ar->set_fade_in_active (!yn);
5679 if (dir == -1 || dir == 0) {
5680 ar->set_fade_out_active (!yn);
5686 /** Update region fade visibility after its configuration has been changed */
5688 Editor::update_region_fade_visibility ()
5690 bool _fade_visibility = _session->config.get_show_region_fades ();
5692 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5693 AudioTimeAxisView* v = dynamic_cast<AudioTimeAxisView*>(*i);
5695 if (_fade_visibility) {
5696 v->audio_view()->show_all_fades ();
5698 v->audio_view()->hide_all_fades ();
5705 Editor::set_edit_point ()
5710 if (!mouse_frame (where, ignored)) {
5716 if (selection->markers.empty()) {
5718 mouse_add_new_marker (where);
5723 Location* loc = find_location_from_marker (selection->markers.front(), ignored);
5726 loc->move_to (where);
5732 Editor::set_playhead_cursor ()
5734 if (entered_marker) {
5735 _session->request_locate (entered_marker->position(), _session->transport_rolling());
5740 if (!mouse_frame (where, ignored)) {
5747 _session->request_locate (where, _session->transport_rolling());
5751 if ( Config->get_follow_edits() )
5752 cancel_time_selection();
5756 Editor::split_region ()
5758 if ( !selection->time.empty()) {
5759 separate_regions_between (selection->time);
5763 RegionSelection rs = get_regions_from_selection_and_edit_point ();
5765 framepos_t where = get_preferred_edit_position ();
5771 split_regions_at (where, rs);
5774 struct EditorOrderRouteSorter {
5775 bool operator() (boost::shared_ptr<Route> a, boost::shared_ptr<Route> b) {
5776 return a->order_key () < b->order_key ();
5781 Editor::select_next_route()
5783 if (selection->tracks.empty()) {
5784 selection->set (track_views.front());
5788 TimeAxisView* current = selection->tracks.front();
5792 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5793 if (*i == current) {
5795 if (i != track_views.end()) {
5798 current = (*(track_views.begin()));
5799 //selection->set (*(track_views.begin()));
5804 rui = dynamic_cast<RouteUI *>(current);
5805 } while ( current->hidden() || (rui != NULL && !rui->route()->active()));
5807 selection->set(current);
5809 ensure_time_axis_view_is_visible (*current, false);
5813 Editor::select_prev_route()
5815 if (selection->tracks.empty()) {
5816 selection->set (track_views.front());
5820 TimeAxisView* current = selection->tracks.front();
5824 for (TrackViewList::reverse_iterator i = track_views.rbegin(); i != track_views.rend(); ++i) {
5825 if (*i == current) {
5827 if (i != track_views.rend()) {
5830 current = *(track_views.rbegin());
5835 rui = dynamic_cast<RouteUI *>(current);
5836 } while ( current->hidden() || (rui != NULL && !rui->route()->active()));
5838 selection->set (current);
5840 ensure_time_axis_view_is_visible (*current, false);
5844 Editor::set_loop_from_selection (bool play)
5846 if (_session == 0 || selection->time.empty()) {
5850 framepos_t start = selection->time[clicked_selection].start;
5851 framepos_t end = selection->time[clicked_selection].end;
5853 set_loop_range (start, end, _("set loop range from selection"));
5856 _session->request_locate (start, true);
5857 _session->request_play_loop (true);
5862 Editor::set_loop_from_edit_range (bool play)
5864 if (_session == 0) {
5871 if (!get_edit_op_range (start, end)) {
5875 set_loop_range (start, end, _("set loop range from edit range"));
5878 _session->request_locate (start, true);
5879 _session->request_play_loop (true);
5884 Editor::set_loop_from_region (bool play)
5886 framepos_t start = max_framepos;
5889 RegionSelection rs = get_regions_from_selection_and_entered ();
5895 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5896 if ((*i)->region()->position() < start) {
5897 start = (*i)->region()->position();
5899 if ((*i)->region()->last_frame() + 1 > end) {
5900 end = (*i)->region()->last_frame() + 1;
5904 set_loop_range (start, end, _("set loop range from region"));
5907 _session->request_locate (start, true);
5908 _session->request_play_loop (true);
5913 Editor::set_punch_from_selection ()
5915 if (_session == 0 || selection->time.empty()) {
5919 framepos_t start = selection->time[clicked_selection].start;
5920 framepos_t end = selection->time[clicked_selection].end;
5922 set_punch_range (start, end, _("set punch range from selection"));
5926 Editor::set_session_extents_from_selection ()
5928 if (_session == 0 || selection->time.empty()) {
5932 begin_reversible_command (_("set session start/stop from selection"));
5934 framepos_t start = selection->time[clicked_selection].start;
5935 framepos_t end = selection->time[clicked_selection].end;
5938 if ((loc = _session->locations()->session_range_location()) == 0) {
5939 _session->set_session_extents ( start, end ); // this will create a new session range; no need for UNDO
5941 XMLNode &before = loc->get_state();
5943 _session->set_session_extents ( start, end );
5945 XMLNode &after = loc->get_state();
5947 _session->add_command (new MementoCommand<Location>(*loc, &before, &after));
5949 commit_reversible_command ();
5954 Editor::set_punch_from_edit_range ()
5956 if (_session == 0) {
5963 if (!get_edit_op_range (start, end)) {
5967 set_punch_range (start, end, _("set punch range from edit range"));
5971 Editor::set_punch_from_region ()
5973 framepos_t start = max_framepos;
5976 RegionSelection rs = get_regions_from_selection_and_entered ();
5982 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5983 if ((*i)->region()->position() < start) {
5984 start = (*i)->region()->position();
5986 if ((*i)->region()->last_frame() + 1 > end) {
5987 end = (*i)->region()->last_frame() + 1;
5991 set_punch_range (start, end, _("set punch range from region"));
5995 Editor::pitch_shift_region ()
5997 RegionSelection rs = get_regions_from_selection_and_entered ();
5999 RegionSelection audio_rs;
6000 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
6001 if (dynamic_cast<AudioRegionView*> (*i)) {
6002 audio_rs.push_back (*i);
6006 if (audio_rs.empty()) {
6010 pitch_shift (audio_rs, 1.2);
6014 Editor::transpose_region ()
6016 RegionSelection rs = get_regions_from_selection_and_entered ();
6018 list<MidiRegionView*> midi_region_views;
6019 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
6020 MidiRegionView* mrv = dynamic_cast<MidiRegionView*> (*i);
6022 midi_region_views.push_back (mrv);
6027 int const r = d.run ();
6028 if (r != RESPONSE_ACCEPT) {
6032 for (list<MidiRegionView*>::iterator i = midi_region_views.begin(); i != midi_region_views.end(); ++i) {
6033 (*i)->midi_region()->transpose (d.semitones ());
6038 Editor::set_tempo_from_region ()
6040 RegionSelection rs = get_regions_from_selection_and_entered ();
6042 if (!_session || rs.empty()) {
6046 RegionView* rv = rs.front();
6048 define_one_bar (rv->region()->position(), rv->region()->last_frame() + 1);
6052 Editor::use_range_as_bar ()
6054 framepos_t start, end;
6055 if (get_edit_op_range (start, end)) {
6056 define_one_bar (start, end);
6061 Editor::define_one_bar (framepos_t start, framepos_t end)
6063 framepos_t length = end - start;
6065 const Meter& m (_session->tempo_map().meter_at (start));
6067 /* length = 1 bar */
6069 /* now we want frames per beat.
6070 we have frames per bar, and beats per bar, so ...
6073 /* XXXX METER MATH */
6075 double frames_per_beat = length / m.divisions_per_bar();
6077 /* beats per minute = */
6079 double beats_per_minute = (_session->frame_rate() * 60.0) / frames_per_beat;
6081 /* now decide whether to:
6083 (a) set global tempo
6084 (b) add a new tempo marker
6088 const TempoSection& t (_session->tempo_map().tempo_section_at (start));
6090 bool do_global = false;
6092 if ((_session->tempo_map().n_tempos() == 1) && (_session->tempo_map().n_meters() == 1)) {
6094 /* only 1 tempo & 1 meter: ask if the user wants to set the tempo
6095 at the start, or create a new marker
6098 vector<string> options;
6099 options.push_back (_("Cancel"));
6100 options.push_back (_("Add new marker"));
6101 options.push_back (_("Set global tempo"));
6104 _("Define one bar"),
6105 _("Do you want to set the global tempo or add a new tempo marker?"),
6109 c.set_default_response (2);
6125 /* more than 1 tempo and/or meter section already, go ahead do the "usual":
6126 if the marker is at the region starter, change it, otherwise add
6131 begin_reversible_command (_("set tempo from region"));
6132 XMLNode& before (_session->tempo_map().get_state());
6135 _session->tempo_map().change_initial_tempo (beats_per_minute, t.note_type());
6136 } else if (t.frame() == start) {
6137 _session->tempo_map().change_existing_tempo_at (start, beats_per_minute, t.note_type());
6139 Timecode::BBT_Time bbt;
6140 _session->tempo_map().bbt_time (start, bbt);
6141 _session->tempo_map().add_tempo (Tempo (beats_per_minute, t.note_type()), bbt);
6144 XMLNode& after (_session->tempo_map().get_state());
6146 _session->add_command (new MementoCommand<TempoMap>(_session->tempo_map(), &before, &after));
6147 commit_reversible_command ();
6151 Editor::split_region_at_transients ()
6153 AnalysisFeatureList positions;
6155 RegionSelection rs = get_regions_from_selection_and_entered ();
6157 if (!_session || rs.empty()) {
6161 begin_reversible_command (_("split regions"));
6163 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ) {
6165 RegionSelection::iterator tmp;
6170 boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion> ((*i)->region());
6172 if (ar && (ar->get_transients (positions) == 0)) {
6173 split_region_at_points ((*i)->region(), positions, true);
6180 commit_reversible_command ();
6185 Editor::split_region_at_points (boost::shared_ptr<Region> r, AnalysisFeatureList& positions, bool can_ferret, bool select_new)
6187 bool use_rhythmic_rodent = false;
6189 boost::shared_ptr<Playlist> pl = r->playlist();
6191 list<boost::shared_ptr<Region> > new_regions;
6197 if (positions.empty()) {
6202 if (positions.size() > 20 && can_ferret) {
6203 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);
6204 MessageDialog msg (msgstr,
6207 Gtk::BUTTONS_OK_CANCEL);
6210 msg.add_button (_("Call for the Ferret!"), RESPONSE_APPLY);
6211 msg.set_secondary_text (_("Press OK to continue with this split operation\nor ask the Ferret dialog to tune the analysis"));
6213 msg.set_secondary_text (_("Press OK to continue with this split operation"));
6216 msg.set_title (_("Excessive split?"));
6219 int response = msg.run();
6225 case RESPONSE_APPLY:
6226 use_rhythmic_rodent = true;
6233 if (use_rhythmic_rodent) {
6234 show_rhythm_ferret ();
6238 AnalysisFeatureList::const_iterator x;
6240 pl->clear_changes ();
6241 pl->clear_owned_changes ();
6243 x = positions.begin();
6245 if (x == positions.end()) {
6250 pl->remove_region (r);
6254 while (x != positions.end()) {
6256 /* deal with positons that are out of scope of present region bounds */
6257 if (*x <= 0 || *x > r->length()) {
6262 /* file start = original start + how far we from the initial position ?
6265 framepos_t file_start = r->start() + pos;
6267 /* length = next position - current position
6270 framepos_t len = (*x) - pos;
6272 /* XXX we do we really want to allow even single-sample regions?
6273 shouldn't we have some kind of lower limit on region size?
6282 if (RegionFactory::region_name (new_name, r->name())) {
6286 /* do NOT announce new regions 1 by one, just wait till they are all done */
6290 plist.add (ARDOUR::Properties::start, file_start);
6291 plist.add (ARDOUR::Properties::length, len);
6292 plist.add (ARDOUR::Properties::name, new_name);
6293 plist.add (ARDOUR::Properties::layer, 0);
6295 boost::shared_ptr<Region> nr = RegionFactory::create (r->sources(), plist, false);
6296 /* because we set annouce to false, manually add the new region to the
6299 RegionFactory::map_add (nr);
6301 pl->add_region (nr, r->position() + pos);
6304 new_regions.push_front(nr);
6313 RegionFactory::region_name (new_name, r->name());
6315 /* Add the final region */
6318 plist.add (ARDOUR::Properties::start, r->start() + pos);
6319 plist.add (ARDOUR::Properties::length, r->last_frame() - (r->position() + pos) + 1);
6320 plist.add (ARDOUR::Properties::name, new_name);
6321 plist.add (ARDOUR::Properties::layer, 0);
6323 boost::shared_ptr<Region> nr = RegionFactory::create (r->sources(), plist, false);
6324 /* because we set annouce to false, manually add the new region to the
6327 RegionFactory::map_add (nr);
6328 pl->add_region (nr, r->position() + pos);
6331 new_regions.push_front(nr);
6336 /* We might have removed regions, which alters other regions' layering_index,
6337 so we need to do a recursive diff here.
6339 vector<Command*> cmds;
6341 _session->add_commands (cmds);
6343 _session->add_command (new StatefulDiffCommand (pl));
6347 for (list<boost::shared_ptr<Region> >::iterator i = new_regions.begin(); i != new_regions.end(); ++i){
6348 set_selected_regionview_from_region_list ((*i), Selection::Add);
6354 Editor::place_transient()
6360 RegionSelection rs = get_regions_from_selection_and_edit_point ();
6366 framepos_t where = get_preferred_edit_position();
6368 begin_reversible_command (_("place transient"));
6370 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6371 framepos_t position = (*r)->region()->position();
6372 (*r)->region()->add_transient(where - position);
6375 commit_reversible_command ();
6379 Editor::remove_transient(ArdourCanvas::Item* item)
6385 ArdourCanvas::Line* _line = reinterpret_cast<ArdourCanvas::Line*> (item);
6388 AudioRegionView* _arv = reinterpret_cast<AudioRegionView*> (item->get_data ("regionview"));
6389 _arv->remove_transient (*(float*) _line->get_data ("position"));
6393 Editor::snap_regions_to_grid ()
6395 list <boost::shared_ptr<Playlist > > used_playlists;
6397 RegionSelection rs = get_regions_from_selection_and_entered ();
6399 if (!_session || rs.empty()) {
6403 begin_reversible_command (_("snap regions to grid"));
6405 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6407 boost::shared_ptr<Playlist> pl = (*r)->region()->playlist();
6409 if (!pl->frozen()) {
6410 /* we haven't seen this playlist before */
6412 /* remember used playlists so we can thaw them later */
6413 used_playlists.push_back(pl);
6417 framepos_t start_frame = (*r)->region()->first_frame ();
6418 snap_to (start_frame);
6419 (*r)->region()->set_position (start_frame);
6422 while (used_playlists.size() > 0) {
6423 list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
6425 used_playlists.pop_front();
6428 commit_reversible_command ();
6432 Editor::close_region_gaps ()
6434 list <boost::shared_ptr<Playlist > > used_playlists;
6436 RegionSelection rs = get_regions_from_selection_and_entered ();
6438 if (!_session || rs.empty()) {
6442 Dialog dialog (_("Close Region Gaps"));
6445 table.set_spacings (12);
6446 table.set_border_width (12);
6447 Label* l = manage (left_aligned_label (_("Crossfade length")));
6448 table.attach (*l, 0, 1, 0, 1);
6450 SpinButton spin_crossfade (1, 0);
6451 spin_crossfade.set_range (0, 15);
6452 spin_crossfade.set_increments (1, 1);
6453 spin_crossfade.set_value (5);
6454 table.attach (spin_crossfade, 1, 2, 0, 1);
6456 table.attach (*manage (new Label (_("ms"))), 2, 3, 0, 1);
6458 l = manage (left_aligned_label (_("Pull-back length")));
6459 table.attach (*l, 0, 1, 1, 2);
6461 SpinButton spin_pullback (1, 0);
6462 spin_pullback.set_range (0, 100);
6463 spin_pullback.set_increments (1, 1);
6464 spin_pullback.set_value(30);
6465 table.attach (spin_pullback, 1, 2, 1, 2);
6467 table.attach (*manage (new Label (_("ms"))), 2, 3, 1, 2);
6469 dialog.get_vbox()->pack_start (table);
6470 dialog.add_button (Stock::CANCEL, RESPONSE_CANCEL);
6471 dialog.add_button (_("Ok"), RESPONSE_ACCEPT);
6474 if (dialog.run () == RESPONSE_CANCEL) {
6478 framepos_t crossfade_len = spin_crossfade.get_value();
6479 framepos_t pull_back_frames = spin_pullback.get_value();
6481 crossfade_len = lrintf (crossfade_len * _session->frame_rate()/1000);
6482 pull_back_frames = lrintf (pull_back_frames * _session->frame_rate()/1000);
6484 /* Iterate over the region list and make adjacent regions overlap by crossfade_len_ms */
6486 begin_reversible_command (_("close region gaps"));
6489 boost::shared_ptr<Region> last_region;
6491 rs.sort_by_position_and_track();
6493 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6495 boost::shared_ptr<Playlist> pl = (*r)->region()->playlist();
6497 if (!pl->frozen()) {
6498 /* we haven't seen this playlist before */
6500 /* remember used playlists so we can thaw them later */
6501 used_playlists.push_back(pl);
6505 framepos_t position = (*r)->region()->position();
6507 if (idx == 0 || position < last_region->position()){
6508 last_region = (*r)->region();
6513 (*r)->region()->trim_front( (position - pull_back_frames));
6514 last_region->trim_end( (position - pull_back_frames + crossfade_len));
6516 last_region = (*r)->region();
6521 while (used_playlists.size() > 0) {
6522 list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
6524 used_playlists.pop_front();
6527 commit_reversible_command ();
6531 Editor::tab_to_transient (bool forward)
6533 AnalysisFeatureList positions;
6535 RegionSelection rs = get_regions_from_selection_and_entered ();
6541 framepos_t pos = _session->audible_frame ();
6543 if (!selection->tracks.empty()) {
6545 /* don't waste time searching for transients in duplicate playlists.
6548 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
6550 for (TrackViewList::iterator t = ts.begin(); t != ts.end(); ++t) {
6552 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*t);
6555 boost::shared_ptr<Track> tr = rtv->track();
6557 boost::shared_ptr<Playlist> pl = tr->playlist ();
6559 framepos_t result = pl->find_next_transient (pos, forward ? 1 : -1);
6562 positions.push_back (result);
6575 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6576 (*r)->region()->get_transients (positions);
6580 TransientDetector::cleanup_transients (positions, _session->frame_rate(), 3.0);
6583 AnalysisFeatureList::iterator x;
6585 for (x = positions.begin(); x != positions.end(); ++x) {
6591 if (x != positions.end ()) {
6592 _session->request_locate (*x);
6596 AnalysisFeatureList::reverse_iterator x;
6598 for (x = positions.rbegin(); x != positions.rend(); ++x) {
6604 if (x != positions.rend ()) {
6605 _session->request_locate (*x);
6611 Editor::playhead_forward_to_grid ()
6617 framepos_t pos = playhead_cursor->current_frame ();
6618 if (pos < max_framepos - 1) {
6620 snap_to_internal (pos, RoundUpAlways, false);
6621 _session->request_locate (pos);
6627 Editor::playhead_backward_to_grid ()
6633 framepos_t pos = playhead_cursor->current_frame ();
6636 snap_to_internal (pos, RoundDownAlways, false);
6637 _session->request_locate (pos);
6642 Editor::set_track_height (Height h)
6644 TrackSelection& ts (selection->tracks);
6646 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
6647 (*x)->set_height_enum (h);
6652 Editor::toggle_tracks_active ()
6654 TrackSelection& ts (selection->tracks);
6656 bool target = false;
6662 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
6663 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*x);
6667 target = !rtv->_route->active();
6670 rtv->_route->set_active (target, this);
6676 Editor::remove_tracks ()
6678 TrackSelection& ts (selection->tracks);
6684 vector<string> choices;
6688 const char* trackstr;
6690 vector<boost::shared_ptr<Route> > routes;
6691 bool special_bus = false;
6693 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
6694 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*x);
6698 if (rtv->is_track()) {
6703 routes.push_back (rtv->_route);
6705 if (rtv->route()->is_master() || rtv->route()->is_monitor()) {
6710 if (special_bus && !Config->get_allow_special_bus_removal()) {
6711 MessageDialog msg (_("That would be bad news ...."),
6715 msg.set_secondary_text (string_compose (_(
6716 "Removing the master or monitor bus is such a bad idea\n\
6717 that %1 is not going to allow it.\n\
6719 If you really want to do this sort of thing\n\
6720 edit your ardour.rc file to set the\n\
6721 \"allow-special-bus-removal\" option to be \"yes\""), PROGRAM_NAME));
6728 if (ntracks + nbusses == 0) {
6732 // XXX should be using gettext plural forms, maybe?
6734 trackstr = _("tracks");
6736 trackstr = _("track");
6740 busstr = _("busses");
6747 prompt = string_compose (_("Do you really want to remove %1 %2 and %3 %4?\n"
6748 "(You may also lose the playlists associated with the %2)\n\n"
6749 "This action cannot be undone, and the session file will be overwritten!"),
6750 ntracks, trackstr, nbusses, busstr);
6752 prompt = string_compose (_("Do you really want to remove %1 %2?\n"
6753 "(You may also lose the playlists associated with the %2)\n\n"
6754 "This action cannot be undone, and the session file will be overwritten!"),
6757 } else if (nbusses) {
6758 prompt = string_compose (_("Do you really want to remove %1 %2?\n\n"
6759 "This action cannot be undone, and the session file will be overwritten"),
6763 choices.push_back (_("No, do nothing."));
6764 if (ntracks + nbusses > 1) {
6765 choices.push_back (_("Yes, remove them."));
6767 choices.push_back (_("Yes, remove it."));
6772 title = string_compose (_("Remove %1"), trackstr);
6774 title = string_compose (_("Remove %1"), busstr);
6777 Choice prompter (title, prompt, choices);
6779 if (prompter.run () != 1) {
6784 Session::StateProtector sp (_session);
6785 DisplaySuspender ds;
6786 for (vector<boost::shared_ptr<Route> >::iterator x = routes.begin(); x != routes.end(); ++x) {
6787 _session->remove_route (*x);
6793 Editor::do_insert_time ()
6795 if (selection->tracks.empty()) {
6799 InsertTimeDialog d (*this);
6800 int response = d.run ();
6802 if (response != RESPONSE_OK) {
6806 if (d.distance() == 0) {
6810 InsertTimeOption opt = d.intersected_region_action ();
6813 get_preferred_edit_position(),
6819 d.move_glued_markers(),
6820 d.move_locked_markers(),
6826 Editor::insert_time (
6827 framepos_t pos, framecnt_t frames, InsertTimeOption opt,
6828 bool all_playlists, bool ignore_music_glue, bool markers_too, bool glued_markers_too, bool locked_markers_too, bool tempo_too
6831 bool commit = false;
6833 if (Config->get_edit_mode() == Lock) {
6837 begin_reversible_command (_("insert time"));
6839 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
6841 for (TrackViewList::iterator x = ts.begin(); x != ts.end(); ++x) {
6845 /* don't operate on any playlist more than once, which could
6846 * happen if "all playlists" is enabled, but there is more
6847 * than 1 track using playlists "from" a given track.
6850 set<boost::shared_ptr<Playlist> > pl;
6852 if (all_playlists) {
6853 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*x);
6855 vector<boost::shared_ptr<Playlist> > all = _session->playlists->playlists_for_track (rtav->track ());
6856 for (vector<boost::shared_ptr<Playlist> >::iterator p = all.begin(); p != all.end(); ++p) {
6861 if ((*x)->playlist ()) {
6862 pl.insert ((*x)->playlist ());
6866 for (set<boost::shared_ptr<Playlist> >::iterator i = pl.begin(); i != pl.end(); ++i) {
6868 (*i)->clear_changes ();
6869 (*i)->clear_owned_changes ();
6871 if (opt == SplitIntersected) {
6875 (*i)->shift (pos, frames, (opt == MoveIntersected), ignore_music_glue);
6877 vector<Command*> cmds;
6879 _session->add_commands (cmds);
6881 _session->add_command (new StatefulDiffCommand (*i));
6886 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*x);
6888 rtav->route ()->shift (pos, frames);
6896 XMLNode& before (_session->locations()->get_state());
6897 Locations::LocationList copy (_session->locations()->list());
6899 for (Locations::LocationList::iterator i = copy.begin(); i != copy.end(); ++i) {
6901 Locations::LocationList::const_iterator tmp;
6903 bool const was_locked = (*i)->locked ();
6904 if (locked_markers_too) {
6908 if ((*i)->position_lock_style() == AudioTime || glued_markers_too) {
6910 if ((*i)->start() >= pos) {
6911 (*i)->set_start ((*i)->start() + frames);
6912 if (!(*i)->is_mark()) {
6913 (*i)->set_end ((*i)->end() + frames);
6926 XMLNode& after (_session->locations()->get_state());
6927 _session->add_command (new MementoCommand<Locations>(*_session->locations(), &before, &after));
6932 _session->tempo_map().insert_time (pos, frames);
6936 commit_reversible_command ();
6941 Editor::fit_selected_tracks ()
6943 if (!selection->tracks.empty()) {
6944 fit_tracks (selection->tracks);
6948 /* no selected tracks - use tracks with selected regions */
6950 if (!selection->regions.empty()) {
6951 for (RegionSelection::iterator r = selection->regions.begin(); r != selection->regions.end(); ++r) {
6952 tvl.push_back (&(*r)->get_time_axis_view ());
6958 } else if (internal_editing()) {
6959 /* no selected tracks, or regions, but in internal edit mode, so follow the mouse and use
6962 if (entered_track) {
6963 tvl.push_back (entered_track);
6972 Editor::fit_tracks (TrackViewList & tracks)
6974 if (tracks.empty()) {
6978 uint32_t child_heights = 0;
6979 int visible_tracks = 0;
6981 for (TrackSelection::iterator t = tracks.begin(); t != tracks.end(); ++t) {
6983 if (!(*t)->marked_for_display()) {
6987 child_heights += (*t)->effective_height() - (*t)->current_height();
6991 /* compute the per-track height from:
6993 total canvas visible height -
6994 height that will be taken by visible children of selected
6995 tracks - height of the ruler/hscroll area
6997 uint32_t h = (uint32_t) floor ((trackviews_height() - child_heights) / visible_tracks);
6998 double first_y_pos = DBL_MAX;
7000 if (h < TimeAxisView::preset_height (HeightSmall)) {
7001 MessageDialog msg (*this, _("There are too many tracks to fit in the current window"));
7002 /* too small to be displayed */
7006 undo_visual_stack.push_back (current_visual_state (true));
7007 no_save_visual = true;
7009 /* build a list of all tracks, including children */
7012 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
7014 TimeAxisView::Children c = (*i)->get_child_list ();
7015 for (TimeAxisView::Children::iterator j = c.begin(); j != c.end(); ++j) {
7016 all.push_back (j->get());
7020 bool prev_was_selected = false;
7021 bool is_selected = tracks.contains (all.front());
7022 bool next_is_selected;
7024 for (TrackViewList::iterator t = all.begin(); t != all.end(); ++t) {
7026 TrackViewList::iterator next;
7031 if (next != all.end()) {
7032 next_is_selected = tracks.contains (*next);
7034 next_is_selected = false;
7037 if ((*t)->marked_for_display ()) {
7039 (*t)->set_height (h);
7040 first_y_pos = std::min ((*t)->y_position (), first_y_pos);
7042 if (prev_was_selected && next_is_selected) {
7043 hide_track_in_display (*t);
7048 prev_was_selected = is_selected;
7049 is_selected = next_is_selected;
7053 set the controls_layout height now, because waiting for its size
7054 request signal handler will cause the vertical adjustment setting to fail
7057 controls_layout.property_height () = _full_canvas_height;
7058 vertical_adjustment.set_value (first_y_pos);
7060 redo_visual_stack.push_back (current_visual_state (true));
7062 visible_tracks_selector.set_text (_("Sel"));
7066 Editor::save_visual_state (uint32_t n)
7068 while (visual_states.size() <= n) {
7069 visual_states.push_back (0);
7072 if (visual_states[n] != 0) {
7073 delete visual_states[n];
7076 visual_states[n] = current_visual_state (true);
7081 Editor::goto_visual_state (uint32_t n)
7083 if (visual_states.size() <= n) {
7087 if (visual_states[n] == 0) {
7091 use_visual_state (*visual_states[n]);
7095 Editor::start_visual_state_op (uint32_t n)
7097 save_visual_state (n);
7099 PopUp* pup = new PopUp (WIN_POS_MOUSE, 1000, true);
7101 snprintf (buf, sizeof (buf), _("Saved view %u"), n+1);
7102 pup->set_text (buf);
7107 Editor::cancel_visual_state_op (uint32_t n)
7109 goto_visual_state (n);
7113 Editor::toggle_region_mute ()
7115 if (_ignore_region_action) {
7119 RegionSelection rs = get_regions_from_selection_and_entered ();
7125 if (rs.size() > 1) {
7126 begin_reversible_command (_("mute regions"));
7128 begin_reversible_command (_("mute region"));
7131 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
7133 (*i)->region()->playlist()->clear_changes ();
7134 (*i)->region()->set_muted (!(*i)->region()->muted ());
7135 _session->add_command (new StatefulDiffCommand ((*i)->region()));
7139 commit_reversible_command ();
7143 Editor::combine_regions ()
7145 /* foreach track with selected regions, take all selected regions
7146 and join them into a new region containing the subregions (as a
7150 typedef set<RouteTimeAxisView*> RTVS;
7153 if (selection->regions.empty()) {
7157 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
7158 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(&(*i)->get_time_axis_view());
7161 tracks.insert (rtv);
7165 begin_reversible_command (_("combine regions"));
7167 vector<RegionView*> new_selection;
7169 for (RTVS::iterator i = tracks.begin(); i != tracks.end(); ++i) {
7172 if ((rv = (*i)->combine_regions ()) != 0) {
7173 new_selection.push_back (rv);
7177 selection->clear_regions ();
7178 for (vector<RegionView*>::iterator i = new_selection.begin(); i != new_selection.end(); ++i) {
7179 selection->add (*i);
7182 commit_reversible_command ();
7186 Editor::uncombine_regions ()
7188 typedef set<RouteTimeAxisView*> RTVS;
7191 if (selection->regions.empty()) {
7195 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
7196 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(&(*i)->get_time_axis_view());
7199 tracks.insert (rtv);
7203 begin_reversible_command (_("uncombine regions"));
7205 for (RTVS::iterator i = tracks.begin(); i != tracks.end(); ++i) {
7206 (*i)->uncombine_regions ();
7209 commit_reversible_command ();
7213 Editor::toggle_midi_input_active (bool flip_others)
7216 boost::shared_ptr<RouteList> rl (new RouteList);
7218 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
7219 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
7225 boost::shared_ptr<MidiTrack> mt = rtav->midi_track();
7228 rl->push_back (rtav->route());
7229 onoff = !mt->input_active();
7233 _session->set_exclusive_input_active (rl, onoff, flip_others);
7240 lock_dialog = new Gtk::Dialog (string_compose (_("%1: Locked"), PROGRAM_NAME), true);
7242 Gtk::Image* padlock = manage (new Gtk::Image (ARDOUR_UI_UTILS::get_icon ("padlock_closed")));
7243 lock_dialog->get_vbox()->pack_start (*padlock);
7245 ArdourButton* b = manage (new ArdourButton);
7246 b->set_name ("lock button");
7247 b->set_text (_("Click to unlock"));
7248 b->signal_clicked.connect (sigc::mem_fun (*this, &Editor::unlock));
7249 lock_dialog->get_vbox()->pack_start (*b);
7251 lock_dialog->get_vbox()->show_all ();
7252 lock_dialog->set_size_request (200, 200);
7256 /* The global menu bar continues to be accessible to applications
7257 with modal dialogs, which means that we need to desensitize
7258 all items in the menu bar. Since those items are really just
7259 proxies for actions, that means disabling all actions.
7261 ActionManager::disable_all_actions ();
7263 lock_dialog->present ();
7269 lock_dialog->hide ();
7272 ActionManager::pop_action_state ();
7275 if (ARDOUR_UI::config()->get_lock_gui_after_seconds()) {
7276 start_lock_event_timing ();
7281 Editor::bring_in_callback (Gtk::Label* label, uint32_t n, uint32_t total, string name)
7283 Gtkmm2ext::UI::instance()->call_slot (invalidator (*this), boost::bind (&Editor::update_bring_in_message, this, label, n, total, name));
7287 Editor::update_bring_in_message (Gtk::Label* label, uint32_t n, uint32_t total, string name)
7289 label->set_text (string_compose ("Copying %1, %2 of %3", name, n, total));
7290 Gtkmm2ext::UI::instance()->flush_pending ();
7294 Editor::bring_all_sources_into_session ()
7301 ArdourDialog w (_("Moving embedded files into session folder"));
7302 w.get_vbox()->pack_start (msg);
7305 /* flush all pending GUI events because we're about to start copying
7309 Gtkmm2ext::UI::instance()->flush_pending ();
7313 _session->bring_all_sources_into_session (boost::bind (&Editor::bring_in_callback, this, &msg, _1, _2, _3));