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 switch (mouse_mode) {
3859 begin_reversible_command (opname + ' ' + X_("MIDI"));
3861 commit_reversible_command ();
3867 bool did_edit = false;
3869 if (!selection->regions.empty() || !selection->points.empty()) {
3870 begin_reversible_command (opname + ' ' + _("objects"));
3873 if (!selection->regions.empty()) {
3874 cut_copy_regions (op, selection->regions);
3876 if (op == Cut || op == Delete) {
3877 selection->clear_regions ();
3881 if (!selection->points.empty()) {
3882 cut_copy_points (op);
3884 if (op == Cut || op == Delete) {
3885 selection->clear_points ();
3888 } else if (selection->time.empty()) {
3889 framepos_t start, end;
3890 /* no time selection, see if we can get an edit range
3893 if (get_edit_op_range (start, end)) {
3894 selection->set (start, end);
3896 } else if (!selection->time.empty()) {
3897 begin_reversible_command (opname + ' ' + _("range"));
3900 cut_copy_ranges (op);
3902 if (op == Cut || op == Delete) {
3903 selection->clear_time ();
3908 /* reset repeated paste state */
3911 commit_reversible_command ();
3914 if (op == Delete || op == Cut || op == Clear) {
3919 struct AutomationRecord {
3920 AutomationRecord () : state (0) , line(NULL) {}
3921 AutomationRecord (XMLNode* s, const AutomationLine* l) : state (s) , line (l) {}
3923 XMLNode* state; ///< state before any operation
3924 const AutomationLine* line; ///< line this came from
3925 boost::shared_ptr<Evoral::ControlList> copy; ///< copied events for the cut buffer
3928 /** Cut, copy or clear selected automation points.
3929 * @param op Operation (Cut, Copy or Clear)
3932 Editor::cut_copy_points (Editing::CutCopyOp op, Evoral::MusicalTime earliest, bool midi)
3934 if (selection->points.empty ()) {
3938 /* XXX: not ideal, as there may be more than one track involved in the point selection */
3939 _last_cut_copy_source_track = &selection->points.front()->line().trackview;
3941 /* Keep a record of the AutomationLists that we end up using in this operation */
3942 typedef std::map<boost::shared_ptr<AutomationList>, AutomationRecord> Lists;
3945 /* Go through all selected points, making an AutomationRecord for each distinct AutomationList */
3946 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
3947 const AutomationLine& line = (*i)->line();
3948 const boost::shared_ptr<AutomationList> al = line.the_list();
3949 if (lists.find (al) == lists.end ()) {
3950 /* We haven't seen this list yet, so make a record for it. This includes
3951 taking a copy of its current state, in case this is needed for undo later.
3953 lists[al] = AutomationRecord (&al->get_state (), &line);
3957 if (op == Cut || op == Copy) {
3958 /* This operation will involve putting things in the cut buffer, so create an empty
3959 ControlList for each of our source lists to put the cut buffer data in.
3961 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
3962 i->second.copy = i->first->create (i->first->parameter (), i->first->descriptor());
3965 /* Add all selected points to the relevant copy ControlLists */
3966 framepos_t start = std::numeric_limits<framepos_t>::max();
3967 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
3968 boost::shared_ptr<AutomationList> al = (*i)->line().the_list();
3969 AutomationList::const_iterator j = (*i)->model();
3971 lists[al].copy->fast_simple_add ((*j)->when, (*j)->value);
3973 /* Update earliest MIDI start time in beats */
3974 earliest = std::min(earliest, Evoral::MusicalTime((*j)->when));
3976 /* Update earliest session start time in frames */
3977 start = std::min(start, (*i)->line().session_position(j));
3981 /* Snap start time backwards, so copy/paste is snap aligned. */
3983 if (earliest == Evoral::MusicalTime::max()) {
3984 earliest = Evoral::MusicalTime(); // Weird... don't offset
3986 earliest.round_down_to_beat();
3988 if (start == std::numeric_limits<double>::max()) {
3989 start = 0; // Weird... don't offset
3991 snap_to(start, RoundDownMaybe);
3994 const double line_offset = midi ? earliest.to_double() : start;
3995 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
3996 /* Correct this copy list so that it is relative to the earliest
3997 start time, so relative ordering between points is preserved
3998 when copying from several lists and the paste starts at the
3999 earliest copied piece of data. */
4000 for (AutomationList::iterator j = i->second.copy->begin(); j != i->second.copy->end(); ++j) {
4001 (*j)->when -= line_offset;
4004 /* And add it to the cut buffer */
4005 cut_buffer->add (i->second.copy);
4009 if (op == Delete || op == Cut) {
4010 /* This operation needs to remove things from the main AutomationList, so do that now */
4012 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
4013 i->first->freeze ();
4016 /* Remove each selected point from its AutomationList */
4017 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
4018 boost::shared_ptr<AutomationList> al = (*i)->line().the_list();
4019 al->erase ((*i)->model ());
4022 /* Thaw the lists and add undo records for them */
4023 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
4024 boost::shared_ptr<AutomationList> al = i->first;
4026 _session->add_command (new MementoCommand<AutomationList> (*al.get(), i->second.state, &(al->get_state ())));
4031 /** Cut, copy or clear selected automation points.
4032 * @param op Operation (Cut, Copy or Clear)
4035 Editor::cut_copy_midi (CutCopyOp op)
4037 Evoral::MusicalTime earliest = Evoral::MusicalTime::max();
4038 for (MidiRegionSelection::iterator i = selection->midi_regions.begin(); i != selection->midi_regions.end(); ++i) {
4039 MidiRegionView* mrv = dynamic_cast<MidiRegionView*>(*i);
4041 if (!mrv->selection().empty()) {
4042 earliest = std::min(earliest, (*mrv->selection().begin())->note()->time());
4044 mrv->cut_copy_clear (op);
4046 /* XXX: not ideal, as there may be more than one track involved in the selection */
4047 _last_cut_copy_source_track = &mrv->get_time_axis_view();
4051 if (!selection->points.empty()) {
4052 cut_copy_points (op, earliest, true);
4053 if (op == Cut || op == Delete) {
4054 selection->clear_points ();
4059 struct lt_playlist {
4060 bool operator () (const PlaylistState& a, const PlaylistState& b) {
4061 return a.playlist < b.playlist;
4065 struct PlaylistMapping {
4067 boost::shared_ptr<Playlist> pl;
4069 PlaylistMapping (TimeAxisView* tvp) : tv (tvp) {}
4072 /** Remove `clicked_regionview' */
4074 Editor::remove_clicked_region ()
4076 if (clicked_routeview == 0 || clicked_regionview == 0) {
4080 begin_reversible_command (_("remove region"));
4082 boost::shared_ptr<Playlist> playlist = clicked_routeview->playlist();
4084 playlist->clear_changes ();
4085 playlist->clear_owned_changes ();
4086 playlist->remove_region (clicked_regionview->region());
4087 if (Config->get_edit_mode() == Ripple)
4088 playlist->ripple (clicked_regionview->region()->position(), -clicked_regionview->region()->length(), boost::shared_ptr<Region>());
4090 /* We might have removed regions, which alters other regions' layering_index,
4091 so we need to do a recursive diff here.
4093 vector<Command*> cmds;
4094 playlist->rdiff (cmds);
4095 _session->add_commands (cmds);
4097 _session->add_command(new StatefulDiffCommand (playlist));
4098 commit_reversible_command ();
4102 /** Remove the selected regions */
4104 Editor::remove_selected_regions ()
4106 RegionSelection rs = get_regions_from_selection_and_entered ();
4108 if (!_session || rs.empty()) {
4112 begin_reversible_command (_("remove region"));
4114 list<boost::shared_ptr<Region> > regions_to_remove;
4116 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
4117 // we can't just remove the region(s) in this loop because
4118 // this removes them from the RegionSelection, and they thus
4119 // disappear from underneath the iterator, and the ++i above
4120 // SEGVs in a puzzling fashion.
4122 // so, first iterate over the regions to be removed from rs and
4123 // add them to the regions_to_remove list, and then
4124 // iterate over the list to actually remove them.
4126 regions_to_remove.push_back ((*i)->region());
4129 vector<boost::shared_ptr<Playlist> > playlists;
4131 for (list<boost::shared_ptr<Region> >::iterator rl = regions_to_remove.begin(); rl != regions_to_remove.end(); ++rl) {
4133 boost::shared_ptr<Playlist> playlist = (*rl)->playlist();
4136 // is this check necessary?
4140 /* get_regions_from_selection_and_entered() guarantees that
4141 the playlists involved are unique, so there is no need
4145 playlists.push_back (playlist);
4147 playlist->clear_changes ();
4148 playlist->clear_owned_changes ();
4149 playlist->freeze ();
4150 playlist->remove_region (*rl);
4151 if (Config->get_edit_mode() == Ripple)
4152 playlist->ripple ((*rl)->position(), -(*rl)->length(), boost::shared_ptr<Region>());
4156 vector<boost::shared_ptr<Playlist> >::iterator pl;
4158 for (pl = playlists.begin(); pl != playlists.end(); ++pl) {
4161 /* We might have removed regions, which alters other regions' layering_index,
4162 so we need to do a recursive diff here.
4164 vector<Command*> cmds;
4165 (*pl)->rdiff (cmds);
4166 _session->add_commands (cmds);
4168 _session->add_command(new StatefulDiffCommand (*pl));
4171 commit_reversible_command ();
4174 /** Cut, copy or clear selected regions.
4175 * @param op Operation (Cut, Copy or Clear)
4178 Editor::cut_copy_regions (CutCopyOp op, RegionSelection& rs)
4180 /* we can't use a std::map here because the ordering is important, and we can't trivially sort
4181 a map when we want ordered access to both elements. i think.
4184 vector<PlaylistMapping> pmap;
4186 framepos_t first_position = max_framepos;
4188 typedef set<boost::shared_ptr<Playlist> > FreezeList;
4189 FreezeList freezelist;
4191 /* get ordering correct before we cut/copy */
4193 rs.sort_by_position_and_track ();
4195 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
4197 first_position = min ((framepos_t) (*x)->region()->position(), first_position);
4199 if (op == Cut || op == Clear || op == Delete) {
4200 boost::shared_ptr<Playlist> pl = (*x)->region()->playlist();
4203 FreezeList::iterator fl;
4205 // only take state if this is a new playlist.
4206 for (fl = freezelist.begin(); fl != freezelist.end(); ++fl) {
4212 if (fl == freezelist.end()) {
4213 pl->clear_changes();
4214 pl->clear_owned_changes ();
4216 freezelist.insert (pl);
4221 TimeAxisView* tv = &(*x)->get_time_axis_view();
4222 vector<PlaylistMapping>::iterator z;
4224 for (z = pmap.begin(); z != pmap.end(); ++z) {
4225 if ((*z).tv == tv) {
4230 if (z == pmap.end()) {
4231 pmap.push_back (PlaylistMapping (tv));
4235 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ) {
4237 boost::shared_ptr<Playlist> pl = (*x)->region()->playlist();
4240 /* region not yet associated with a playlist (e.g. unfinished
4247 TimeAxisView& tv = (*x)->get_time_axis_view();
4248 boost::shared_ptr<Playlist> npl;
4249 RegionSelection::iterator tmp;
4256 vector<PlaylistMapping>::iterator z;
4258 for (z = pmap.begin(); z != pmap.end(); ++z) {
4259 if ((*z).tv == &tv) {
4264 assert (z != pmap.end());
4267 npl = PlaylistFactory::create (pl->data_type(), *_session, "cutlist", true);
4275 boost::shared_ptr<Region> r = (*x)->region();
4276 boost::shared_ptr<Region> _xx;
4282 pl->remove_region (r);
4283 if (Config->get_edit_mode() == Ripple)
4284 pl->ripple (r->position(), -r->length(), boost::shared_ptr<Region>());
4288 _xx = RegionFactory::create (r);
4289 npl->add_region (_xx, r->position() - first_position);
4290 pl->remove_region (r);
4291 if (Config->get_edit_mode() == Ripple)
4292 pl->ripple (r->position(), -r->length(), boost::shared_ptr<Region>());
4296 /* copy region before adding, so we're not putting same object into two different playlists */
4297 npl->add_region (RegionFactory::create (r), r->position() - first_position);
4301 pl->remove_region (r);
4302 if (Config->get_edit_mode() == Ripple)
4303 pl->ripple (r->position(), -r->length(), boost::shared_ptr<Region>());
4312 list<boost::shared_ptr<Playlist> > foo;
4314 /* the pmap is in the same order as the tracks in which selected regions occured */
4316 for (vector<PlaylistMapping>::iterator i = pmap.begin(); i != pmap.end(); ++i) {
4319 foo.push_back ((*i).pl);
4324 cut_buffer->set (foo);
4328 _last_cut_copy_source_track = 0;
4330 _last_cut_copy_source_track = pmap.front().tv;
4334 for (FreezeList::iterator pl = freezelist.begin(); pl != freezelist.end(); ++pl) {
4337 /* We might have removed regions, which alters other regions' layering_index,
4338 so we need to do a recursive diff here.
4340 vector<Command*> cmds;
4341 (*pl)->rdiff (cmds);
4342 _session->add_commands (cmds);
4344 _session->add_command (new StatefulDiffCommand (*pl));
4349 Editor::cut_copy_ranges (CutCopyOp op)
4351 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4353 /* Sort the track selection now, so that it if is used, the playlists
4354 selected by the calls below to cut_copy_clear are in the order that
4355 their tracks appear in the editor. This makes things like paste
4356 of ranges work properly.
4359 sort_track_selection (ts);
4362 if (!entered_track) {
4365 ts.push_back (entered_track);
4368 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4369 (*i)->cut_copy_clear (*selection, op);
4374 Editor::paste (float times, bool from_context)
4376 DEBUG_TRACE (DEBUG::CutNPaste, "paste to preferred edit pos\n");
4378 paste_internal (get_preferred_edit_position (false, from_context), times);
4382 Editor::mouse_paste ()
4387 if (!mouse_frame (where, ignored)) {
4392 paste_internal (where, 1);
4396 Editor::paste_internal (framepos_t position, float times)
4398 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("apparent paste position is %1\n", position));
4400 if (cut_buffer->empty(internal_editing())) {
4404 if (position == max_framepos) {
4405 position = get_preferred_edit_position();
4406 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("preferred edit position is %1\n", position));
4409 if (position == last_paste_pos) {
4410 /* repeated paste in the same position */
4413 /* paste in new location, reset repeated paste state */
4415 last_paste_pos = position;
4418 /* get everything in the correct order */
4421 if (!selection->tracks.empty()) {
4422 /* If there is a track selection, paste into exactly those tracks and
4423 only those tracks. This allows the user to be explicit and override
4424 the below "do the reasonable thing" logic. */
4425 ts = selection->tracks.filter_to_unique_playlists ();
4426 sort_track_selection (ts);
4428 /* Figure out which track to base the paste at. */
4429 TimeAxisView* base_track = NULL;
4430 if (_edit_point == Editing::EditAtMouse && entered_track) {
4431 /* With the mouse edit point, paste onto the track under the mouse. */
4432 base_track = entered_track;
4433 } else if (_edit_point == Editing::EditAtMouse && entered_regionview) {
4434 /* With the mouse edit point, paste onto the track of the region under the mouse. */
4435 base_track = &entered_regionview->get_time_axis_view();
4436 } else if (_last_cut_copy_source_track) {
4437 /* Paste to the track that the cut/copy came from (see mantis #333). */
4438 base_track = _last_cut_copy_source_track;
4440 /* This is "impossible" since we've copied... well, do nothing. */
4444 /* Walk up to parent if necessary, so base track is a route. */
4445 while (base_track->get_parent()) {
4446 base_track = base_track->get_parent();
4449 /* Add base track and all tracks below it. The paste logic will select
4450 the appropriate object types from the cut buffer in relative order. */
4451 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4452 if ((*i)->order() >= base_track->order()) {
4457 /* Sort tracks so the nth track of type T will pick the nth object of type T. */
4458 sort_track_selection (ts);
4460 /* Add automation children of each track in order, for pasting several lines. */
4461 for (TrackViewList::iterator i = ts.begin(); i != ts.end();) {
4462 /* Add any automation children for pasting several lines */
4463 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*i++);
4468 typedef RouteTimeAxisView::AutomationTracks ATracks;
4469 const ATracks& atracks = rtv->automation_tracks();
4470 for (ATracks::const_iterator a = atracks.begin(); a != atracks.end(); ++a) {
4471 i = ts.insert(i, a->second.get());
4476 /* We now have a list of trackviews starting at base_track, including
4477 automation children, in the order shown in the editor, e.g. R1,
4478 R1.A1, R1.A2, R2, R2.A1, ... */
4481 if (ts.size() == 1 && cut_buffer->lines.size() == 1 &&
4482 dynamic_cast<AutomationTimeAxisView*>(ts.front())) {
4483 /* Only one line copied, and one automation track selected. Do a
4484 "greedy" paste from one automation type to another. */
4486 begin_reversible_command (Operations::paste);
4488 PasteContext ctx(paste_count, times, ItemCounts(), true);
4489 ts.front()->paste (position, *cut_buffer, ctx);
4491 commit_reversible_command ();
4493 } else if (internal_editing ()) {
4495 /* undo/redo is handled by individual tracks/regions */
4498 get_regions_at (rs, position, ts);
4500 PasteContext ctx(paste_count, times, ItemCounts(), false);
4501 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
4502 MidiRegionView* mrv = dynamic_cast<MidiRegionView*> (*r);
4504 mrv->paste (position, *cut_buffer, ctx);
4510 /* we do redo (do you do voodoo?) */
4512 begin_reversible_command (Operations::paste);
4514 PasteContext ctx(paste_count, times, ItemCounts(), false);
4515 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4516 (*i)->paste (position, *cut_buffer, ctx);
4519 commit_reversible_command ();
4524 Editor::duplicate_some_regions (RegionSelection& regions, float times)
4526 boost::shared_ptr<Playlist> playlist;
4527 RegionSelection sel = regions; // clear (below) may clear the argument list if its the current region selection
4528 RegionSelection foo;
4530 framepos_t const start_frame = regions.start ();
4531 framepos_t const end_frame = regions.end_frame ();
4533 begin_reversible_command (Operations::duplicate_region);
4535 selection->clear_regions ();
4537 for (RegionSelection::iterator i = sel.begin(); i != sel.end(); ++i) {
4539 boost::shared_ptr<Region> r ((*i)->region());
4541 TimeAxisView& tv = (*i)->get_time_axis_view();
4542 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (&tv);
4543 latest_regionviews.clear ();
4544 sigc::connection c = rtv->view()->RegionViewAdded.connect (sigc::mem_fun(*this, &Editor::collect_new_region_view));
4546 playlist = (*i)->region()->playlist();
4547 playlist->clear_changes ();
4548 playlist->duplicate (r, end_frame + (r->first_frame() - start_frame), times);
4549 _session->add_command(new StatefulDiffCommand (playlist));
4553 foo.insert (foo.end(), latest_regionviews.begin(), latest_regionviews.end());
4557 selection->set (foo);
4560 commit_reversible_command ();
4564 Editor::duplicate_selection (float times)
4566 if (selection->time.empty() || selection->tracks.empty()) {
4570 boost::shared_ptr<Playlist> playlist;
4571 vector<boost::shared_ptr<Region> > new_regions;
4572 vector<boost::shared_ptr<Region> >::iterator ri;
4574 create_region_from_selection (new_regions);
4576 if (new_regions.empty()) {
4580 begin_reversible_command (_("duplicate selection"));
4582 ri = new_regions.begin();
4584 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4586 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4587 if ((playlist = (*i)->playlist()) == 0) {
4590 playlist->clear_changes ();
4591 playlist->duplicate (*ri, selection->time[clicked_selection].end, times);
4592 _session->add_command (new StatefulDiffCommand (playlist));
4595 if (ri == new_regions.end()) {
4600 commit_reversible_command ();
4603 /** Reset all selected points to the relevant default value */
4605 Editor::reset_point_selection ()
4607 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
4608 ARDOUR::AutomationList::iterator j = (*i)->model ();
4609 (*j)->value = (*i)->line().the_list()->default_value ();
4614 Editor::center_playhead ()
4616 float const page = _visible_canvas_width * samples_per_pixel;
4617 center_screen_internal (playhead_cursor->current_frame (), page);
4621 Editor::center_edit_point ()
4623 float const page = _visible_canvas_width * samples_per_pixel;
4624 center_screen_internal (get_preferred_edit_position(), page);
4627 /** Caller must begin and commit a reversible command */
4629 Editor::clear_playlist (boost::shared_ptr<Playlist> playlist)
4631 playlist->clear_changes ();
4633 _session->add_command (new StatefulDiffCommand (playlist));
4637 Editor::nudge_track (bool use_edit, bool forwards)
4639 boost::shared_ptr<Playlist> playlist;
4640 framepos_t distance;
4641 framepos_t next_distance;
4645 start = get_preferred_edit_position();
4650 if ((distance = get_nudge_distance (start, next_distance)) == 0) {
4654 if (selection->tracks.empty()) {
4658 begin_reversible_command (_("nudge track"));
4660 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4662 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4664 if ((playlist = (*i)->playlist()) == 0) {
4668 playlist->clear_changes ();
4669 playlist->clear_owned_changes ();
4671 playlist->nudge_after (start, distance, forwards);
4673 vector<Command*> cmds;
4675 playlist->rdiff (cmds);
4676 _session->add_commands (cmds);
4678 _session->add_command (new StatefulDiffCommand (playlist));
4681 commit_reversible_command ();
4685 Editor::remove_last_capture ()
4687 vector<string> choices;
4694 if (Config->get_verify_remove_last_capture()) {
4695 prompt = _("Do you really want to destroy the last capture?"
4696 "\n(This is destructive and cannot be undone)");
4698 choices.push_back (_("No, do nothing."));
4699 choices.push_back (_("Yes, destroy it."));
4701 Gtkmm2ext::Choice prompter (_("Destroy last capture"), prompt, choices);
4703 if (prompter.run () == 1) {
4704 _session->remove_last_capture ();
4705 _regions->redisplay ();
4709 _session->remove_last_capture();
4710 _regions->redisplay ();
4715 Editor::normalize_region ()
4721 RegionSelection rs = get_regions_from_selection_and_entered ();
4727 NormalizeDialog dialog (rs.size() > 1);
4729 if (dialog.run () == RESPONSE_CANCEL) {
4733 set_canvas_cursor (_cursors->wait);
4736 /* XXX: should really only count audio regions here */
4737 int const regions = rs.size ();
4739 /* Make a list of the selected audio regions' maximum amplitudes, and also
4740 obtain the maximum amplitude of them all.
4742 list<double> max_amps;
4744 for (RegionSelection::const_iterator i = rs.begin(); i != rs.end(); ++i) {
4745 AudioRegionView const * arv = dynamic_cast<AudioRegionView const *> (*i);
4747 dialog.descend (1.0 / regions);
4748 double const a = arv->audio_region()->maximum_amplitude (&dialog);
4751 /* the user cancelled the operation */
4752 set_canvas_cursor (current_canvas_cursor);
4756 max_amps.push_back (a);
4757 max_amp = max (max_amp, a);
4762 begin_reversible_command (_("normalize"));
4764 list<double>::const_iterator a = max_amps.begin ();
4766 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
4767 AudioRegionView* const arv = dynamic_cast<AudioRegionView*> (*r);
4772 arv->region()->clear_changes ();
4774 double const amp = dialog.normalize_individually() ? *a : max_amp;
4776 arv->audio_region()->normalize (amp, dialog.target ());
4777 _session->add_command (new StatefulDiffCommand (arv->region()));
4782 commit_reversible_command ();
4783 set_canvas_cursor (current_canvas_cursor);
4788 Editor::reset_region_scale_amplitude ()
4794 RegionSelection rs = get_regions_from_selection_and_entered ();
4800 begin_reversible_command ("reset gain");
4802 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
4803 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
4806 arv->region()->clear_changes ();
4807 arv->audio_region()->set_scale_amplitude (1.0f);
4808 _session->add_command (new StatefulDiffCommand (arv->region()));
4811 commit_reversible_command ();
4815 Editor::adjust_region_gain (bool up)
4817 RegionSelection rs = get_regions_from_selection_and_entered ();
4819 if (!_session || rs.empty()) {
4823 begin_reversible_command ("adjust region gain");
4825 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
4826 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
4831 arv->region()->clear_changes ();
4833 double dB = accurate_coefficient_to_dB (arv->audio_region()->scale_amplitude ());
4841 arv->audio_region()->set_scale_amplitude (dB_to_coefficient (dB));
4842 _session->add_command (new StatefulDiffCommand (arv->region()));
4845 commit_reversible_command ();
4850 Editor::reverse_region ()
4856 Reverse rev (*_session);
4857 apply_filter (rev, _("reverse regions"));
4861 Editor::strip_region_silence ()
4867 RegionSelection rs = get_regions_from_selection_and_entered ();
4873 std::list<RegionView*> audio_only;
4875 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
4876 AudioRegionView* const arv = dynamic_cast<AudioRegionView*> (*i);
4878 audio_only.push_back (arv);
4882 StripSilenceDialog d (_session, audio_only);
4883 int const r = d.run ();
4887 if (r == Gtk::RESPONSE_OK) {
4888 ARDOUR::AudioIntervalMap silences;
4889 d.silences (silences);
4890 StripSilence s (*_session, silences, d.fade_length());
4891 apply_filter (s, _("strip silence"), &d);
4896 Editor::apply_midi_note_edit_op_to_region (MidiOperator& op, MidiRegionView& mrv)
4898 Evoral::Sequence<Evoral::MusicalTime>::Notes selected;
4899 mrv.selection_as_notelist (selected, true);
4901 vector<Evoral::Sequence<Evoral::MusicalTime>::Notes> v;
4902 v.push_back (selected);
4904 framepos_t pos_frames = mrv.midi_region()->position() - mrv.midi_region()->start();
4905 Evoral::MusicalTime pos_beats = _session->tempo_map().framewalk_to_beats(0, pos_frames);
4907 return op (mrv.midi_region()->model(), pos_beats, v);
4911 Editor::apply_midi_note_edit_op (MidiOperator& op)
4915 RegionSelection rs = get_regions_from_selection_and_entered ();
4921 begin_reversible_command (op.name ());
4923 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
4924 RegionSelection::iterator tmp = r;
4927 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*r);
4930 cmd = apply_midi_note_edit_op_to_region (op, *mrv);
4933 _session->add_command (cmd);
4940 commit_reversible_command ();
4944 Editor::fork_region ()
4946 RegionSelection rs = get_regions_from_selection_and_entered ();
4952 begin_reversible_command (_("Fork Region(s)"));
4954 set_canvas_cursor (_cursors->wait);
4957 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
4958 RegionSelection::iterator tmp = r;
4961 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*>(*r);
4965 boost::shared_ptr<Playlist> playlist = mrv->region()->playlist();
4966 boost::shared_ptr<MidiSource> new_source = _session->create_midi_source_by_stealing_name (mrv->midi_view()->track());
4967 boost::shared_ptr<MidiRegion> newregion = mrv->midi_region()->clone (new_source);
4969 playlist->clear_changes ();
4970 playlist->replace_region (mrv->region(), newregion, mrv->region()->position());
4971 _session->add_command(new StatefulDiffCommand (playlist));
4973 error << string_compose (_("Could not unlink %1"), mrv->region()->name()) << endmsg;
4980 commit_reversible_command ();
4982 set_canvas_cursor (current_canvas_cursor);
4986 Editor::quantize_region ()
4988 int selected_midi_region_cnt = 0;
4994 RegionSelection rs = get_regions_from_selection_and_entered ();
5000 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
5001 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*r);
5003 selected_midi_region_cnt++;
5007 if (selected_midi_region_cnt == 0) {
5011 QuantizeDialog* qd = new QuantizeDialog (*this);
5014 const int r = qd->run ();
5017 if (r == Gtk::RESPONSE_OK) {
5018 Quantize quant (qd->snap_start(), qd->snap_end(),
5019 qd->start_grid_size(), qd->end_grid_size(),
5020 qd->strength(), qd->swing(), qd->threshold());
5022 apply_midi_note_edit_op (quant);
5027 Editor::legatize_region (bool shrink_only)
5029 int selected_midi_region_cnt = 0;
5035 RegionSelection rs = get_regions_from_selection_and_entered ();
5041 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
5042 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*r);
5044 selected_midi_region_cnt++;
5048 if (selected_midi_region_cnt == 0) {
5052 Legatize legatize(shrink_only);
5053 apply_midi_note_edit_op (legatize);
5057 Editor::insert_patch_change (bool from_context)
5059 RegionSelection rs = get_regions_from_selection_and_entered ();
5065 const framepos_t p = get_preferred_edit_position (false, from_context);
5067 /* XXX: bit of a hack; use the MIDNAM from the first selected region;
5068 there may be more than one, but the PatchChangeDialog can only offer
5069 one set of patch menus.
5071 MidiRegionView* first = dynamic_cast<MidiRegionView*> (rs.front ());
5073 Evoral::PatchChange<Evoral::MusicalTime> empty (Evoral::MusicalTime(), 0, 0, 0);
5074 PatchChangeDialog d (0, _session, empty, first->instrument_info(), Gtk::Stock::ADD);
5076 if (d.run() == RESPONSE_CANCEL) {
5080 for (RegionSelection::iterator i = rs.begin (); i != rs.end(); ++i) {
5081 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*i);
5083 if (p >= mrv->region()->first_frame() && p <= mrv->region()->last_frame()) {
5084 mrv->add_patch_change (p - mrv->region()->position(), d.patch ());
5091 Editor::apply_filter (Filter& filter, string command, ProgressReporter* progress)
5093 RegionSelection rs = get_regions_from_selection_and_entered ();
5099 begin_reversible_command (command);
5101 set_canvas_cursor (_cursors->wait);
5105 int const N = rs.size ();
5107 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
5108 RegionSelection::iterator tmp = r;
5111 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
5113 boost::shared_ptr<Playlist> playlist = arv->region()->playlist();
5116 progress->descend (1.0 / N);
5119 if (arv->audio_region()->apply (filter, progress) == 0) {
5121 playlist->clear_changes ();
5122 playlist->clear_owned_changes ();
5124 if (filter.results.empty ()) {
5126 /* no regions returned; remove the old one */
5127 playlist->remove_region (arv->region ());
5131 std::vector<boost::shared_ptr<Region> >::iterator res = filter.results.begin ();
5133 /* first region replaces the old one */
5134 playlist->replace_region (arv->region(), *res, (*res)->position());
5138 while (res != filter.results.end()) {
5139 playlist->add_region (*res, (*res)->position());
5145 /* We might have removed regions, which alters other regions' layering_index,
5146 so we need to do a recursive diff here.
5148 vector<Command*> cmds;
5149 playlist->rdiff (cmds);
5150 _session->add_commands (cmds);
5152 _session->add_command(new StatefulDiffCommand (playlist));
5158 progress->ascend ();
5166 commit_reversible_command ();
5169 set_canvas_cursor (current_canvas_cursor);
5173 Editor::external_edit_region ()
5179 Editor::reset_region_gain_envelopes ()
5181 RegionSelection rs = get_regions_from_selection_and_entered ();
5183 if (!_session || rs.empty()) {
5187 begin_reversible_command (_("reset region gain"));
5189 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5190 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
5192 boost::shared_ptr<AutomationList> alist (arv->audio_region()->envelope());
5193 XMLNode& before (alist->get_state());
5195 arv->audio_region()->set_default_envelope ();
5196 _session->add_command (new MementoCommand<AutomationList>(*arv->audio_region()->envelope().get(), &before, &alist->get_state()));
5200 commit_reversible_command ();
5204 Editor::set_region_gain_visibility (RegionView* rv)
5206 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (rv);
5208 arv->update_envelope_visibility();
5213 Editor::set_gain_envelope_visibility ()
5219 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5220 AudioTimeAxisView* v = dynamic_cast<AudioTimeAxisView*>(*i);
5222 v->audio_view()->foreach_regionview (sigc::mem_fun (this, &Editor::set_region_gain_visibility));
5228 Editor::toggle_gain_envelope_active ()
5230 if (_ignore_region_action) {
5234 RegionSelection rs = get_regions_from_selection_and_entered ();
5236 if (!_session || rs.empty()) {
5240 begin_reversible_command (_("region gain envelope active"));
5242 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5243 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
5245 arv->region()->clear_changes ();
5246 arv->audio_region()->set_envelope_active (!arv->audio_region()->envelope_active());
5247 _session->add_command (new StatefulDiffCommand (arv->region()));
5251 commit_reversible_command ();
5255 Editor::toggle_region_lock ()
5257 if (_ignore_region_action) {
5261 RegionSelection rs = get_regions_from_selection_and_entered ();
5263 if (!_session || rs.empty()) {
5267 begin_reversible_command (_("toggle region lock"));
5269 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5270 (*i)->region()->clear_changes ();
5271 (*i)->region()->set_locked (!(*i)->region()->locked());
5272 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5275 commit_reversible_command ();
5279 Editor::toggle_region_video_lock ()
5281 if (_ignore_region_action) {
5285 RegionSelection rs = get_regions_from_selection_and_entered ();
5287 if (!_session || rs.empty()) {
5291 begin_reversible_command (_("Toggle Video Lock"));
5293 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5294 (*i)->region()->clear_changes ();
5295 (*i)->region()->set_video_locked (!(*i)->region()->video_locked());
5296 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5299 commit_reversible_command ();
5303 Editor::toggle_region_lock_style ()
5305 if (_ignore_region_action) {
5309 RegionSelection rs = get_regions_from_selection_and_entered ();
5311 if (!_session || rs.empty()) {
5315 begin_reversible_command (_("region lock style"));
5317 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5318 (*i)->region()->clear_changes ();
5319 PositionLockStyle const ns = (*i)->region()->position_lock_style() == AudioTime ? MusicTime : AudioTime;
5320 (*i)->region()->set_position_lock_style (ns);
5321 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5324 commit_reversible_command ();
5328 Editor::toggle_opaque_region ()
5330 if (_ignore_region_action) {
5334 RegionSelection rs = get_regions_from_selection_and_entered ();
5336 if (!_session || rs.empty()) {
5340 begin_reversible_command (_("change region opacity"));
5342 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5343 (*i)->region()->clear_changes ();
5344 (*i)->region()->set_opaque (!(*i)->region()->opaque());
5345 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5348 commit_reversible_command ();
5352 Editor::toggle_record_enable ()
5354 bool new_state = false;
5356 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5357 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5360 if (!rtav->is_track())
5364 new_state = !rtav->track()->record_enabled();
5368 rtav->track()->set_record_enabled (new_state, this);
5373 Editor::toggle_solo ()
5375 bool new_state = false;
5377 boost::shared_ptr<RouteList> rl (new RouteList);
5379 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5380 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5387 new_state = !rtav->route()->soloed ();
5391 rl->push_back (rtav->route());
5394 _session->set_solo (rl, new_state, Session::rt_cleanup, true);
5398 Editor::toggle_mute ()
5400 bool new_state = false;
5402 boost::shared_ptr<RouteList> rl (new RouteList);
5404 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5405 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5412 new_state = !rtav->route()->muted();
5416 rl->push_back (rtav->route());
5419 _session->set_mute (rl, new_state, Session::rt_cleanup, true);
5423 Editor::toggle_solo_isolate ()
5429 Editor::fade_range ()
5431 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
5433 begin_reversible_command (_("fade range"));
5435 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
5436 (*i)->fade_range (selection->time);
5439 commit_reversible_command ();
5444 Editor::set_fade_length (bool in)
5446 RegionSelection rs = get_regions_from_selection_and_entered ();
5452 /* we need a region to measure the offset from the start */
5454 RegionView* rv = rs.front ();
5456 framepos_t pos = get_preferred_edit_position();
5460 if (pos > rv->region()->last_frame() || pos < rv->region()->first_frame()) {
5461 /* edit point is outside the relevant region */
5466 if (pos <= rv->region()->position()) {
5470 len = pos - rv->region()->position();
5471 cmd = _("set fade in length");
5473 if (pos >= rv->region()->last_frame()) {
5477 len = rv->region()->last_frame() - pos;
5478 cmd = _("set fade out length");
5481 begin_reversible_command (cmd);
5483 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5484 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5490 boost::shared_ptr<AutomationList> alist;
5492 alist = tmp->audio_region()->fade_in();
5494 alist = tmp->audio_region()->fade_out();
5497 XMLNode &before = alist->get_state();
5500 tmp->audio_region()->set_fade_in_length (len);
5501 tmp->audio_region()->set_fade_in_active (true);
5503 tmp->audio_region()->set_fade_out_length (len);
5504 tmp->audio_region()->set_fade_out_active (true);
5507 XMLNode &after = alist->get_state();
5508 _session->add_command(new MementoCommand<AutomationList>(*alist, &before, &after));
5511 commit_reversible_command ();
5515 Editor::set_fade_in_shape (FadeShape shape)
5517 RegionSelection rs = get_regions_from_selection_and_entered ();
5523 begin_reversible_command (_("set fade in shape"));
5525 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5526 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5532 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_in();
5533 XMLNode &before = alist->get_state();
5535 tmp->audio_region()->set_fade_in_shape (shape);
5537 XMLNode &after = alist->get_state();
5538 _session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
5541 commit_reversible_command ();
5546 Editor::set_fade_out_shape (FadeShape shape)
5548 RegionSelection rs = get_regions_from_selection_and_entered ();
5554 begin_reversible_command (_("set fade out shape"));
5556 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5557 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5563 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_out();
5564 XMLNode &before = alist->get_state();
5566 tmp->audio_region()->set_fade_out_shape (shape);
5568 XMLNode &after = alist->get_state();
5569 _session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
5572 commit_reversible_command ();
5576 Editor::set_fade_in_active (bool yn)
5578 RegionSelection rs = get_regions_from_selection_and_entered ();
5584 begin_reversible_command (_("set fade in active"));
5586 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5587 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5594 boost::shared_ptr<AudioRegion> ar (tmp->audio_region());
5596 ar->clear_changes ();
5597 ar->set_fade_in_active (yn);
5598 _session->add_command (new StatefulDiffCommand (ar));
5601 commit_reversible_command ();
5605 Editor::set_fade_out_active (bool yn)
5607 RegionSelection rs = get_regions_from_selection_and_entered ();
5613 begin_reversible_command (_("set fade out active"));
5615 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5616 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5622 boost::shared_ptr<AudioRegion> ar (tmp->audio_region());
5624 ar->clear_changes ();
5625 ar->set_fade_out_active (yn);
5626 _session->add_command(new StatefulDiffCommand (ar));
5629 commit_reversible_command ();
5633 Editor::toggle_region_fades (int dir)
5635 if (_ignore_region_action) {
5639 boost::shared_ptr<AudioRegion> ar;
5642 RegionSelection rs = get_regions_from_selection_and_entered ();
5648 RegionSelection::iterator i;
5649 for (i = rs.begin(); i != rs.end(); ++i) {
5650 if ((ar = boost::dynamic_pointer_cast<AudioRegion>((*i)->region())) != 0) {
5652 yn = ar->fade_out_active ();
5654 yn = ar->fade_in_active ();
5660 if (i == rs.end()) {
5664 /* XXX should this undo-able? */
5666 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5667 if ((ar = boost::dynamic_pointer_cast<AudioRegion>((*i)->region())) == 0) {
5670 if (dir == 1 || dir == 0) {
5671 ar->set_fade_in_active (!yn);
5674 if (dir == -1 || dir == 0) {
5675 ar->set_fade_out_active (!yn);
5681 /** Update region fade visibility after its configuration has been changed */
5683 Editor::update_region_fade_visibility ()
5685 bool _fade_visibility = _session->config.get_show_region_fades ();
5687 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5688 AudioTimeAxisView* v = dynamic_cast<AudioTimeAxisView*>(*i);
5690 if (_fade_visibility) {
5691 v->audio_view()->show_all_fades ();
5693 v->audio_view()->hide_all_fades ();
5700 Editor::set_edit_point ()
5705 if (!mouse_frame (where, ignored)) {
5711 if (selection->markers.empty()) {
5713 mouse_add_new_marker (where);
5718 Location* loc = find_location_from_marker (selection->markers.front(), ignored);
5721 loc->move_to (where);
5727 Editor::set_playhead_cursor ()
5729 if (entered_marker) {
5730 _session->request_locate (entered_marker->position(), _session->transport_rolling());
5735 if (!mouse_frame (where, ignored)) {
5742 _session->request_locate (where, _session->transport_rolling());
5746 if ( Config->get_follow_edits() )
5747 cancel_time_selection();
5751 Editor::split_region ()
5753 if ( !selection->time.empty()) {
5754 separate_regions_between (selection->time);
5758 RegionSelection rs = get_regions_from_selection_and_edit_point ();
5760 framepos_t where = get_preferred_edit_position ();
5766 split_regions_at (where, rs);
5769 struct EditorOrderRouteSorter {
5770 bool operator() (boost::shared_ptr<Route> a, boost::shared_ptr<Route> b) {
5771 return a->order_key () < b->order_key ();
5776 Editor::select_next_route()
5778 if (selection->tracks.empty()) {
5779 selection->set (track_views.front());
5783 TimeAxisView* current = selection->tracks.front();
5787 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5788 if (*i == current) {
5790 if (i != track_views.end()) {
5793 current = (*(track_views.begin()));
5794 //selection->set (*(track_views.begin()));
5799 rui = dynamic_cast<RouteUI *>(current);
5800 } while ( current->hidden() || (rui != NULL && !rui->route()->active()));
5802 selection->set(current);
5804 ensure_time_axis_view_is_visible (*current, false);
5808 Editor::select_prev_route()
5810 if (selection->tracks.empty()) {
5811 selection->set (track_views.front());
5815 TimeAxisView* current = selection->tracks.front();
5819 for (TrackViewList::reverse_iterator i = track_views.rbegin(); i != track_views.rend(); ++i) {
5820 if (*i == current) {
5822 if (i != track_views.rend()) {
5825 current = *(track_views.rbegin());
5830 rui = dynamic_cast<RouteUI *>(current);
5831 } while ( current->hidden() || (rui != NULL && !rui->route()->active()));
5833 selection->set (current);
5835 ensure_time_axis_view_is_visible (*current, false);
5839 Editor::set_loop_from_selection (bool play)
5841 if (_session == 0 || selection->time.empty()) {
5845 framepos_t start = selection->time[clicked_selection].start;
5846 framepos_t end = selection->time[clicked_selection].end;
5848 set_loop_range (start, end, _("set loop range from selection"));
5851 _session->request_locate (start, true);
5852 _session->request_play_loop (true);
5857 Editor::set_loop_from_edit_range (bool play)
5859 if (_session == 0) {
5866 if (!get_edit_op_range (start, end)) {
5870 set_loop_range (start, end, _("set loop range from edit range"));
5873 _session->request_locate (start, true);
5874 _session->request_play_loop (true);
5879 Editor::set_loop_from_region (bool play)
5881 framepos_t start = max_framepos;
5884 RegionSelection rs = get_regions_from_selection_and_entered ();
5890 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5891 if ((*i)->region()->position() < start) {
5892 start = (*i)->region()->position();
5894 if ((*i)->region()->last_frame() + 1 > end) {
5895 end = (*i)->region()->last_frame() + 1;
5899 set_loop_range (start, end, _("set loop range from region"));
5902 _session->request_locate (start, true);
5903 _session->request_play_loop (true);
5908 Editor::set_punch_from_selection ()
5910 if (_session == 0 || selection->time.empty()) {
5914 framepos_t start = selection->time[clicked_selection].start;
5915 framepos_t end = selection->time[clicked_selection].end;
5917 set_punch_range (start, end, _("set punch range from selection"));
5921 Editor::set_session_extents_from_selection ()
5923 if (_session == 0 || selection->time.empty()) {
5927 begin_reversible_command (_("set session start/stop from selection"));
5929 framepos_t start = selection->time[clicked_selection].start;
5930 framepos_t end = selection->time[clicked_selection].end;
5933 if ((loc = _session->locations()->session_range_location()) == 0) {
5934 _session->set_session_extents ( start, end ); // this will create a new session range; no need for UNDO
5936 XMLNode &before = loc->get_state();
5938 _session->set_session_extents ( start, end );
5940 XMLNode &after = loc->get_state();
5942 _session->add_command (new MementoCommand<Location>(*loc, &before, &after));
5944 commit_reversible_command ();
5949 Editor::set_punch_from_edit_range ()
5951 if (_session == 0) {
5958 if (!get_edit_op_range (start, end)) {
5962 set_punch_range (start, end, _("set punch range from edit range"));
5966 Editor::set_punch_from_region ()
5968 framepos_t start = max_framepos;
5971 RegionSelection rs = get_regions_from_selection_and_entered ();
5977 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5978 if ((*i)->region()->position() < start) {
5979 start = (*i)->region()->position();
5981 if ((*i)->region()->last_frame() + 1 > end) {
5982 end = (*i)->region()->last_frame() + 1;
5986 set_punch_range (start, end, _("set punch range from region"));
5990 Editor::pitch_shift_region ()
5992 RegionSelection rs = get_regions_from_selection_and_entered ();
5994 RegionSelection audio_rs;
5995 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5996 if (dynamic_cast<AudioRegionView*> (*i)) {
5997 audio_rs.push_back (*i);
6001 if (audio_rs.empty()) {
6005 pitch_shift (audio_rs, 1.2);
6009 Editor::transpose_region ()
6011 RegionSelection rs = get_regions_from_selection_and_entered ();
6013 list<MidiRegionView*> midi_region_views;
6014 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
6015 MidiRegionView* mrv = dynamic_cast<MidiRegionView*> (*i);
6017 midi_region_views.push_back (mrv);
6022 int const r = d.run ();
6023 if (r != RESPONSE_ACCEPT) {
6027 for (list<MidiRegionView*>::iterator i = midi_region_views.begin(); i != midi_region_views.end(); ++i) {
6028 (*i)->midi_region()->transpose (d.semitones ());
6033 Editor::set_tempo_from_region ()
6035 RegionSelection rs = get_regions_from_selection_and_entered ();
6037 if (!_session || rs.empty()) {
6041 RegionView* rv = rs.front();
6043 define_one_bar (rv->region()->position(), rv->region()->last_frame() + 1);
6047 Editor::use_range_as_bar ()
6049 framepos_t start, end;
6050 if (get_edit_op_range (start, end)) {
6051 define_one_bar (start, end);
6056 Editor::define_one_bar (framepos_t start, framepos_t end)
6058 framepos_t length = end - start;
6060 const Meter& m (_session->tempo_map().meter_at (start));
6062 /* length = 1 bar */
6064 /* now we want frames per beat.
6065 we have frames per bar, and beats per bar, so ...
6068 /* XXXX METER MATH */
6070 double frames_per_beat = length / m.divisions_per_bar();
6072 /* beats per minute = */
6074 double beats_per_minute = (_session->frame_rate() * 60.0) / frames_per_beat;
6076 /* now decide whether to:
6078 (a) set global tempo
6079 (b) add a new tempo marker
6083 const TempoSection& t (_session->tempo_map().tempo_section_at (start));
6085 bool do_global = false;
6087 if ((_session->tempo_map().n_tempos() == 1) && (_session->tempo_map().n_meters() == 1)) {
6089 /* only 1 tempo & 1 meter: ask if the user wants to set the tempo
6090 at the start, or create a new marker
6093 vector<string> options;
6094 options.push_back (_("Cancel"));
6095 options.push_back (_("Add new marker"));
6096 options.push_back (_("Set global tempo"));
6099 _("Define one bar"),
6100 _("Do you want to set the global tempo or add a new tempo marker?"),
6104 c.set_default_response (2);
6120 /* more than 1 tempo and/or meter section already, go ahead do the "usual":
6121 if the marker is at the region starter, change it, otherwise add
6126 begin_reversible_command (_("set tempo from region"));
6127 XMLNode& before (_session->tempo_map().get_state());
6130 _session->tempo_map().change_initial_tempo (beats_per_minute, t.note_type());
6131 } else if (t.frame() == start) {
6132 _session->tempo_map().change_existing_tempo_at (start, beats_per_minute, t.note_type());
6134 Timecode::BBT_Time bbt;
6135 _session->tempo_map().bbt_time (start, bbt);
6136 _session->tempo_map().add_tempo (Tempo (beats_per_minute, t.note_type()), bbt);
6139 XMLNode& after (_session->tempo_map().get_state());
6141 _session->add_command (new MementoCommand<TempoMap>(_session->tempo_map(), &before, &after));
6142 commit_reversible_command ();
6146 Editor::split_region_at_transients ()
6148 AnalysisFeatureList positions;
6150 RegionSelection rs = get_regions_from_selection_and_entered ();
6152 if (!_session || rs.empty()) {
6156 begin_reversible_command (_("split regions"));
6158 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ) {
6160 RegionSelection::iterator tmp;
6165 boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion> ((*i)->region());
6167 if (ar && (ar->get_transients (positions) == 0)) {
6168 split_region_at_points ((*i)->region(), positions, true);
6175 commit_reversible_command ();
6180 Editor::split_region_at_points (boost::shared_ptr<Region> r, AnalysisFeatureList& positions, bool can_ferret, bool select_new)
6182 bool use_rhythmic_rodent = false;
6184 boost::shared_ptr<Playlist> pl = r->playlist();
6186 list<boost::shared_ptr<Region> > new_regions;
6192 if (positions.empty()) {
6197 if (positions.size() > 20 && can_ferret) {
6198 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);
6199 MessageDialog msg (msgstr,
6202 Gtk::BUTTONS_OK_CANCEL);
6205 msg.add_button (_("Call for the Ferret!"), RESPONSE_APPLY);
6206 msg.set_secondary_text (_("Press OK to continue with this split operation\nor ask the Ferret dialog to tune the analysis"));
6208 msg.set_secondary_text (_("Press OK to continue with this split operation"));
6211 msg.set_title (_("Excessive split?"));
6214 int response = msg.run();
6220 case RESPONSE_APPLY:
6221 use_rhythmic_rodent = true;
6228 if (use_rhythmic_rodent) {
6229 show_rhythm_ferret ();
6233 AnalysisFeatureList::const_iterator x;
6235 pl->clear_changes ();
6236 pl->clear_owned_changes ();
6238 x = positions.begin();
6240 if (x == positions.end()) {
6245 pl->remove_region (r);
6249 while (x != positions.end()) {
6251 /* deal with positons that are out of scope of present region bounds */
6252 if (*x <= 0 || *x > r->length()) {
6257 /* file start = original start + how far we from the initial position ?
6260 framepos_t file_start = r->start() + pos;
6262 /* length = next position - current position
6265 framepos_t len = (*x) - pos;
6267 /* XXX we do we really want to allow even single-sample regions?
6268 shouldn't we have some kind of lower limit on region size?
6277 if (RegionFactory::region_name (new_name, r->name())) {
6281 /* do NOT announce new regions 1 by one, just wait till they are all done */
6285 plist.add (ARDOUR::Properties::start, file_start);
6286 plist.add (ARDOUR::Properties::length, len);
6287 plist.add (ARDOUR::Properties::name, new_name);
6288 plist.add (ARDOUR::Properties::layer, 0);
6290 boost::shared_ptr<Region> nr = RegionFactory::create (r->sources(), plist, false);
6291 /* because we set annouce to false, manually add the new region to the
6294 RegionFactory::map_add (nr);
6296 pl->add_region (nr, r->position() + pos);
6299 new_regions.push_front(nr);
6308 RegionFactory::region_name (new_name, r->name());
6310 /* Add the final region */
6313 plist.add (ARDOUR::Properties::start, r->start() + pos);
6314 plist.add (ARDOUR::Properties::length, r->last_frame() - (r->position() + pos) + 1);
6315 plist.add (ARDOUR::Properties::name, new_name);
6316 plist.add (ARDOUR::Properties::layer, 0);
6318 boost::shared_ptr<Region> nr = RegionFactory::create (r->sources(), plist, false);
6319 /* because we set annouce to false, manually add the new region to the
6322 RegionFactory::map_add (nr);
6323 pl->add_region (nr, r->position() + pos);
6326 new_regions.push_front(nr);
6331 /* We might have removed regions, which alters other regions' layering_index,
6332 so we need to do a recursive diff here.
6334 vector<Command*> cmds;
6336 _session->add_commands (cmds);
6338 _session->add_command (new StatefulDiffCommand (pl));
6342 for (list<boost::shared_ptr<Region> >::iterator i = new_regions.begin(); i != new_regions.end(); ++i){
6343 set_selected_regionview_from_region_list ((*i), Selection::Add);
6349 Editor::place_transient()
6355 RegionSelection rs = get_regions_from_selection_and_edit_point ();
6361 framepos_t where = get_preferred_edit_position();
6363 begin_reversible_command (_("place transient"));
6365 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6366 framepos_t position = (*r)->region()->position();
6367 (*r)->region()->add_transient(where - position);
6370 commit_reversible_command ();
6374 Editor::remove_transient(ArdourCanvas::Item* item)
6380 ArdourCanvas::Line* _line = reinterpret_cast<ArdourCanvas::Line*> (item);
6383 AudioRegionView* _arv = reinterpret_cast<AudioRegionView*> (item->get_data ("regionview"));
6384 _arv->remove_transient (*(float*) _line->get_data ("position"));
6388 Editor::snap_regions_to_grid ()
6390 list <boost::shared_ptr<Playlist > > used_playlists;
6392 RegionSelection rs = get_regions_from_selection_and_entered ();
6394 if (!_session || rs.empty()) {
6398 begin_reversible_command (_("snap regions to grid"));
6400 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6402 boost::shared_ptr<Playlist> pl = (*r)->region()->playlist();
6404 if (!pl->frozen()) {
6405 /* we haven't seen this playlist before */
6407 /* remember used playlists so we can thaw them later */
6408 used_playlists.push_back(pl);
6412 framepos_t start_frame = (*r)->region()->first_frame ();
6413 snap_to (start_frame);
6414 (*r)->region()->set_position (start_frame);
6417 while (used_playlists.size() > 0) {
6418 list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
6420 used_playlists.pop_front();
6423 commit_reversible_command ();
6427 Editor::close_region_gaps ()
6429 list <boost::shared_ptr<Playlist > > used_playlists;
6431 RegionSelection rs = get_regions_from_selection_and_entered ();
6433 if (!_session || rs.empty()) {
6437 Dialog dialog (_("Close Region Gaps"));
6440 table.set_spacings (12);
6441 table.set_border_width (12);
6442 Label* l = manage (left_aligned_label (_("Crossfade length")));
6443 table.attach (*l, 0, 1, 0, 1);
6445 SpinButton spin_crossfade (1, 0);
6446 spin_crossfade.set_range (0, 15);
6447 spin_crossfade.set_increments (1, 1);
6448 spin_crossfade.set_value (5);
6449 table.attach (spin_crossfade, 1, 2, 0, 1);
6451 table.attach (*manage (new Label (_("ms"))), 2, 3, 0, 1);
6453 l = manage (left_aligned_label (_("Pull-back length")));
6454 table.attach (*l, 0, 1, 1, 2);
6456 SpinButton spin_pullback (1, 0);
6457 spin_pullback.set_range (0, 100);
6458 spin_pullback.set_increments (1, 1);
6459 spin_pullback.set_value(30);
6460 table.attach (spin_pullback, 1, 2, 1, 2);
6462 table.attach (*manage (new Label (_("ms"))), 2, 3, 1, 2);
6464 dialog.get_vbox()->pack_start (table);
6465 dialog.add_button (Stock::CANCEL, RESPONSE_CANCEL);
6466 dialog.add_button (_("Ok"), RESPONSE_ACCEPT);
6469 if (dialog.run () == RESPONSE_CANCEL) {
6473 framepos_t crossfade_len = spin_crossfade.get_value();
6474 framepos_t pull_back_frames = spin_pullback.get_value();
6476 crossfade_len = lrintf (crossfade_len * _session->frame_rate()/1000);
6477 pull_back_frames = lrintf (pull_back_frames * _session->frame_rate()/1000);
6479 /* Iterate over the region list and make adjacent regions overlap by crossfade_len_ms */
6481 begin_reversible_command (_("close region gaps"));
6484 boost::shared_ptr<Region> last_region;
6486 rs.sort_by_position_and_track();
6488 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6490 boost::shared_ptr<Playlist> pl = (*r)->region()->playlist();
6492 if (!pl->frozen()) {
6493 /* we haven't seen this playlist before */
6495 /* remember used playlists so we can thaw them later */
6496 used_playlists.push_back(pl);
6500 framepos_t position = (*r)->region()->position();
6502 if (idx == 0 || position < last_region->position()){
6503 last_region = (*r)->region();
6508 (*r)->region()->trim_front( (position - pull_back_frames));
6509 last_region->trim_end( (position - pull_back_frames + crossfade_len));
6511 last_region = (*r)->region();
6516 while (used_playlists.size() > 0) {
6517 list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
6519 used_playlists.pop_front();
6522 commit_reversible_command ();
6526 Editor::tab_to_transient (bool forward)
6528 AnalysisFeatureList positions;
6530 RegionSelection rs = get_regions_from_selection_and_entered ();
6536 framepos_t pos = _session->audible_frame ();
6538 if (!selection->tracks.empty()) {
6540 /* don't waste time searching for transients in duplicate playlists.
6543 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
6545 for (TrackViewList::iterator t = ts.begin(); t != ts.end(); ++t) {
6547 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*t);
6550 boost::shared_ptr<Track> tr = rtv->track();
6552 boost::shared_ptr<Playlist> pl = tr->playlist ();
6554 framepos_t result = pl->find_next_transient (pos, forward ? 1 : -1);
6557 positions.push_back (result);
6570 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6571 (*r)->region()->get_transients (positions);
6575 TransientDetector::cleanup_transients (positions, _session->frame_rate(), 3.0);
6578 AnalysisFeatureList::iterator x;
6580 for (x = positions.begin(); x != positions.end(); ++x) {
6586 if (x != positions.end ()) {
6587 _session->request_locate (*x);
6591 AnalysisFeatureList::reverse_iterator x;
6593 for (x = positions.rbegin(); x != positions.rend(); ++x) {
6599 if (x != positions.rend ()) {
6600 _session->request_locate (*x);
6606 Editor::playhead_forward_to_grid ()
6612 framepos_t pos = playhead_cursor->current_frame ();
6613 if (pos < max_framepos - 1) {
6615 snap_to_internal (pos, RoundUpAlways, false);
6616 _session->request_locate (pos);
6622 Editor::playhead_backward_to_grid ()
6628 framepos_t pos = playhead_cursor->current_frame ();
6631 snap_to_internal (pos, RoundDownAlways, false);
6632 _session->request_locate (pos);
6637 Editor::set_track_height (Height h)
6639 TrackSelection& ts (selection->tracks);
6641 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
6642 (*x)->set_height_enum (h);
6647 Editor::toggle_tracks_active ()
6649 TrackSelection& ts (selection->tracks);
6651 bool target = false;
6657 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
6658 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*x);
6662 target = !rtv->_route->active();
6665 rtv->_route->set_active (target, this);
6671 Editor::remove_tracks ()
6673 TrackSelection& ts (selection->tracks);
6679 vector<string> choices;
6683 const char* trackstr;
6685 vector<boost::shared_ptr<Route> > routes;
6686 bool special_bus = false;
6688 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
6689 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*x);
6693 if (rtv->is_track()) {
6698 routes.push_back (rtv->_route);
6700 if (rtv->route()->is_master() || rtv->route()->is_monitor()) {
6705 if (special_bus && !Config->get_allow_special_bus_removal()) {
6706 MessageDialog msg (_("That would be bad news ...."),
6710 msg.set_secondary_text (string_compose (_(
6711 "Removing the master or monitor bus is such a bad idea\n\
6712 that %1 is not going to allow it.\n\
6714 If you really want to do this sort of thing\n\
6715 edit your ardour.rc file to set the\n\
6716 \"allow-special-bus-removal\" option to be \"yes\""), PROGRAM_NAME));
6723 if (ntracks + nbusses == 0) {
6727 // XXX should be using gettext plural forms, maybe?
6729 trackstr = _("tracks");
6731 trackstr = _("track");
6735 busstr = _("busses");
6742 prompt = string_compose (_("Do you really want to remove %1 %2 and %3 %4?\n"
6743 "(You may also lose the playlists associated with the %2)\n\n"
6744 "This action cannot be undone, and the session file will be overwritten!"),
6745 ntracks, trackstr, nbusses, busstr);
6747 prompt = string_compose (_("Do you really want to remove %1 %2?\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!"),
6752 } else if (nbusses) {
6753 prompt = string_compose (_("Do you really want to remove %1 %2?\n\n"
6754 "This action cannot be undone, and the session file will be overwritten"),
6758 choices.push_back (_("No, do nothing."));
6759 if (ntracks + nbusses > 1) {
6760 choices.push_back (_("Yes, remove them."));
6762 choices.push_back (_("Yes, remove it."));
6767 title = string_compose (_("Remove %1"), trackstr);
6769 title = string_compose (_("Remove %1"), busstr);
6772 Choice prompter (title, prompt, choices);
6774 if (prompter.run () != 1) {
6779 Session::StateProtector sp (_session);
6780 DisplaySuspender ds;
6781 for (vector<boost::shared_ptr<Route> >::iterator x = routes.begin(); x != routes.end(); ++x) {
6782 _session->remove_route (*x);
6788 Editor::do_insert_time ()
6790 if (selection->tracks.empty()) {
6794 InsertTimeDialog d (*this);
6795 int response = d.run ();
6797 if (response != RESPONSE_OK) {
6801 if (d.distance() == 0) {
6805 InsertTimeOption opt = d.intersected_region_action ();
6808 get_preferred_edit_position(),
6814 d.move_glued_markers(),
6815 d.move_locked_markers(),
6821 Editor::insert_time (
6822 framepos_t pos, framecnt_t frames, InsertTimeOption opt,
6823 bool all_playlists, bool ignore_music_glue, bool markers_too, bool glued_markers_too, bool locked_markers_too, bool tempo_too
6826 bool commit = false;
6828 if (Config->get_edit_mode() == Lock) {
6832 begin_reversible_command (_("insert time"));
6834 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
6836 for (TrackViewList::iterator x = ts.begin(); x != ts.end(); ++x) {
6840 /* don't operate on any playlist more than once, which could
6841 * happen if "all playlists" is enabled, but there is more
6842 * than 1 track using playlists "from" a given track.
6845 set<boost::shared_ptr<Playlist> > pl;
6847 if (all_playlists) {
6848 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*x);
6850 vector<boost::shared_ptr<Playlist> > all = _session->playlists->playlists_for_track (rtav->track ());
6851 for (vector<boost::shared_ptr<Playlist> >::iterator p = all.begin(); p != all.end(); ++p) {
6856 if ((*x)->playlist ()) {
6857 pl.insert ((*x)->playlist ());
6861 for (set<boost::shared_ptr<Playlist> >::iterator i = pl.begin(); i != pl.end(); ++i) {
6863 (*i)->clear_changes ();
6864 (*i)->clear_owned_changes ();
6866 if (opt == SplitIntersected) {
6870 (*i)->shift (pos, frames, (opt == MoveIntersected), ignore_music_glue);
6872 vector<Command*> cmds;
6874 _session->add_commands (cmds);
6876 _session->add_command (new StatefulDiffCommand (*i));
6881 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*x);
6883 rtav->route ()->shift (pos, frames);
6891 XMLNode& before (_session->locations()->get_state());
6892 Locations::LocationList copy (_session->locations()->list());
6894 for (Locations::LocationList::iterator i = copy.begin(); i != copy.end(); ++i) {
6896 Locations::LocationList::const_iterator tmp;
6898 bool const was_locked = (*i)->locked ();
6899 if (locked_markers_too) {
6903 if ((*i)->position_lock_style() == AudioTime || glued_markers_too) {
6905 if ((*i)->start() >= pos) {
6906 (*i)->set_start ((*i)->start() + frames);
6907 if (!(*i)->is_mark()) {
6908 (*i)->set_end ((*i)->end() + frames);
6921 XMLNode& after (_session->locations()->get_state());
6922 _session->add_command (new MementoCommand<Locations>(*_session->locations(), &before, &after));
6927 _session->tempo_map().insert_time (pos, frames);
6931 commit_reversible_command ();
6936 Editor::fit_selected_tracks ()
6938 if (!selection->tracks.empty()) {
6939 fit_tracks (selection->tracks);
6943 /* no selected tracks - use tracks with selected regions */
6945 if (!selection->regions.empty()) {
6946 for (RegionSelection::iterator r = selection->regions.begin(); r != selection->regions.end(); ++r) {
6947 tvl.push_back (&(*r)->get_time_axis_view ());
6953 } else if (internal_editing()) {
6954 /* no selected tracks, or regions, but in internal edit mode, so follow the mouse and use
6957 if (entered_track) {
6958 tvl.push_back (entered_track);
6967 Editor::fit_tracks (TrackViewList & tracks)
6969 if (tracks.empty()) {
6973 uint32_t child_heights = 0;
6974 int visible_tracks = 0;
6976 for (TrackSelection::iterator t = tracks.begin(); t != tracks.end(); ++t) {
6978 if (!(*t)->marked_for_display()) {
6982 child_heights += (*t)->effective_height() - (*t)->current_height();
6986 /* compute the per-track height from:
6988 total canvas visible height -
6989 height that will be taken by visible children of selected
6990 tracks - height of the ruler/hscroll area
6992 uint32_t h = (uint32_t) floor ((trackviews_height() - child_heights) / visible_tracks);
6993 double first_y_pos = DBL_MAX;
6995 if (h < TimeAxisView::preset_height (HeightSmall)) {
6996 MessageDialog msg (*this, _("There are too many tracks to fit in the current window"));
6997 /* too small to be displayed */
7001 undo_visual_stack.push_back (current_visual_state (true));
7002 no_save_visual = true;
7004 /* build a list of all tracks, including children */
7007 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
7009 TimeAxisView::Children c = (*i)->get_child_list ();
7010 for (TimeAxisView::Children::iterator j = c.begin(); j != c.end(); ++j) {
7011 all.push_back (j->get());
7015 bool prev_was_selected = false;
7016 bool is_selected = tracks.contains (all.front());
7017 bool next_is_selected;
7019 for (TrackViewList::iterator t = all.begin(); t != all.end(); ++t) {
7021 TrackViewList::iterator next;
7026 if (next != all.end()) {
7027 next_is_selected = tracks.contains (*next);
7029 next_is_selected = false;
7032 if ((*t)->marked_for_display ()) {
7034 (*t)->set_height (h);
7035 first_y_pos = std::min ((*t)->y_position (), first_y_pos);
7037 if (prev_was_selected && next_is_selected) {
7038 hide_track_in_display (*t);
7043 prev_was_selected = is_selected;
7044 is_selected = next_is_selected;
7048 set the controls_layout height now, because waiting for its size
7049 request signal handler will cause the vertical adjustment setting to fail
7052 controls_layout.property_height () = _full_canvas_height;
7053 vertical_adjustment.set_value (first_y_pos);
7055 redo_visual_stack.push_back (current_visual_state (true));
7057 visible_tracks_selector.set_text (_("Sel"));
7061 Editor::save_visual_state (uint32_t n)
7063 while (visual_states.size() <= n) {
7064 visual_states.push_back (0);
7067 if (visual_states[n] != 0) {
7068 delete visual_states[n];
7071 visual_states[n] = current_visual_state (true);
7076 Editor::goto_visual_state (uint32_t n)
7078 if (visual_states.size() <= n) {
7082 if (visual_states[n] == 0) {
7086 use_visual_state (*visual_states[n]);
7090 Editor::start_visual_state_op (uint32_t n)
7092 save_visual_state (n);
7094 PopUp* pup = new PopUp (WIN_POS_MOUSE, 1000, true);
7096 snprintf (buf, sizeof (buf), _("Saved view %u"), n+1);
7097 pup->set_text (buf);
7102 Editor::cancel_visual_state_op (uint32_t n)
7104 goto_visual_state (n);
7108 Editor::toggle_region_mute ()
7110 if (_ignore_region_action) {
7114 RegionSelection rs = get_regions_from_selection_and_entered ();
7120 if (rs.size() > 1) {
7121 begin_reversible_command (_("mute regions"));
7123 begin_reversible_command (_("mute region"));
7126 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
7128 (*i)->region()->playlist()->clear_changes ();
7129 (*i)->region()->set_muted (!(*i)->region()->muted ());
7130 _session->add_command (new StatefulDiffCommand ((*i)->region()));
7134 commit_reversible_command ();
7138 Editor::combine_regions ()
7140 /* foreach track with selected regions, take all selected regions
7141 and join them into a new region containing the subregions (as a
7145 typedef set<RouteTimeAxisView*> RTVS;
7148 if (selection->regions.empty()) {
7152 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
7153 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(&(*i)->get_time_axis_view());
7156 tracks.insert (rtv);
7160 begin_reversible_command (_("combine regions"));
7162 vector<RegionView*> new_selection;
7164 for (RTVS::iterator i = tracks.begin(); i != tracks.end(); ++i) {
7167 if ((rv = (*i)->combine_regions ()) != 0) {
7168 new_selection.push_back (rv);
7172 selection->clear_regions ();
7173 for (vector<RegionView*>::iterator i = new_selection.begin(); i != new_selection.end(); ++i) {
7174 selection->add (*i);
7177 commit_reversible_command ();
7181 Editor::uncombine_regions ()
7183 typedef set<RouteTimeAxisView*> RTVS;
7186 if (selection->regions.empty()) {
7190 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
7191 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(&(*i)->get_time_axis_view());
7194 tracks.insert (rtv);
7198 begin_reversible_command (_("uncombine regions"));
7200 for (RTVS::iterator i = tracks.begin(); i != tracks.end(); ++i) {
7201 (*i)->uncombine_regions ();
7204 commit_reversible_command ();
7208 Editor::toggle_midi_input_active (bool flip_others)
7211 boost::shared_ptr<RouteList> rl (new RouteList);
7213 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
7214 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
7220 boost::shared_ptr<MidiTrack> mt = rtav->midi_track();
7223 rl->push_back (rtav->route());
7224 onoff = !mt->input_active();
7228 _session->set_exclusive_input_active (rl, onoff, flip_others);
7235 lock_dialog = new Gtk::Dialog (string_compose (_("%1: Locked"), PROGRAM_NAME), true);
7237 Gtk::Image* padlock = manage (new Gtk::Image (ARDOUR_UI_UTILS::get_icon ("padlock_closed")));
7238 lock_dialog->get_vbox()->pack_start (*padlock);
7240 ArdourButton* b = manage (new ArdourButton);
7241 b->set_name ("lock button");
7242 b->set_text (_("Click to unlock"));
7243 b->signal_clicked.connect (sigc::mem_fun (*this, &Editor::unlock));
7244 lock_dialog->get_vbox()->pack_start (*b);
7246 lock_dialog->get_vbox()->show_all ();
7247 lock_dialog->set_size_request (200, 200);
7251 /* The global menu bar continues to be accessible to applications
7252 with modal dialogs, which means that we need to desensitize
7253 all items in the menu bar. Since those items are really just
7254 proxies for actions, that means disabling all actions.
7256 ActionManager::disable_all_actions ();
7258 lock_dialog->present ();
7264 lock_dialog->hide ();
7267 ActionManager::pop_action_state ();
7270 if (ARDOUR_UI::config()->get_lock_gui_after_seconds()) {
7271 start_lock_event_timing ();
7276 Editor::bring_in_callback (Gtk::Label* label, uint32_t n, uint32_t total, string name)
7278 Gtkmm2ext::UI::instance()->call_slot (invalidator (*this), boost::bind (&Editor::update_bring_in_message, this, label, n, total, name));
7282 Editor::update_bring_in_message (Gtk::Label* label, uint32_t n, uint32_t total, string name)
7284 label->set_text (string_compose ("Copying %1, %2 of %3", name, n, total));
7285 Gtkmm2ext::UI::instance()->flush_pending ();
7289 Editor::bring_all_sources_into_session ()
7296 ArdourDialog w (_("Moving embedded files into session folder"));
7297 w.get_vbox()->pack_start (msg);
7300 /* flush all pending GUI events because we're about to start copying
7304 Gtkmm2ext::UI::instance()->flush_pending ();
7308 _session->bring_all_sources_into_session (boost::bind (&Editor::bring_in_callback, this, &msg, _1, _2, _3));