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 */
30 #include "pbd/error.h"
31 #include "pbd/basename.h"
32 #include "pbd/pthread_utils.h"
33 #include "pbd/memento_command.h"
34 #include "pbd/unwind.h"
35 #include "pbd/whitespace.h"
36 #include "pbd/stateful_diff_command.h"
38 #include <gtkmm2ext/utils.h>
39 #include <gtkmm2ext/choice.h>
40 #include <gtkmm2ext/popup.h>
42 #include "ardour/audio_track.h"
43 #include "ardour/audioregion.h"
44 #include "ardour/dB.h"
45 #include "ardour/location.h"
46 #include "ardour/midi_region.h"
47 #include "ardour/midi_track.h"
48 #include "ardour/operations.h"
49 #include "ardour/playlist_factory.h"
50 #include "ardour/quantize.h"
51 #include "ardour/region_factory.h"
52 #include "ardour/reverse.h"
53 #include "ardour/session.h"
54 #include "ardour/session_playlists.h"
55 #include "ardour/strip_silence.h"
56 #include "ardour/transient_detector.h"
58 #include "canvas/canvas.h"
61 #include "ardour_ui.h"
62 #include "audio_region_view.h"
63 #include "audio_streamview.h"
64 #include "audio_time_axis.h"
65 #include "automation_time_axis.h"
66 #include "control_point.h"
70 #include "editor_cursors.h"
71 #include "editor_drag.h"
72 #include "editor_regions.h"
73 #include "editor_routes.h"
74 #include "gui_thread.h"
75 #include "insert_time_dialog.h"
76 #include "interthread_progress_window.h"
78 #include "midi_region_view.h"
79 #include "mouse_cursors.h"
80 #include "normalize_dialog.h"
81 #include "patch_change_dialog.h"
82 #include "quantize_dialog.h"
83 #include "region_gain_line.h"
84 #include "rgb_macros.h"
85 #include "route_time_axis.h"
86 #include "selection.h"
87 #include "selection_templates.h"
88 #include "streamview.h"
89 #include "strip_silence_dialog.h"
90 #include "time_axis_view.h"
91 #include "transpose_dialog.h"
96 using namespace ARDOUR;
99 using namespace Gtkmm2ext;
100 using namespace Editing;
101 using Gtkmm2ext::Keyboard;
103 /***********************************************************************
105 ***********************************************************************/
108 Editor::undo (uint32_t n)
110 if (_drags->active ()) {
120 Editor::redo (uint32_t n)
122 if (_drags->active ()) {
132 Editor::split_regions_at (framepos_t where, RegionSelection& regions)
136 list<boost::shared_ptr<Playlist> > used_playlists;
137 list<RouteTimeAxisView*> used_trackviews;
139 if (regions.empty()) {
143 begin_reversible_command (_("split"));
145 // if splitting a single region, and snap-to is using
146 // region boundaries, don't pay attention to them
148 if (regions.size() == 1) {
149 switch (_snap_type) {
150 case SnapToRegionStart:
151 case SnapToRegionSync:
152 case SnapToRegionEnd:
161 EditorFreeze(); /* Emit Signal */
164 for (RegionSelection::iterator a = regions.begin(); a != regions.end(); ) {
166 RegionSelection::iterator tmp;
168 /* XXX this test needs to be more complicated, to make sure we really
169 have something to split.
172 if (!(*a)->region()->covers (where)) {
180 boost::shared_ptr<Playlist> pl = (*a)->region()->playlist();
188 /* we haven't seen this playlist before */
190 /* remember used playlists so we can thaw them later */
191 used_playlists.push_back(pl);
193 TimeAxisView& tv = (*a)->get_time_axis_view();
194 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (&tv);
196 used_trackviews.push_back (rtv);
203 pl->clear_changes ();
204 pl->split_region ((*a)->region(), where);
205 _session->add_command (new StatefulDiffCommand (pl));
211 vector<sigc::connection> region_added_connections;
213 for (list<RouteTimeAxisView*>::iterator i = used_trackviews.begin(); i != used_trackviews.end(); ++i) {
214 region_added_connections.push_back ((*i)->view()->RegionViewAdded.connect (sigc::mem_fun(*this, &Editor::collect_new_region_view)));
217 latest_regionviews.clear ();
219 while (used_playlists.size() > 0) {
220 list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
222 used_playlists.pop_front();
225 for (vector<sigc::connection>::iterator c = region_added_connections.begin(); c != region_added_connections.end(); ++c) {
229 commit_reversible_command ();
232 EditorThaw(); /* Emit Signal */
235 if (!latest_regionviews.empty()) {
236 selection->add (latest_regionviews);
241 /** Move one extreme of the current range selection. If more than one range is selected,
242 * the start of the earliest range or the end of the latest range is moved.
244 * @param move_end true to move the end of the current range selection, false to move
246 * @param next true to move the extreme to the next region boundary, false to move to
250 Editor::move_range_selection_start_or_end_to_region_boundary (bool move_end, bool next)
252 if (selection->time.start() == selection->time.end_frame()) {
256 framepos_t start = selection->time.start ();
257 framepos_t end = selection->time.end_frame ();
259 /* the position of the thing we may move */
260 framepos_t pos = move_end ? end : start;
261 int dir = next ? 1 : -1;
263 /* so we don't find the current region again */
264 if (dir > 0 || pos > 0) {
268 framepos_t const target = get_region_boundary (pos, dir, true, false);
283 begin_reversible_command (_("alter selection"));
284 selection->set_preserving_all_ranges (start, end);
285 commit_reversible_command ();
289 Editor::nudge_forward_release (GdkEventButton* ev)
291 if (ev->state & Keyboard::PrimaryModifier) {
292 nudge_forward (false, true);
294 nudge_forward (false, false);
300 Editor::nudge_backward_release (GdkEventButton* ev)
302 if (ev->state & Keyboard::PrimaryModifier) {
303 nudge_backward (false, true);
305 nudge_backward (false, false);
312 Editor::nudge_forward (bool next, bool force_playhead)
315 framepos_t next_distance;
321 RegionSelection rs = get_regions_from_selection_and_entered ();
323 if (!force_playhead && !rs.empty()) {
325 begin_reversible_command (_("nudge regions forward"));
327 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
328 boost::shared_ptr<Region> r ((*i)->region());
330 distance = get_nudge_distance (r->position(), next_distance);
333 distance = next_distance;
337 r->set_position (r->position() + distance);
338 _session->add_command (new StatefulDiffCommand (r));
341 commit_reversible_command ();
344 } else if (!force_playhead && !selection->markers.empty()) {
348 begin_reversible_command (_("nudge location forward"));
350 for (MarkerSelection::iterator i = selection->markers.begin(); i != selection->markers.end(); ++i) {
352 Location* loc = find_location_from_marker ((*i), is_start);
356 XMLNode& before (loc->get_state());
359 distance = get_nudge_distance (loc->start(), next_distance);
361 distance = next_distance;
363 if (max_framepos - distance > loc->start() + loc->length()) {
364 loc->set_start (loc->start() + distance);
366 loc->set_start (max_framepos - loc->length());
369 distance = get_nudge_distance (loc->end(), next_distance);
371 distance = next_distance;
373 if (max_framepos - distance > loc->end()) {
374 loc->set_end (loc->end() + distance);
376 loc->set_end (max_framepos);
379 XMLNode& after (loc->get_state());
380 _session->add_command (new MementoCommand<Location>(*loc, &before, &after));
384 commit_reversible_command ();
387 distance = get_nudge_distance (playhead_cursor->current_frame (), next_distance);
388 _session->request_locate (playhead_cursor->current_frame () + distance);
393 Editor::nudge_backward (bool next, bool force_playhead)
396 framepos_t next_distance;
402 RegionSelection rs = get_regions_from_selection_and_entered ();
404 if (!force_playhead && !rs.empty()) {
406 begin_reversible_command (_("nudge regions backward"));
408 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
409 boost::shared_ptr<Region> r ((*i)->region());
411 distance = get_nudge_distance (r->position(), next_distance);
414 distance = next_distance;
419 if (r->position() > distance) {
420 r->set_position (r->position() - distance);
424 _session->add_command (new StatefulDiffCommand (r));
427 commit_reversible_command ();
429 } else if (!force_playhead && !selection->markers.empty()) {
433 begin_reversible_command (_("nudge location forward"));
435 for (MarkerSelection::iterator i = selection->markers.begin(); i != selection->markers.end(); ++i) {
437 Location* loc = find_location_from_marker ((*i), is_start);
441 XMLNode& before (loc->get_state());
444 distance = get_nudge_distance (loc->start(), next_distance);
446 distance = next_distance;
448 if (distance < loc->start()) {
449 loc->set_start (loc->start() - distance);
454 distance = get_nudge_distance (loc->end(), next_distance);
457 distance = next_distance;
460 if (distance < loc->end() - loc->length()) {
461 loc->set_end (loc->end() - distance);
463 loc->set_end (loc->length());
467 XMLNode& after (loc->get_state());
468 _session->add_command (new MementoCommand<Location>(*loc, &before, &after));
472 commit_reversible_command ();
476 distance = get_nudge_distance (playhead_cursor->current_frame (), next_distance);
478 if (playhead_cursor->current_frame () > distance) {
479 _session->request_locate (playhead_cursor->current_frame () - distance);
481 _session->goto_start();
487 Editor::nudge_forward_capture_offset ()
489 RegionSelection rs = get_regions_from_selection_and_entered ();
491 if (!_session || rs.empty()) {
495 begin_reversible_command (_("nudge forward"));
497 framepos_t const distance = _session->worst_output_latency();
499 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
500 boost::shared_ptr<Region> r ((*i)->region());
503 r->set_position (r->position() + distance);
504 _session->add_command(new StatefulDiffCommand (r));
507 commit_reversible_command ();
511 Editor::nudge_backward_capture_offset ()
513 RegionSelection rs = get_regions_from_selection_and_entered ();
515 if (!_session || rs.empty()) {
519 begin_reversible_command (_("nudge backward"));
521 framepos_t const distance = _session->worst_output_latency();
523 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
524 boost::shared_ptr<Region> r ((*i)->region());
528 if (r->position() > distance) {
529 r->set_position (r->position() - distance);
533 _session->add_command(new StatefulDiffCommand (r));
536 commit_reversible_command ();
539 struct RegionSelectionPositionSorter {
540 bool operator() (RegionView* a, RegionView* b) {
541 return a->region()->position() < b->region()->position();
546 Editor::sequence_regions ()
549 framepos_t r_end_prev;
557 RegionSelection rs = get_regions_from_selection_and_entered ();
558 rs.sort(RegionSelectionPositionSorter());
562 begin_reversible_command (_("sequence regions"));
563 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
564 boost::shared_ptr<Region> r ((*i)->region());
572 if(r->position_locked())
579 r->set_position(r_end_prev);
582 _session->add_command (new StatefulDiffCommand (r));
584 r_end=r->position() + r->length();
588 commit_reversible_command ();
596 Editor::move_to_start ()
598 _session->goto_start ();
602 Editor::move_to_end ()
605 _session->request_locate (_session->current_end_frame());
609 Editor::build_region_boundary_cache ()
612 vector<RegionPoint> interesting_points;
613 boost::shared_ptr<Region> r;
614 TrackViewList tracks;
617 region_boundary_cache.clear ();
623 switch (_snap_type) {
624 case SnapToRegionStart:
625 interesting_points.push_back (Start);
627 case SnapToRegionEnd:
628 interesting_points.push_back (End);
630 case SnapToRegionSync:
631 interesting_points.push_back (SyncPoint);
633 case SnapToRegionBoundary:
634 interesting_points.push_back (Start);
635 interesting_points.push_back (End);
638 fatal << string_compose (_("build_region_boundary_cache called with snap_type = %1"), _snap_type) << endmsg;
643 TimeAxisView *ontrack = 0;
646 if (!selection->tracks.empty()) {
647 tlist = selection->tracks.filter_to_unique_playlists ();
649 tlist = track_views.filter_to_unique_playlists ();
652 while (pos < _session->current_end_frame() && !at_end) {
655 framepos_t lpos = max_framepos;
657 for (vector<RegionPoint>::iterator p = interesting_points.begin(); p != interesting_points.end(); ++p) {
659 if ((r = find_next_region (pos, *p, 1, tlist, &ontrack)) == 0) {
660 if (*p == interesting_points.back()) {
663 /* move to next point type */
669 rpos = r->first_frame();
673 rpos = r->last_frame();
677 rpos = r->sync_position ();
685 RouteTimeAxisView *rtav;
687 if (ontrack != 0 && (rtav = dynamic_cast<RouteTimeAxisView*>(ontrack)) != 0 ) {
688 if (rtav->track() != 0) {
689 speed = rtav->track()->speed();
693 rpos = track_frame_to_session_frame (rpos, speed);
699 /* prevent duplicates, but we don't use set<> because we want to be able
703 vector<framepos_t>::iterator ri;
705 for (ri = region_boundary_cache.begin(); ri != region_boundary_cache.end(); ++ri) {
711 if (ri == region_boundary_cache.end()) {
712 region_boundary_cache.push_back (rpos);
719 /* finally sort to be sure that the order is correct */
721 sort (region_boundary_cache.begin(), region_boundary_cache.end());
724 boost::shared_ptr<Region>
725 Editor::find_next_region (framepos_t frame, RegionPoint point, int32_t dir, TrackViewList& tracks, TimeAxisView **ontrack)
727 TrackViewList::iterator i;
728 framepos_t closest = max_framepos;
729 boost::shared_ptr<Region> ret;
733 framepos_t track_frame;
734 RouteTimeAxisView *rtav;
736 for (i = tracks.begin(); i != tracks.end(); ++i) {
739 boost::shared_ptr<Region> r;
742 if ( (rtav = dynamic_cast<RouteTimeAxisView*>(*i)) != 0 ) {
743 if (rtav->track()!=0)
744 track_speed = rtav->track()->speed();
747 track_frame = session_frame_to_track_frame(frame, track_speed);
749 if ((r = (*i)->find_next_region (track_frame, point, dir)) == 0) {
755 rpos = r->first_frame ();
759 rpos = r->last_frame ();
763 rpos = r->sync_position ();
767 // rpos is a "track frame", converting it to "_session frame"
768 rpos = track_frame_to_session_frame(rpos, track_speed);
771 distance = rpos - frame;
773 distance = frame - rpos;
776 if (distance < closest) {
788 Editor::find_next_region_boundary (framepos_t pos, int32_t dir, const TrackViewList& tracks)
790 framecnt_t distance = max_framepos;
791 framepos_t current_nearest = -1;
793 for (TrackViewList::const_iterator i = tracks.begin(); i != tracks.end(); ++i) {
794 framepos_t contender;
797 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*i);
803 if ((contender = rtv->find_next_region_boundary (pos, dir)) < 0) {
807 d = ::llabs (pos - contender);
810 current_nearest = contender;
815 return current_nearest;
819 Editor::get_region_boundary (framepos_t pos, int32_t dir, bool with_selection, bool only_onscreen)
824 if (with_selection && Config->get_region_boundaries_from_selected_tracks()) {
826 if (!selection->tracks.empty()) {
828 target = find_next_region_boundary (pos, dir, selection->tracks);
832 if (only_onscreen || Config->get_region_boundaries_from_onscreen_tracks()) {
833 get_onscreen_tracks (tvl);
834 target = find_next_region_boundary (pos, dir, tvl);
836 target = find_next_region_boundary (pos, dir, track_views);
842 if (only_onscreen || Config->get_region_boundaries_from_onscreen_tracks()) {
843 get_onscreen_tracks (tvl);
844 target = find_next_region_boundary (pos, dir, tvl);
846 target = find_next_region_boundary (pos, dir, track_views);
854 Editor::cursor_to_region_boundary (bool with_selection, int32_t dir)
856 framepos_t pos = playhead_cursor->current_frame ();
863 // so we don't find the current region again..
864 if (dir > 0 || pos > 0) {
868 if ((target = get_region_boundary (pos, dir, with_selection, false)) < 0) {
872 _session->request_locate (target);
876 Editor::cursor_to_next_region_boundary (bool with_selection)
878 cursor_to_region_boundary (with_selection, 1);
882 Editor::cursor_to_previous_region_boundary (bool with_selection)
884 cursor_to_region_boundary (with_selection, -1);
888 Editor::cursor_to_region_point (EditorCursor* cursor, RegionPoint point, int32_t dir)
890 boost::shared_ptr<Region> r;
891 framepos_t pos = cursor->current_frame ();
897 TimeAxisView *ontrack = 0;
899 // so we don't find the current region again..
903 if (!selection->tracks.empty()) {
905 r = find_next_region (pos, point, dir, selection->tracks, &ontrack);
907 } else if (clicked_axisview) {
910 t.push_back (clicked_axisview);
912 r = find_next_region (pos, point, dir, t, &ontrack);
916 r = find_next_region (pos, point, dir, track_views, &ontrack);
925 pos = r->first_frame ();
929 pos = r->last_frame ();
933 pos = r->sync_position ();
938 RouteTimeAxisView *rtav;
940 if ( ontrack != 0 && (rtav = dynamic_cast<RouteTimeAxisView*>(ontrack)) != 0 ) {
941 if (rtav->track() != 0) {
942 speed = rtav->track()->speed();
946 pos = track_frame_to_session_frame(pos, speed);
948 if (cursor == playhead_cursor) {
949 _session->request_locate (pos);
951 cursor->set_position (pos);
956 Editor::cursor_to_next_region_point (EditorCursor* cursor, RegionPoint point)
958 cursor_to_region_point (cursor, point, 1);
962 Editor::cursor_to_previous_region_point (EditorCursor* cursor, RegionPoint point)
964 cursor_to_region_point (cursor, point, -1);
968 Editor::cursor_to_selection_start (EditorCursor *cursor)
972 switch (mouse_mode) {
974 if (!selection->regions.empty()) {
975 pos = selection->regions.start();
980 if (!selection->time.empty()) {
981 pos = selection->time.start ();
989 if (cursor == playhead_cursor) {
990 _session->request_locate (pos);
992 cursor->set_position (pos);
997 Editor::cursor_to_selection_end (EditorCursor *cursor)
1001 switch (mouse_mode) {
1003 if (!selection->regions.empty()) {
1004 pos = selection->regions.end_frame();
1009 if (!selection->time.empty()) {
1010 pos = selection->time.end_frame ();
1018 if (cursor == playhead_cursor) {
1019 _session->request_locate (pos);
1021 cursor->set_position (pos);
1026 Editor::selected_marker_to_region_boundary (bool with_selection, int32_t dir)
1036 if (selection->markers.empty()) {
1040 if (!mouse_frame (mouse, ignored)) {
1044 add_location_mark (mouse);
1047 if ((loc = find_location_from_marker (selection->markers.front(), ignored)) == 0) {
1051 framepos_t pos = loc->start();
1053 // so we don't find the current region again..
1054 if (dir > 0 || pos > 0) {
1058 if ((target = get_region_boundary (pos, dir, with_selection, false)) < 0) {
1062 loc->move_to (target);
1066 Editor::selected_marker_to_next_region_boundary (bool with_selection)
1068 selected_marker_to_region_boundary (with_selection, 1);
1072 Editor::selected_marker_to_previous_region_boundary (bool with_selection)
1074 selected_marker_to_region_boundary (with_selection, -1);
1078 Editor::selected_marker_to_region_point (RegionPoint point, int32_t dir)
1080 boost::shared_ptr<Region> r;
1085 if (!_session || selection->markers.empty()) {
1089 if ((loc = find_location_from_marker (selection->markers.front(), ignored)) == 0) {
1093 TimeAxisView *ontrack = 0;
1097 // so we don't find the current region again..
1101 if (!selection->tracks.empty()) {
1103 r = find_next_region (pos, point, dir, selection->tracks, &ontrack);
1107 r = find_next_region (pos, point, dir, track_views, &ontrack);
1116 pos = r->first_frame ();
1120 pos = r->last_frame ();
1124 pos = r->adjust_to_sync (r->first_frame());
1129 RouteTimeAxisView *rtav;
1131 if (ontrack != 0 && (rtav = dynamic_cast<RouteTimeAxisView*>(ontrack)) != 0) {
1132 if (rtav->track() != 0) {
1133 speed = rtav->track()->speed();
1137 pos = track_frame_to_session_frame(pos, speed);
1143 Editor::selected_marker_to_next_region_point (RegionPoint point)
1145 selected_marker_to_region_point (point, 1);
1149 Editor::selected_marker_to_previous_region_point (RegionPoint point)
1151 selected_marker_to_region_point (point, -1);
1155 Editor::selected_marker_to_selection_start ()
1161 if (!_session || selection->markers.empty()) {
1165 if ((loc = find_location_from_marker (selection->markers.front(), ignored)) == 0) {
1169 switch (mouse_mode) {
1171 if (!selection->regions.empty()) {
1172 pos = selection->regions.start();
1177 if (!selection->time.empty()) {
1178 pos = selection->time.start ();
1190 Editor::selected_marker_to_selection_end ()
1196 if (!_session || selection->markers.empty()) {
1200 if ((loc = find_location_from_marker (selection->markers.front(), ignored)) == 0) {
1204 switch (mouse_mode) {
1206 if (!selection->regions.empty()) {
1207 pos = selection->regions.end_frame();
1212 if (!selection->time.empty()) {
1213 pos = selection->time.end_frame ();
1225 Editor::scroll_playhead (bool forward)
1227 framepos_t pos = playhead_cursor->current_frame ();
1228 framecnt_t delta = (framecnt_t) floor (current_page_samples() / 0.8);
1231 if (pos == max_framepos) {
1235 if (pos < max_framepos - delta) {
1254 _session->request_locate (pos);
1258 Editor::cursor_align (bool playhead_to_edit)
1264 if (playhead_to_edit) {
1266 if (selection->markers.empty()) {
1270 _session->request_locate (selection->markers.front()->position(), _session->transport_rolling());
1273 /* move selected markers to playhead */
1275 for (MarkerSelection::iterator i = selection->markers.begin(); i != selection->markers.end(); ++i) {
1278 Location* loc = find_location_from_marker (*i, ignored);
1280 if (loc->is_mark()) {
1281 loc->set_start (playhead_cursor->current_frame ());
1283 loc->set (playhead_cursor->current_frame (),
1284 playhead_cursor->current_frame () + loc->length());
1291 Editor::scroll_backward (float pages)
1293 framepos_t const one_page = (framepos_t) rint (_visible_canvas_width * samples_per_pixel);
1294 framepos_t const cnt = (framepos_t) floor (pages * one_page);
1297 if (leftmost_frame < cnt) {
1300 frame = leftmost_frame - cnt;
1303 reset_x_origin (frame);
1307 Editor::scroll_forward (float pages)
1309 framepos_t const one_page = (framepos_t) rint (_visible_canvas_width * samples_per_pixel);
1310 framepos_t const cnt = (framepos_t) floor (pages * one_page);
1313 if (max_framepos - cnt < leftmost_frame) {
1314 frame = max_framepos - cnt;
1316 frame = leftmost_frame + cnt;
1319 reset_x_origin (frame);
1323 Editor::scroll_tracks_down ()
1325 double vert_value = vertical_adjustment.get_value() + vertical_adjustment.get_page_size();
1326 if (vert_value > vertical_adjustment.get_upper() - _visible_canvas_height) {
1327 vert_value = vertical_adjustment.get_upper() - _visible_canvas_height;
1330 vertical_adjustment.set_value (vert_value);
1334 Editor::scroll_tracks_up ()
1336 vertical_adjustment.set_value (vertical_adjustment.get_value() - vertical_adjustment.get_page_size());
1340 Editor::scroll_tracks_down_line ()
1342 double vert_value = vertical_adjustment.get_value() + 60;
1344 if (vert_value > vertical_adjustment.get_upper() - _visible_canvas_height) {
1345 vert_value = vertical_adjustment.get_upper() - _visible_canvas_height;
1348 vertical_adjustment.set_value (vert_value);
1352 Editor::scroll_tracks_up_line ()
1354 reset_y_origin (vertical_adjustment.get_value() - 60);
1358 Editor::scroll_down_one_track ()
1360 TrackViewList::reverse_iterator next = track_views.rend();
1361 std::pair<TimeAxisView*,double> res;
1362 const double bottom_of_trackviews = vertical_adjustment.get_value() + vertical_adjustment.get_page_size() - 1;
1364 for (TrackViewList::reverse_iterator t = track_views.rbegin(); t != track_views.rend(); ++t) {
1365 if ((*t)->hidden()) {
1369 /* If this is the bottom visible trackview, we want to display
1373 res = (*t)->covers_y_position (bottom_of_trackviews);
1379 ++next; // moves "next" towards the "front" since it is a reverse iterator
1382 /* move to the track below the first one that covers the */
1384 if (next != track_views.rend()) {
1385 ensure_time_axis_view_is_visible (**next);
1393 Editor::scroll_up_one_track ()
1395 double vertical_pos = vertical_adjustment.get_value ();
1397 TrackViewList::iterator prev = track_views.end();
1398 std::pair<TimeAxisView*,double> res;
1400 for (TrackViewList::iterator t = track_views.begin(); t != track_views.end(); ++t) {
1402 if ((*t)->hidden()) {
1406 /* find the trackview at the top of the trackview group */
1407 res = (*t)->covers_y_position (vertical_pos);
1410 cerr << res.first->name() << " covers the top\n";
1417 if (prev != track_views.end()) {
1418 ensure_time_axis_view_is_visible (**prev);
1428 Editor::tav_zoom_step (bool coarser)
1430 DisplaySuspender ds;
1434 if (selection->tracks.empty()) {
1437 ts = &selection->tracks;
1440 for (TrackViewList::iterator i = ts->begin(); i != ts->end(); ++i) {
1441 TimeAxisView *tv = (static_cast<TimeAxisView*>(*i));
1442 tv->step_height (coarser);
1447 Editor::tav_zoom_smooth (bool coarser, bool force_all)
1449 DisplaySuspender ds;
1453 if (selection->tracks.empty() || force_all) {
1456 ts = &selection->tracks;
1459 for (TrackViewList::iterator i = ts->begin(); i != ts->end(); ++i) {
1460 TimeAxisView *tv = (static_cast<TimeAxisView*>(*i));
1461 uint32_t h = tv->current_height ();
1466 if (h >= TimeAxisView::preset_height (HeightSmall)) {
1471 tv->set_height (h + 5);
1478 Editor::temporal_zoom_step (bool coarser)
1480 ENSURE_GUI_THREAD (*this, &Editor::temporal_zoom_step, coarser)
1482 framecnt_t nspp = samples_per_pixel;
1490 temporal_zoom (nspp);
1494 Editor::temporal_zoom (framecnt_t fpp)
1500 framepos_t current_page = current_page_samples();
1501 framepos_t current_leftmost = leftmost_frame;
1502 framepos_t current_rightmost;
1503 framepos_t current_center;
1504 framepos_t new_page_size;
1505 framepos_t half_page_size;
1506 framepos_t leftmost_after_zoom = 0;
1508 bool in_track_canvas;
1512 if (fpp == samples_per_pixel) {
1516 // Imposing an arbitrary limit to zoom out as too much zoom out produces
1517 // segfaults for lack of memory. If somebody decides this is not high enough I
1518 // believe it can be raisen to higher values but some limit must be in place.
1520 // This constant represents 1 day @ 48kHz on a 1600 pixel wide display
1521 // all of which is used for the editor track displays. The whole day
1522 // would be 4147200000 samples, so 2592000 samples per pixel.
1524 nfpp = min (fpp, (framecnt_t) 2592000);
1525 nfpp = max ((framecnt_t) 1, fpp);
1527 new_page_size = (framepos_t) floor (_visible_canvas_width * nfpp);
1528 half_page_size = new_page_size / 2;
1530 switch (zoom_focus) {
1532 leftmost_after_zoom = current_leftmost;
1535 case ZoomFocusRight:
1536 current_rightmost = leftmost_frame + current_page;
1537 if (current_rightmost < new_page_size) {
1538 leftmost_after_zoom = 0;
1540 leftmost_after_zoom = current_rightmost - new_page_size;
1544 case ZoomFocusCenter:
1545 current_center = current_leftmost + (current_page/2);
1546 if (current_center < half_page_size) {
1547 leftmost_after_zoom = 0;
1549 leftmost_after_zoom = current_center - half_page_size;
1553 case ZoomFocusPlayhead:
1554 /* centre playhead */
1555 l = playhead_cursor->current_frame () - (new_page_size * 0.5);
1558 leftmost_after_zoom = 0;
1559 } else if (l > max_framepos) {
1560 leftmost_after_zoom = max_framepos - new_page_size;
1562 leftmost_after_zoom = (framepos_t) l;
1566 case ZoomFocusMouse:
1567 /* try to keep the mouse over the same point in the display */
1569 if (!mouse_frame (where, in_track_canvas)) {
1570 /* use playhead instead */
1571 where = playhead_cursor->current_frame ();
1573 if (where < half_page_size) {
1574 leftmost_after_zoom = 0;
1576 leftmost_after_zoom = where - half_page_size;
1581 l = - ((new_page_size * ((where - current_leftmost)/(double)current_page)) - where);
1584 leftmost_after_zoom = 0;
1585 } else if (l > max_framepos) {
1586 leftmost_after_zoom = max_framepos - new_page_size;
1588 leftmost_after_zoom = (framepos_t) l;
1595 /* try to keep the edit point in the same place */
1596 where = get_preferred_edit_position ();
1600 double l = - ((new_page_size * ((where - current_leftmost)/(double)current_page)) - where);
1603 leftmost_after_zoom = 0;
1604 } else if (l > max_framepos) {
1605 leftmost_after_zoom = max_framepos - new_page_size;
1607 leftmost_after_zoom = (framepos_t) l;
1611 /* edit point not defined */
1618 // leftmost_after_zoom = min (leftmost_after_zoom, _session->current_end_frame());
1620 reposition_and_zoom (leftmost_after_zoom, nfpp);
1624 Editor::temporal_zoom_region (bool both_axes)
1626 framepos_t start = max_framepos;
1628 set<TimeAxisView*> tracks;
1630 RegionSelection rs = get_regions_from_selection_and_entered ();
1636 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
1638 if ((*i)->region()->position() < start) {
1639 start = (*i)->region()->position();
1642 if ((*i)->region()->last_frame() + 1 > end) {
1643 end = (*i)->region()->last_frame() + 1;
1646 tracks.insert (&((*i)->get_time_axis_view()));
1649 /* now comes an "interesting" hack ... make sure we leave a little space
1650 at each end of the editor so that the zoom doesn't fit the region
1651 precisely to the screen.
1654 GdkScreen* screen = gdk_screen_get_default ();
1655 gint pixwidth = gdk_screen_get_width (screen);
1656 gint mmwidth = gdk_screen_get_width_mm (screen);
1657 double pix_per_mm = (double) pixwidth/ (double) mmwidth;
1658 double one_centimeter_in_pixels = pix_per_mm * 10.0;
1660 if ((start == 0 && end == 0) || end < start) {
1664 framepos_t range = end - start;
1665 double new_fpp = (double) range / (double) _visible_canvas_width;
1666 framepos_t extra_samples = (framepos_t) floor (one_centimeter_in_pixels * new_fpp);
1668 if (start > extra_samples) {
1669 start -= extra_samples;
1674 if (max_framepos - extra_samples > end) {
1675 end += extra_samples;
1680 /* if we're zooming on both axes we need to save track heights etc.
1683 undo_visual_stack.push_back (current_visual_state (both_axes));
1685 PBD::Unwinder<bool> nsv (no_save_visual, true);
1687 temporal_zoom_by_frame (start, end);
1690 uint32_t per_track_height = (uint32_t) floor ((_visible_canvas_height - 10.0) / tracks.size());
1692 /* set visible track heights appropriately */
1694 for (set<TimeAxisView*>::iterator t = tracks.begin(); t != tracks.end(); ++t) {
1695 (*t)->set_height (per_track_height);
1698 /* hide irrelevant tracks */
1700 DisplaySuspender ds;
1702 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1703 if (find (tracks.begin(), tracks.end(), (*i)) == tracks.end()) {
1704 hide_track_in_display (*i);
1708 vertical_adjustment.set_value (0.0);
1711 redo_visual_stack.push_back (current_visual_state (both_axes));
1715 Editor::zoom_to_region (bool both_axes)
1717 temporal_zoom_region (both_axes);
1721 Editor::temporal_zoom_selection ()
1723 if (!selection) return;
1725 if (selection->time.empty()) {
1729 framepos_t start = selection->time[clicked_selection].start;
1730 framepos_t end = selection->time[clicked_selection].end;
1732 temporal_zoom_by_frame (start, end);
1736 Editor::temporal_zoom_session ()
1738 ENSURE_GUI_THREAD (*this, &Editor::temporal_zoom_session)
1741 framecnt_t const l = _session->current_end_frame() - _session->current_start_frame();
1742 double s = _session->current_start_frame() - l * 0.01;
1746 framecnt_t const e = _session->current_end_frame() + l * 0.01;
1747 temporal_zoom_by_frame (framecnt_t (s), e);
1752 Editor::temporal_zoom_by_frame (framepos_t start, framepos_t end)
1754 if (!_session) return;
1756 if ((start == 0 && end == 0) || end < start) {
1760 framepos_t range = end - start;
1762 double const new_fpp = (double) range / (double) _visible_canvas_width;
1764 framepos_t new_page = (framepos_t) floor (_visible_canvas_width * new_fpp);
1765 framepos_t middle = (framepos_t) floor ((double) start + ((double) range / 2.0f));
1766 framepos_t new_leftmost = (framepos_t) floor ((double) middle - ((double) new_page / 2.0f));
1768 if (new_leftmost > middle) {
1772 if (new_leftmost < 0) {
1776 reposition_and_zoom (new_leftmost, new_fpp);
1780 Editor::temporal_zoom_to_frame (bool coarser, framepos_t frame)
1786 framecnt_t range_before = frame - leftmost_frame;
1790 if (samples_per_pixel <= 1) {
1793 new_spp = samples_per_pixel + (samples_per_pixel/2);
1795 range_before += range_before/2;
1797 if (samples_per_pixel >= 1) {
1798 new_spp = samples_per_pixel - (samples_per_pixel/2);
1800 /* could bail out here since we cannot zoom any finer,
1801 but leave that to the equality test below
1803 new_spp = samples_per_pixel;
1806 range_before -= range_before/2;
1809 if (new_spp == samples_per_pixel) {
1813 /* zoom focus is automatically taken as @param frame when this
1817 framepos_t new_leftmost = frame - (framepos_t)range_before;
1819 if (new_leftmost > frame) {
1823 if (new_leftmost < 0) {
1827 reposition_and_zoom (new_leftmost, new_spp);
1832 Editor::choose_new_marker_name(string &name) {
1834 if (!Config->get_name_new_markers()) {
1835 /* don't prompt user for a new name */
1839 ArdourPrompter dialog (true);
1841 dialog.set_prompt (_("New Name:"));
1843 dialog.set_title (_("New Location Marker"));
1845 dialog.set_name ("MarkNameWindow");
1846 dialog.set_size_request (250, -1);
1847 dialog.set_position (Gtk::WIN_POS_MOUSE);
1849 dialog.add_button (Stock::OK, RESPONSE_ACCEPT);
1850 dialog.set_initial_text (name);
1854 switch (dialog.run ()) {
1855 case RESPONSE_ACCEPT:
1861 dialog.get_result(name);
1868 Editor::add_location_from_selection ()
1872 if (selection->time.empty()) {
1876 if (_session == 0 || clicked_axisview == 0) {
1880 framepos_t start = selection->time[clicked_selection].start;
1881 framepos_t end = selection->time[clicked_selection].end;
1883 _session->locations()->next_available_name(rangename,"selection");
1884 Location *location = new Location (*_session, start, end, rangename, Location::IsRangeMarker);
1886 _session->begin_reversible_command (_("add marker"));
1887 XMLNode &before = _session->locations()->get_state();
1888 _session->locations()->add (location, true);
1889 XMLNode &after = _session->locations()->get_state();
1890 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
1891 _session->commit_reversible_command ();
1895 Editor::add_location_mark (framepos_t where)
1899 select_new_marker = true;
1901 _session->locations()->next_available_name(markername,"mark");
1902 if (!choose_new_marker_name(markername)) {
1905 Location *location = new Location (*_session, where, where, markername, Location::IsMark);
1906 _session->begin_reversible_command (_("add marker"));
1907 XMLNode &before = _session->locations()->get_state();
1908 _session->locations()->add (location, true);
1909 XMLNode &after = _session->locations()->get_state();
1910 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
1911 _session->commit_reversible_command ();
1915 Editor::add_location_from_playhead_cursor ()
1917 add_location_mark (_session->audible_frame());
1921 Editor::remove_location_at_playhead_cursor ()
1926 _session->begin_reversible_command (_("remove marker"));
1927 XMLNode &before = _session->locations()->get_state();
1928 bool removed = false;
1930 //find location(s) at this time
1931 Locations::LocationList locs;
1932 _session->locations()->find_all_between (_session->audible_frame(), _session->audible_frame()+1, locs, Location::Flags(0));
1933 for (Locations::LocationList::iterator i = locs.begin(); i != locs.end(); ++i) {
1934 if ((*i)->is_mark()) {
1935 _session->locations()->remove (*i);
1942 XMLNode &after = _session->locations()->get_state();
1943 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
1944 _session->commit_reversible_command ();
1949 /** Add a range marker around each selected region */
1951 Editor::add_locations_from_region ()
1953 RegionSelection rs = get_regions_from_selection_and_entered ();
1959 _session->begin_reversible_command (selection->regions.size () > 1 ? _("add markers") : _("add marker"));
1960 XMLNode &before = _session->locations()->get_state();
1962 for (RegionSelection::iterator i = rs.begin (); i != rs.end (); ++i) {
1964 boost::shared_ptr<Region> region = (*i)->region ();
1966 Location *location = new Location (*_session, region->position(), region->last_frame(), region->name(), Location::IsRangeMarker);
1968 _session->locations()->add (location, true);
1971 XMLNode &after = _session->locations()->get_state();
1972 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
1973 _session->commit_reversible_command ();
1976 /** Add a single range marker around all selected regions */
1978 Editor::add_location_from_region ()
1980 RegionSelection rs = get_regions_from_selection_and_entered ();
1986 _session->begin_reversible_command (_("add marker"));
1987 XMLNode &before = _session->locations()->get_state();
1991 if (rs.size() > 1) {
1992 _session->locations()->next_available_name(markername, "regions");
1994 RegionView* rv = *(rs.begin());
1995 boost::shared_ptr<Region> region = rv->region();
1996 markername = region->name();
1999 if (!choose_new_marker_name(markername)) {
2003 // single range spanning all selected
2004 Location *location = new Location (*_session, selection->regions.start(), selection->regions.end_frame(), markername, Location::IsRangeMarker);
2005 _session->locations()->add (location, true);
2007 XMLNode &after = _session->locations()->get_state();
2008 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2009 _session->commit_reversible_command ();
2015 Editor::jump_forward_to_mark ()
2021 framepos_t pos = _session->locations()->first_mark_after (playhead_cursor->current_frame());
2027 _session->request_locate (pos, _session->transport_rolling());
2031 Editor::jump_backward_to_mark ()
2037 framepos_t pos = _session->locations()->first_mark_before (playhead_cursor->current_frame());
2043 _session->request_locate (pos, _session->transport_rolling());
2049 framepos_t const pos = _session->audible_frame ();
2052 _session->locations()->next_available_name (markername, "mark");
2054 if (!choose_new_marker_name (markername)) {
2058 _session->locations()->add (new Location (*_session, pos, 0, markername, Location::IsMark), true);
2062 Editor::clear_markers ()
2065 _session->begin_reversible_command (_("clear markers"));
2066 XMLNode &before = _session->locations()->get_state();
2067 _session->locations()->clear_markers ();
2068 XMLNode &after = _session->locations()->get_state();
2069 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2070 _session->commit_reversible_command ();
2075 Editor::clear_ranges ()
2078 _session->begin_reversible_command (_("clear ranges"));
2079 XMLNode &before = _session->locations()->get_state();
2081 Location * looploc = _session->locations()->auto_loop_location();
2082 Location * punchloc = _session->locations()->auto_punch_location();
2083 Location * sessionloc = _session->locations()->session_range_location();
2085 _session->locations()->clear_ranges ();
2087 if (looploc) _session->locations()->add (looploc);
2088 if (punchloc) _session->locations()->add (punchloc);
2089 if (sessionloc) _session->locations()->add (sessionloc);
2091 XMLNode &after = _session->locations()->get_state();
2092 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2093 _session->commit_reversible_command ();
2098 Editor::clear_locations ()
2100 _session->begin_reversible_command (_("clear locations"));
2101 XMLNode &before = _session->locations()->get_state();
2102 _session->locations()->clear ();
2103 XMLNode &after = _session->locations()->get_state();
2104 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2105 _session->commit_reversible_command ();
2106 _session->locations()->clear ();
2110 Editor::unhide_markers ()
2112 for (LocationMarkerMap::iterator i = location_markers.begin(); i != location_markers.end(); ++i) {
2113 Location *l = (*i).first;
2114 if (l->is_hidden() && l->is_mark()) {
2115 l->set_hidden(false, this);
2121 Editor::unhide_ranges ()
2123 for (LocationMarkerMap::iterator i = location_markers.begin(); i != location_markers.end(); ++i) {
2124 Location *l = (*i).first;
2125 if (l->is_hidden() && l->is_range_marker()) {
2126 l->set_hidden(false, this);
2131 /* INSERT/REPLACE */
2134 Editor::insert_region_list_selection (float times)
2136 RouteTimeAxisView *tv = 0;
2137 boost::shared_ptr<Playlist> playlist;
2139 if (clicked_routeview != 0) {
2140 tv = clicked_routeview;
2141 } else if (!selection->tracks.empty()) {
2142 if ((tv = dynamic_cast<RouteTimeAxisView*>(selection->tracks.front())) == 0) {
2145 } else if (entered_track != 0) {
2146 if ((tv = dynamic_cast<RouteTimeAxisView*>(entered_track)) == 0) {
2153 if ((playlist = tv->playlist()) == 0) {
2157 boost::shared_ptr<Region> region = _regions->get_single_selection ();
2162 begin_reversible_command (_("insert region"));
2163 playlist->clear_changes ();
2164 playlist->add_region ((RegionFactory::create (region, true)), get_preferred_edit_position(), times);
2165 if (Config->get_edit_mode() == Ripple)
2166 playlist->ripple (get_preferred_edit_position(), region->length() * times, boost::shared_ptr<Region>());
2168 _session->add_command(new StatefulDiffCommand (playlist));
2169 commit_reversible_command ();
2172 /* BUILT-IN EFFECTS */
2175 Editor::reverse_selection ()
2180 /* GAIN ENVELOPE EDITING */
2183 Editor::edit_envelope ()
2190 Editor::transition_to_rolling (bool fwd)
2196 if (_session->config.get_external_sync()) {
2197 switch (Config->get_sync_source()) {
2201 /* transport controlled by the master */
2206 if (_session->is_auditioning()) {
2207 _session->cancel_audition ();
2211 _session->request_transport_speed (fwd ? 1.0f : -1.0f);
2215 Editor::play_from_start ()
2217 _session->request_locate (_session->current_start_frame(), true);
2221 Editor::play_from_edit_point ()
2223 _session->request_locate (get_preferred_edit_position(), true);
2227 Editor::play_from_edit_point_and_return ()
2229 framepos_t start_frame;
2230 framepos_t return_frame;
2232 start_frame = get_preferred_edit_position (true);
2234 if (_session->transport_rolling()) {
2235 _session->request_locate (start_frame, false);
2239 /* don't reset the return frame if its already set */
2241 if ((return_frame = _session->requested_return_frame()) < 0) {
2242 return_frame = _session->audible_frame();
2245 if (start_frame >= 0) {
2246 _session->request_roll_at_and_return (start_frame, return_frame);
2251 Editor::play_selection ()
2253 if (selection->time.empty()) {
2257 _session->request_play_range (&selection->time, true);
2261 Editor::get_preroll ()
2263 return 1.0 /*Config->get_edit_preroll_seconds()*/ * _session->frame_rate();
2268 Editor::maybe_locate_with_edit_preroll ( framepos_t location )
2270 if ( _session->transport_rolling() || !Config->get_follow_edits() )
2273 location -= get_preroll();
2275 //don't try to locate before the beginning of time
2279 //if follow_playhead is on, keep the playhead on the screen
2280 if ( _follow_playhead )
2281 if ( location < leftmost_frame )
2282 location = leftmost_frame;
2284 _session->request_locate( location );
2288 Editor::play_with_preroll ()
2290 if (selection->time.empty()) {
2293 framepos_t preroll = get_preroll();
2295 framepos_t start = 0;
2296 if (selection->time[clicked_selection].start > preroll)
2297 start = selection->time[clicked_selection].start - preroll;
2299 framepos_t end = selection->time[clicked_selection].end + preroll;
2301 AudioRange ar (start, end, 0);
2302 list<AudioRange> lar;
2305 _session->request_play_range (&lar, true);
2310 Editor::play_location (Location& location)
2312 if (location.start() <= location.end()) {
2316 _session->request_bounded_roll (location.start(), location.end());
2320 Editor::loop_location (Location& location)
2322 if (location.start() <= location.end()) {
2328 if ((tll = transport_loop_location()) != 0) {
2329 tll->set (location.start(), location.end());
2331 // enable looping, reposition and start rolling
2332 _session->request_play_loop (true);
2333 _session->request_locate (tll->start(), true);
2338 Editor::do_layer_operation (LayerOperation op)
2340 if (selection->regions.empty ()) {
2344 bool const multiple = selection->regions.size() > 1;
2348 begin_reversible_command (_("raise regions"));
2350 begin_reversible_command (_("raise region"));
2356 begin_reversible_command (_("raise regions to top"));
2358 begin_reversible_command (_("raise region to top"));
2364 begin_reversible_command (_("lower regions"));
2366 begin_reversible_command (_("lower region"));
2372 begin_reversible_command (_("lower regions to bottom"));
2374 begin_reversible_command (_("lower region"));
2379 set<boost::shared_ptr<Playlist> > playlists = selection->regions.playlists ();
2380 for (set<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
2381 (*i)->clear_owned_changes ();
2384 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
2385 boost::shared_ptr<Region> r = (*i)->region ();
2397 r->lower_to_bottom ();
2401 for (set<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
2402 vector<Command*> cmds;
2404 _session->add_commands (cmds);
2407 commit_reversible_command ();
2411 Editor::raise_region ()
2413 do_layer_operation (Raise);
2417 Editor::raise_region_to_top ()
2419 do_layer_operation (RaiseToTop);
2423 Editor::lower_region ()
2425 do_layer_operation (Lower);
2429 Editor::lower_region_to_bottom ()
2431 do_layer_operation (LowerToBottom);
2434 /** Show the region editor for the selected regions */
2436 Editor::show_region_properties ()
2438 selection->foreach_regionview (&RegionView::show_region_editor);
2441 /** Show the midi list editor for the selected MIDI regions */
2443 Editor::show_midi_list_editor ()
2445 selection->foreach_midi_regionview (&MidiRegionView::show_list_editor);
2449 Editor::rename_region ()
2451 RegionSelection rs = get_regions_from_selection_and_entered ();
2457 ArdourDialog d (*this, _("Rename Region"), true, false);
2459 Label label (_("New name:"));
2462 hbox.set_spacing (6);
2463 hbox.pack_start (label, false, false);
2464 hbox.pack_start (entry, true, true);
2466 d.get_vbox()->set_border_width (12);
2467 d.get_vbox()->pack_start (hbox, false, false);
2469 d.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
2470 d.add_button(Gtk::Stock::OK, Gtk::RESPONSE_OK);
2472 d.set_size_request (300, -1);
2474 entry.set_text (rs.front()->region()->name());
2475 entry.select_region (0, -1);
2477 entry.signal_activate().connect (sigc::bind (sigc::mem_fun (d, &Dialog::response), RESPONSE_OK));
2483 int const ret = d.run();
2487 if (ret != RESPONSE_OK) {
2491 std::string str = entry.get_text();
2492 strip_whitespace_edges (str);
2494 rs.front()->region()->set_name (str);
2495 _regions->redisplay ();
2500 Editor::audition_playlist_region_via_route (boost::shared_ptr<Region> region, Route& route)
2502 if (_session->is_auditioning()) {
2503 _session->cancel_audition ();
2506 // note: some potential for creativity here, because region doesn't
2507 // have to belong to the playlist that Route is handling
2509 // bool was_soloed = route.soloed();
2511 route.set_solo (true, this);
2513 _session->request_bounded_roll (region->position(), region->position() + region->length());
2515 /* XXX how to unset the solo state ? */
2518 /** Start an audition of the first selected region */
2520 Editor::play_edit_range ()
2522 framepos_t start, end;
2524 if (get_edit_op_range (start, end)) {
2525 _session->request_bounded_roll (start, end);
2530 Editor::play_selected_region ()
2532 framepos_t start = max_framepos;
2535 RegionSelection rs = get_regions_from_selection_and_entered ();
2541 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
2542 if ((*i)->region()->position() < start) {
2543 start = (*i)->region()->position();
2545 if ((*i)->region()->last_frame() + 1 > end) {
2546 end = (*i)->region()->last_frame() + 1;
2550 _session->request_bounded_roll (start, end);
2554 Editor::audition_playlist_region_standalone (boost::shared_ptr<Region> region)
2556 _session->audition_region (region);
2560 Editor::region_from_selection ()
2562 if (clicked_axisview == 0) {
2566 if (selection->time.empty()) {
2570 framepos_t start = selection->time[clicked_selection].start;
2571 framepos_t end = selection->time[clicked_selection].end;
2573 TrackViewList tracks = get_tracks_for_range_action ();
2575 framepos_t selection_cnt = end - start + 1;
2577 for (TrackSelection::iterator i = tracks.begin(); i != tracks.end(); ++i) {
2578 boost::shared_ptr<Region> current;
2579 boost::shared_ptr<Playlist> pl;
2580 framepos_t internal_start;
2583 if ((pl = (*i)->playlist()) == 0) {
2587 if ((current = pl->top_region_at (start)) == 0) {
2591 internal_start = start - current->position();
2592 RegionFactory::region_name (new_name, current->name(), true);
2596 plist.add (ARDOUR::Properties::start, current->start() + internal_start);
2597 plist.add (ARDOUR::Properties::length, selection_cnt);
2598 plist.add (ARDOUR::Properties::name, new_name);
2599 plist.add (ARDOUR::Properties::layer, 0);
2601 boost::shared_ptr<Region> region (RegionFactory::create (current, plist));
2606 Editor::create_region_from_selection (vector<boost::shared_ptr<Region> >& new_regions)
2608 if (selection->time.empty() || selection->tracks.empty()) {
2612 framepos_t start = selection->time[clicked_selection].start;
2613 framepos_t end = selection->time[clicked_selection].end;
2615 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
2616 sort_track_selection (ts);
2618 for (TrackSelection::iterator i = ts.begin(); i != ts.end(); ++i) {
2619 boost::shared_ptr<Region> current;
2620 boost::shared_ptr<Playlist> playlist;
2621 framepos_t internal_start;
2624 if ((playlist = (*i)->playlist()) == 0) {
2628 if ((current = playlist->top_region_at(start)) == 0) {
2632 internal_start = start - current->position();
2633 RegionFactory::region_name (new_name, current->name(), true);
2637 plist.add (ARDOUR::Properties::start, current->start() + internal_start);
2638 plist.add (ARDOUR::Properties::length, end - start + 1);
2639 plist.add (ARDOUR::Properties::name, new_name);
2641 new_regions.push_back (RegionFactory::create (current, plist));
2646 Editor::split_multichannel_region ()
2648 RegionSelection rs = get_regions_from_selection_and_entered ();
2654 vector< boost::shared_ptr<Region> > v;
2656 for (list<RegionView*>::iterator x = rs.begin(); x != rs.end(); ++x) {
2657 (*x)->region()->separate_by_channel (*_session, v);
2662 Editor::new_region_from_selection ()
2664 region_from_selection ();
2665 cancel_selection ();
2669 add_if_covered (RegionView* rv, const AudioRange* ar, RegionSelection* rs)
2671 switch (rv->region()->coverage (ar->start, ar->end - 1)) {
2672 case Evoral::OverlapNone:
2680 * - selected tracks, or if there are none...
2681 * - tracks containing selected regions, or if there are none...
2686 Editor::get_tracks_for_range_action () const
2690 if (selection->tracks.empty()) {
2692 /* use tracks with selected regions */
2694 RegionSelection rs = selection->regions;
2696 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
2697 TimeAxisView* tv = &(*i)->get_time_axis_view();
2699 if (!t.contains (tv)) {
2705 /* no regions and no tracks: use all tracks */
2711 t = selection->tracks;
2714 return t.filter_to_unique_playlists();
2718 Editor::separate_regions_between (const TimeSelection& ts)
2720 bool in_command = false;
2721 boost::shared_ptr<Playlist> playlist;
2722 RegionSelection new_selection;
2724 TrackViewList tmptracks = get_tracks_for_range_action ();
2725 sort_track_selection (tmptracks);
2727 for (TrackSelection::iterator i = tmptracks.begin(); i != tmptracks.end(); ++i) {
2729 RouteTimeAxisView* rtv;
2731 if ((rtv = dynamic_cast<RouteTimeAxisView*> ((*i))) != 0) {
2733 if (rtv->is_track()) {
2735 /* no edits to destructive tracks */
2737 if (rtv->track()->destructive()) {
2741 if ((playlist = rtv->playlist()) != 0) {
2743 playlist->clear_changes ();
2745 /* XXX need to consider musical time selections here at some point */
2747 double speed = rtv->track()->speed();
2750 for (list<AudioRange>::const_iterator t = ts.begin(); t != ts.end(); ++t) {
2752 sigc::connection c = rtv->view()->RegionViewAdded.connect (
2753 sigc::mem_fun(*this, &Editor::collect_new_region_view));
2755 latest_regionviews.clear ();
2757 playlist->partition ((framepos_t)((*t).start * speed),
2758 (framepos_t)((*t).end * speed), false);
2762 if (!latest_regionviews.empty()) {
2764 rtv->view()->foreach_regionview (sigc::bind (
2765 sigc::ptr_fun (add_if_covered),
2766 &(*t), &new_selection));
2769 begin_reversible_command (_("separate"));
2773 /* pick up changes to existing regions */
2775 vector<Command*> cmds;
2776 playlist->rdiff (cmds);
2777 _session->add_commands (cmds);
2779 /* pick up changes to the playlist itself (adds/removes)
2782 _session->add_command(new StatefulDiffCommand (playlist));
2791 selection->set (new_selection);
2792 set_mouse_mode (MouseObject);
2794 commit_reversible_command ();
2798 struct PlaylistState {
2799 boost::shared_ptr<Playlist> playlist;
2803 /** Take tracks from get_tracks_for_range_action and cut any regions
2804 * on those tracks so that the tracks are empty over the time
2808 Editor::separate_region_from_selection ()
2810 /* preferentially use *all* ranges in the time selection if we're in range mode
2811 to allow discontiguous operation, since get_edit_op_range() currently
2812 returns a single range.
2815 if (!selection->time.empty()) {
2817 separate_regions_between (selection->time);
2824 if (get_edit_op_range (start, end)) {
2826 AudioRange ar (start, end, 1);
2830 separate_regions_between (ts);
2836 Editor::separate_region_from_punch ()
2838 Location* loc = _session->locations()->auto_punch_location();
2840 separate_regions_using_location (*loc);
2845 Editor::separate_region_from_loop ()
2847 Location* loc = _session->locations()->auto_loop_location();
2849 separate_regions_using_location (*loc);
2854 Editor::separate_regions_using_location (Location& loc)
2856 if (loc.is_mark()) {
2860 AudioRange ar (loc.start(), loc.end(), 1);
2865 separate_regions_between (ts);
2868 /** Separate regions under the selected region */
2870 Editor::separate_under_selected_regions ()
2872 vector<PlaylistState> playlists;
2876 rs = get_regions_from_selection_and_entered();
2878 if (!_session || rs.empty()) {
2882 begin_reversible_command (_("separate region under"));
2884 list<boost::shared_ptr<Region> > regions_to_remove;
2886 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
2887 // we can't just remove the region(s) in this loop because
2888 // this removes them from the RegionSelection, and they thus
2889 // disappear from underneath the iterator, and the ++i above
2890 // SEGVs in a puzzling fashion.
2892 // so, first iterate over the regions to be removed from rs and
2893 // add them to the regions_to_remove list, and then
2894 // iterate over the list to actually remove them.
2896 regions_to_remove.push_back ((*i)->region());
2899 for (list<boost::shared_ptr<Region> >::iterator rl = regions_to_remove.begin(); rl != regions_to_remove.end(); ++rl) {
2901 boost::shared_ptr<Playlist> playlist = (*rl)->playlist();
2904 // is this check necessary?
2908 vector<PlaylistState>::iterator i;
2910 //only take state if this is a new playlist.
2911 for (i = playlists.begin(); i != playlists.end(); ++i) {
2912 if ((*i).playlist == playlist) {
2917 if (i == playlists.end()) {
2919 PlaylistState before;
2920 before.playlist = playlist;
2921 before.before = &playlist->get_state();
2923 playlist->freeze ();
2924 playlists.push_back(before);
2927 //Partition on the region bounds
2928 playlist->partition ((*rl)->first_frame() - 1, (*rl)->last_frame() + 1, true);
2930 //Re-add region that was just removed due to the partition operation
2931 playlist->add_region( (*rl), (*rl)->first_frame() );
2934 vector<PlaylistState>::iterator pl;
2936 for (pl = playlists.begin(); pl != playlists.end(); ++pl) {
2937 (*pl).playlist->thaw ();
2938 _session->add_command(new MementoCommand<Playlist>(*(*pl).playlist, (*pl).before, &(*pl).playlist->get_state()));
2941 commit_reversible_command ();
2945 Editor::crop_region_to_selection ()
2947 if (!selection->time.empty()) {
2949 crop_region_to (selection->time.start(), selection->time.end_frame());
2956 if (get_edit_op_range (start, end)) {
2957 crop_region_to (start, end);
2964 Editor::crop_region_to (framepos_t start, framepos_t end)
2966 vector<boost::shared_ptr<Playlist> > playlists;
2967 boost::shared_ptr<Playlist> playlist;
2970 if (selection->tracks.empty()) {
2971 ts = track_views.filter_to_unique_playlists();
2973 ts = selection->tracks.filter_to_unique_playlists ();
2976 sort_track_selection (ts);
2978 for (TrackSelection::iterator i = ts.begin(); i != ts.end(); ++i) {
2980 RouteTimeAxisView* rtv;
2982 if ((rtv = dynamic_cast<RouteTimeAxisView*> ((*i))) != 0) {
2984 boost::shared_ptr<Track> t = rtv->track();
2986 if (t != 0 && ! t->destructive()) {
2988 if ((playlist = rtv->playlist()) != 0) {
2989 playlists.push_back (playlist);
2995 if (playlists.empty()) {
2999 framepos_t the_start;
3003 begin_reversible_command (_("trim to selection"));
3005 for (vector<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
3007 boost::shared_ptr<Region> region;
3011 if ((region = (*i)->top_region_at(the_start)) == 0) {
3015 /* now adjust lengths to that we do the right thing
3016 if the selection extends beyond the region
3019 the_start = max (the_start, (framepos_t) region->position());
3020 if (max_framepos - the_start < region->length()) {
3021 the_end = the_start + region->length() - 1;
3023 the_end = max_framepos;
3025 the_end = min (end, the_end);
3026 cnt = the_end - the_start + 1;
3028 region->clear_changes ();
3029 region->trim_to (the_start, cnt);
3030 _session->add_command (new StatefulDiffCommand (region));
3033 commit_reversible_command ();
3037 Editor::region_fill_track ()
3039 RegionSelection rs = get_regions_from_selection_and_entered ();
3041 if (!_session || rs.empty()) {
3045 framepos_t const end = _session->current_end_frame ();
3047 begin_reversible_command (Operations::region_fill);
3049 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3051 boost::shared_ptr<Region> region ((*i)->region());
3053 boost::shared_ptr<Playlist> pl = region->playlist();
3055 if (end <= region->last_frame()) {
3059 double times = (double) (end - region->last_frame()) / (double) region->length();
3065 pl->clear_changes ();
3066 pl->add_region (RegionFactory::create (region, true), region->last_frame(), times);
3067 _session->add_command (new StatefulDiffCommand (pl));
3070 commit_reversible_command ();
3074 Editor::region_fill_selection ()
3076 if (clicked_routeview == 0 || !clicked_routeview->is_audio_track()) {
3080 if (selection->time.empty()) {
3084 boost::shared_ptr<Region> region = _regions->get_single_selection ();
3089 framepos_t start = selection->time[clicked_selection].start;
3090 framepos_t end = selection->time[clicked_selection].end;
3092 boost::shared_ptr<Playlist> playlist;
3094 if (selection->tracks.empty()) {
3098 framepos_t selection_length = end - start;
3099 float times = (float)selection_length / region->length();
3101 begin_reversible_command (Operations::fill_selection);
3103 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
3105 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
3107 if ((playlist = (*i)->playlist()) == 0) {
3111 playlist->clear_changes ();
3112 playlist->add_region (RegionFactory::create (region, true), start, times);
3113 _session->add_command (new StatefulDiffCommand (playlist));
3116 commit_reversible_command ();
3120 Editor::set_region_sync_position ()
3122 set_sync_point (get_preferred_edit_position (), get_regions_from_selection_and_edit_point ());
3126 Editor::set_sync_point (framepos_t where, const RegionSelection& rs)
3128 bool in_command = false;
3130 for (RegionSelection::const_iterator r = rs.begin(); r != rs.end(); ++r) {
3132 if (!(*r)->region()->covers (where)) {
3136 boost::shared_ptr<Region> region ((*r)->region());
3139 begin_reversible_command (_("set sync point"));
3143 region->clear_changes ();
3144 region->set_sync_position (where);
3145 _session->add_command(new StatefulDiffCommand (region));
3149 commit_reversible_command ();
3153 /** Remove the sync positions of the selection */
3155 Editor::remove_region_sync ()
3157 RegionSelection rs = get_regions_from_selection_and_entered ();
3163 begin_reversible_command (_("remove region sync"));
3165 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3167 (*i)->region()->clear_changes ();
3168 (*i)->region()->clear_sync_position ();
3169 _session->add_command(new StatefulDiffCommand ((*i)->region()));
3172 commit_reversible_command ();
3176 Editor::naturalize_region ()
3178 RegionSelection rs = get_regions_from_selection_and_entered ();
3184 if (rs.size() > 1) {
3185 begin_reversible_command (_("move regions to original position"));
3187 begin_reversible_command (_("move region to original position"));
3190 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3191 (*i)->region()->clear_changes ();
3192 (*i)->region()->move_to_natural_position ();
3193 _session->add_command (new StatefulDiffCommand ((*i)->region()));
3196 commit_reversible_command ();
3200 Editor::align_regions (RegionPoint what)
3202 RegionSelection const rs = get_regions_from_selection_and_edit_point ();
3208 begin_reversible_command (_("align selection"));
3210 framepos_t const position = get_preferred_edit_position ();
3212 for (RegionSelection::const_iterator i = rs.begin(); i != rs.end(); ++i) {
3213 align_region_internal ((*i)->region(), what, position);
3216 commit_reversible_command ();
3219 struct RegionSortByTime {
3220 bool operator() (const RegionView* a, const RegionView* b) {
3221 return a->region()->position() < b->region()->position();
3226 Editor::align_regions_relative (RegionPoint point)
3228 RegionSelection const rs = get_regions_from_selection_and_edit_point ();
3234 framepos_t const position = get_preferred_edit_position ();
3236 framepos_t distance = 0;
3240 list<RegionView*> sorted;
3241 rs.by_position (sorted);
3243 boost::shared_ptr<Region> r ((*sorted.begin())->region());
3248 if (position > r->position()) {
3249 distance = position - r->position();
3251 distance = r->position() - position;
3257 if (position > r->last_frame()) {
3258 distance = position - r->last_frame();
3259 pos = r->position() + distance;
3261 distance = r->last_frame() - position;
3262 pos = r->position() - distance;
3268 pos = r->adjust_to_sync (position);
3269 if (pos > r->position()) {
3270 distance = pos - r->position();
3272 distance = r->position() - pos;
3278 if (pos == r->position()) {
3282 begin_reversible_command (_("align selection (relative)"));
3284 /* move first one specially */
3286 r->clear_changes ();
3287 r->set_position (pos);
3288 _session->add_command(new StatefulDiffCommand (r));
3290 /* move rest by the same amount */
3294 for (list<RegionView*>::iterator i = sorted.begin(); i != sorted.end(); ++i) {
3296 boost::shared_ptr<Region> region ((*i)->region());
3298 region->clear_changes ();
3301 region->set_position (region->position() + distance);
3303 region->set_position (region->position() - distance);
3306 _session->add_command(new StatefulDiffCommand (region));
3310 commit_reversible_command ();
3314 Editor::align_region (boost::shared_ptr<Region> region, RegionPoint point, framepos_t position)
3316 begin_reversible_command (_("align region"));
3317 align_region_internal (region, point, position);
3318 commit_reversible_command ();
3322 Editor::align_region_internal (boost::shared_ptr<Region> region, RegionPoint point, framepos_t position)
3324 region->clear_changes ();
3328 region->set_position (region->adjust_to_sync (position));
3332 if (position > region->length()) {
3333 region->set_position (position - region->length());
3338 region->set_position (position);
3342 _session->add_command(new StatefulDiffCommand (region));
3346 Editor::trim_region_front ()
3352 Editor::trim_region_back ()
3354 trim_region (false);
3358 Editor::trim_region (bool front)
3360 framepos_t where = get_preferred_edit_position();
3361 RegionSelection rs = get_regions_from_selection_and_edit_point ();
3367 begin_reversible_command (front ? _("trim front") : _("trim back"));
3369 for (list<RegionView*>::const_iterator i = rs.by_layer().begin(); i != rs.by_layer().end(); ++i) {
3370 if (!(*i)->region()->locked()) {
3372 (*i)->region()->clear_changes ();
3375 (*i)->region()->trim_front (where);
3376 maybe_locate_with_edit_preroll ( where );
3378 (*i)->region()->trim_end (where);
3379 maybe_locate_with_edit_preroll ( where );
3382 _session->add_command (new StatefulDiffCommand ((*i)->region()));
3386 commit_reversible_command ();
3389 /** Trim the end of the selected regions to the position of the edit cursor */
3391 Editor::trim_region_to_loop ()
3393 Location* loc = _session->locations()->auto_loop_location();
3397 trim_region_to_location (*loc, _("trim to loop"));
3401 Editor::trim_region_to_punch ()
3403 Location* loc = _session->locations()->auto_punch_location();
3407 trim_region_to_location (*loc, _("trim to punch"));
3411 Editor::trim_region_to_location (const Location& loc, const char* str)
3413 RegionSelection rs = get_regions_from_selection_and_entered ();
3415 begin_reversible_command (str);
3417 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
3418 RegionView* rv = (*x);
3420 /* require region to span proposed trim */
3421 switch (rv->region()->coverage (loc.start(), loc.end())) {
3422 case Evoral::OverlapInternal:
3428 RouteTimeAxisView* tav = dynamic_cast<RouteTimeAxisView*> (&rv->get_time_axis_view());
3437 if (tav->track() != 0) {
3438 speed = tav->track()->speed();
3441 start = session_frame_to_track_frame (loc.start(), speed);
3442 end = session_frame_to_track_frame (loc.end(), speed);
3444 rv->region()->clear_changes ();
3445 rv->region()->trim_to (start, (end - start));
3446 _session->add_command(new StatefulDiffCommand (rv->region()));
3449 commit_reversible_command ();
3453 Editor::trim_region_to_previous_region_end ()
3455 return trim_to_region(false);
3459 Editor::trim_region_to_next_region_start ()
3461 return trim_to_region(true);
3465 Editor::trim_to_region(bool forward)
3467 RegionSelection rs = get_regions_from_selection_and_entered ();
3469 begin_reversible_command (_("trim to region"));
3471 boost::shared_ptr<Region> next_region;
3473 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
3475 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*x);
3481 AudioTimeAxisView* atav = dynamic_cast<AudioTimeAxisView*> (&arv->get_time_axis_view());
3489 if (atav->track() != 0) {
3490 speed = atav->track()->speed();
3494 boost::shared_ptr<Region> region = arv->region();
3495 boost::shared_ptr<Playlist> playlist (region->playlist());
3497 region->clear_changes ();
3501 next_region = playlist->find_next_region (region->first_frame(), Start, 1);
3507 region->trim_end((framepos_t) ( (next_region->first_frame() - 1) * speed));
3508 arv->region_changed (PropertyChange (ARDOUR::Properties::length));
3512 next_region = playlist->find_next_region (region->first_frame(), Start, 0);
3518 region->trim_front((framepos_t) ((next_region->last_frame() + 1) * speed));
3520 arv->region_changed (ARDOUR::bounds_change);
3523 _session->add_command(new StatefulDiffCommand (region));
3526 commit_reversible_command ();
3530 Editor::unfreeze_route ()
3532 if (clicked_routeview == 0 || !clicked_routeview->is_track()) {
3536 clicked_routeview->track()->unfreeze ();
3540 Editor::_freeze_thread (void* arg)
3542 return static_cast<Editor*>(arg)->freeze_thread ();
3546 Editor::freeze_thread ()
3548 /* create event pool because we may need to talk to the session */
3549 SessionEvent::create_per_thread_pool ("freeze events", 64);
3550 /* create per-thread buffers for process() tree to use */
3551 clicked_routeview->audio_track()->freeze_me (*current_interthread_info);
3552 current_interthread_info->done = true;
3557 Editor::freeze_route ()
3563 /* stop transport before we start. this is important */
3565 _session->request_transport_speed (0.0);
3567 /* wait for just a little while, because the above call is asynchronous */
3569 Glib::usleep (250000);
3571 if (clicked_routeview == 0 || !clicked_routeview->is_audio_track()) {
3575 if (!clicked_routeview->track()->bounceable (clicked_routeview->track()->main_outs(), true)) {
3577 _("This track/bus cannot be frozen because the signal adds or loses channels before reaching the outputs.\n"
3578 "This is typically caused by plugins that generate stereo output from mono input or vice versa.")
3580 d.set_title (_("Cannot freeze"));
3585 if (clicked_routeview->track()->has_external_redirects()) {
3586 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"
3587 "Freezing will only process the signal as far as the first send/insert/return."),
3588 clicked_routeview->track()->name()), true, MESSAGE_INFO, BUTTONS_NONE, true);
3590 d.add_button (_("Freeze anyway"), Gtk::RESPONSE_OK);
3591 d.add_button (_("Don't freeze"), Gtk::RESPONSE_CANCEL);
3592 d.set_title (_("Freeze Limits"));
3594 int response = d.run ();
3597 case Gtk::RESPONSE_CANCEL:
3604 InterThreadInfo itt;
3605 current_interthread_info = &itt;
3607 InterthreadProgressWindow ipw (current_interthread_info, _("Freeze"), _("Cancel Freeze"));
3609 pthread_create_and_store (X_("freezer"), &itt.thread, _freeze_thread, this);
3611 set_canvas_cursor (_cursors->wait);
3613 while (!itt.done && !itt.cancel) {
3614 gtk_main_iteration ();
3617 current_interthread_info = 0;
3618 set_canvas_cursor (current_canvas_cursor);
3622 Editor::bounce_range_selection (bool replace, bool enable_processing)
3624 if (selection->time.empty()) {
3628 TrackSelection views = selection->tracks;
3630 for (TrackViewList::iterator i = views.begin(); i != views.end(); ++i) {
3632 if (enable_processing) {
3634 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*i);
3636 if (rtv && rtv->track() && replace && enable_processing && !rtv->track()->bounceable (rtv->track()->main_outs(), false)) {
3638 _("You can't perform this operation because the processing of the signal "
3639 "will cause one or more of the tracks to end up with a region with more channels than this track has inputs.\n\n"
3640 "You can do this without processing, which is a different operation.")
3642 d.set_title (_("Cannot bounce"));
3649 framepos_t start = selection->time[clicked_selection].start;
3650 framepos_t end = selection->time[clicked_selection].end;
3651 framepos_t cnt = end - start + 1;
3653 begin_reversible_command (_("bounce range"));
3655 for (TrackViewList::iterator i = views.begin(); i != views.end(); ++i) {
3657 RouteTimeAxisView* rtv;
3659 if ((rtv = dynamic_cast<RouteTimeAxisView*> (*i)) == 0) {
3663 boost::shared_ptr<Playlist> playlist;
3665 if ((playlist = rtv->playlist()) == 0) {
3669 InterThreadInfo itt;
3671 playlist->clear_changes ();
3672 playlist->clear_owned_changes ();
3674 boost::shared_ptr<Region> r;
3676 if (enable_processing) {
3677 r = rtv->track()->bounce_range (start, start+cnt, itt, rtv->track()->main_outs(), false);
3679 r = rtv->track()->bounce_range (start, start+cnt, itt, boost::shared_ptr<Processor>(), false);
3687 list<AudioRange> ranges;
3688 ranges.push_back (AudioRange (start, start+cnt, 0));
3689 playlist->cut (ranges); // discard result
3690 playlist->add_region (r, start);
3693 vector<Command*> cmds;
3694 playlist->rdiff (cmds);
3695 _session->add_commands (cmds);
3697 _session->add_command (new StatefulDiffCommand (playlist));
3700 commit_reversible_command ();
3703 /** Delete selected regions, automation points or a time range */
3710 /** Cut selected regions, automation points or a time range */
3717 /** Copy selected regions, automation points or a time range */
3725 /** @return true if a Cut, Copy or Clear is possible */
3727 Editor::can_cut_copy () const
3729 switch (effective_mouse_mode()) {
3732 if (!selection->regions.empty() || !selection->points.empty()) {
3738 if (!selection->time.empty()) {
3751 /** Cut, copy or clear selected regions, automation points or a time range.
3752 * @param op Operation (Delete, Cut, Copy or Clear)
3755 Editor::cut_copy (CutCopyOp op)
3757 /* only cancel selection if cut/copy is successful.*/
3763 opname = _("delete");
3772 opname = _("clear");
3776 /* if we're deleting something, and the mouse is still pressed,
3777 the thing we started a drag for will be gone when we release
3778 the mouse button(s). avoid this. see part 2 at the end of
3782 if (op == Delete || op == Cut || op == Clear) {
3783 if (_drags->active ()) {
3788 if ( op != Delete ) //"Delete" doesn't change copy/paste buf
3789 cut_buffer->clear ();
3791 if (entered_marker) {
3793 /* cut/delete op while pointing at a marker */
3796 Location* loc = find_location_from_marker (entered_marker, ignored);
3798 if (_session && loc) {
3799 Glib::signal_idle().connect (sigc::bind (sigc::mem_fun(*this, &Editor::really_remove_marker), loc));
3806 if (internal_editing()) {
3808 switch (effective_mouse_mode()) {
3811 begin_reversible_command (opname + ' ' + X_("MIDI"));
3813 commit_reversible_command ();
3822 bool did_edit = false;
3824 switch (effective_mouse_mode()) {
3826 if (!selection->points.empty()) {
3827 begin_reversible_command (opname + _(" points"));
3829 cut_copy_points (op);
3830 if (op == Cut || op == Delete) {
3831 selection->clear_points ();
3838 if (!selection->regions.empty() || !selection->points.empty()) {
3842 if (selection->regions.empty()) {
3843 thing_name = _("points");
3844 } else if (selection->points.empty()) {
3845 thing_name = _("regions");
3847 thing_name = _("objects");
3850 begin_reversible_command (opname + ' ' + thing_name);
3853 if (!selection->regions.empty()) {
3854 cut_copy_regions (op, selection->regions);
3856 if (op == Cut || op == Delete) {
3857 selection->clear_regions ();
3861 if (!selection->points.empty()) {
3862 cut_copy_points (op);
3864 if (op == Cut || op == Delete) {
3865 selection->clear_points ();
3872 if (selection->time.empty()) {
3873 framepos_t start, end;
3874 /* no time selection, see if we can get an edit range
3877 if (get_edit_op_range (start, end)) {
3878 selection->set (start, end);
3881 if (!selection->time.empty()) {
3882 begin_reversible_command (opname + _(" range"));
3885 cut_copy_ranges (op);
3887 if (op == Cut || op == Delete) {
3888 selection->clear_time ();
3898 commit_reversible_command ();
3901 if (op == Delete || op == Cut || op == Clear) {
3906 struct AutomationRecord {
3907 AutomationRecord () : state (0) {}
3908 AutomationRecord (XMLNode* s) : state (s) {}
3910 XMLNode* state; ///< state before any operation
3911 boost::shared_ptr<Evoral::ControlList> copy; ///< copied events for the cut buffer
3914 /** Cut, copy or clear selected automation points.
3915 * @param op Operation (Cut, Copy or Clear)
3918 Editor::cut_copy_points (CutCopyOp op)
3920 if (selection->points.empty ()) {
3924 /* XXX: not ideal, as there may be more than one track involved in the point selection */
3925 _last_cut_copy_source_track = &selection->points.front()->line().trackview;
3927 /* Keep a record of the AutomationLists that we end up using in this operation */
3928 typedef std::map<boost::shared_ptr<AutomationList>, AutomationRecord> Lists;
3931 /* Go through all selected points, making an AutomationRecord for each distinct AutomationList */
3932 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
3933 boost::shared_ptr<AutomationList> al = (*i)->line().the_list();
3934 if (lists.find (al) == lists.end ()) {
3935 /* We haven't seen this list yet, so make a record for it. This includes
3936 taking a copy of its current state, in case this is needed for undo later.
3938 lists[al] = AutomationRecord (&al->get_state ());
3942 if (op == Cut || op == Copy) {
3943 /* This operation will involve putting things in the cut buffer, so create an empty
3944 ControlList for each of our source lists to put the cut buffer data in.
3946 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
3947 i->second.copy = i->first->create (i->first->parameter ());
3950 /* Add all selected points to the relevant copy ControlLists */
3951 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
3952 boost::shared_ptr<AutomationList> al = (*i)->line().the_list();
3953 AutomationList::const_iterator j = (*i)->model ();
3954 lists[al].copy->add ((*j)->when, (*j)->value);
3957 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
3958 /* Correct this copy list so that it starts at time 0 */
3959 double const start = i->second.copy->front()->when;
3960 for (AutomationList::iterator j = i->second.copy->begin(); j != i->second.copy->end(); ++j) {
3961 (*j)->when -= start;
3964 /* And add it to the cut buffer */
3965 cut_buffer->add (i->second.copy);
3969 if (op == Delete || op == Cut) {
3970 /* This operation needs to remove things from the main AutomationList, so do that now */
3972 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
3973 i->first->freeze ();
3976 /* Remove each selected point from its AutomationList */
3977 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
3978 boost::shared_ptr<AutomationList> al = (*i)->line().the_list();
3979 al->erase ((*i)->model ());
3982 /* Thaw the lists and add undo records for them */
3983 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
3984 boost::shared_ptr<AutomationList> al = i->first;
3986 _session->add_command (new MementoCommand<AutomationList> (*al.get(), i->second.state, &(al->get_state ())));
3991 /** Cut, copy or clear selected automation points.
3992 * @param op Operation (Cut, Copy or Clear)
3995 Editor::cut_copy_midi (CutCopyOp op)
3997 for (MidiRegionSelection::iterator i = selection->midi_regions.begin(); i != selection->midi_regions.end(); ++i) {
3998 MidiRegionView* mrv = *i;
3999 mrv->cut_copy_clear (op);
4005 struct lt_playlist {
4006 bool operator () (const PlaylistState& a, const PlaylistState& b) {
4007 return a.playlist < b.playlist;
4011 struct PlaylistMapping {
4013 boost::shared_ptr<Playlist> pl;
4015 PlaylistMapping (TimeAxisView* tvp) : tv (tvp) {}
4018 /** Remove `clicked_regionview' */
4020 Editor::remove_clicked_region ()
4022 if (clicked_routeview == 0 || clicked_regionview == 0) {
4026 boost::shared_ptr<Playlist> playlist = clicked_routeview->playlist();
4028 playlist->clear_changes ();
4029 playlist->clear_owned_changes ();
4030 playlist->remove_region (clicked_regionview->region());
4031 if (Config->get_edit_mode() == Ripple)
4032 playlist->ripple (clicked_regionview->region()->position(), -clicked_regionview->region()->length(), boost::shared_ptr<Region>());
4034 /* We might have removed regions, which alters other regions' layering_index,
4035 so we need to do a recursive diff here.
4037 vector<Command*> cmds;
4038 playlist->rdiff (cmds);
4039 _session->add_commands (cmds);
4041 _session->add_command(new StatefulDiffCommand (playlist));
4042 commit_reversible_command ();
4046 /** Remove the selected regions */
4048 Editor::remove_selected_regions ()
4050 RegionSelection rs = get_regions_from_selection_and_entered ();
4052 if (!_session || rs.empty()) {
4056 begin_reversible_command (_("remove region"));
4058 list<boost::shared_ptr<Region> > regions_to_remove;
4060 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
4061 // we can't just remove the region(s) in this loop because
4062 // this removes them from the RegionSelection, and they thus
4063 // disappear from underneath the iterator, and the ++i above
4064 // SEGVs in a puzzling fashion.
4066 // so, first iterate over the regions to be removed from rs and
4067 // add them to the regions_to_remove list, and then
4068 // iterate over the list to actually remove them.
4070 regions_to_remove.push_back ((*i)->region());
4073 vector<boost::shared_ptr<Playlist> > playlists;
4075 for (list<boost::shared_ptr<Region> >::iterator rl = regions_to_remove.begin(); rl != regions_to_remove.end(); ++rl) {
4077 boost::shared_ptr<Playlist> playlist = (*rl)->playlist();
4080 // is this check necessary?
4084 /* get_regions_from_selection_and_entered() guarantees that
4085 the playlists involved are unique, so there is no need
4089 playlists.push_back (playlist);
4091 playlist->clear_changes ();
4092 playlist->clear_owned_changes ();
4093 playlist->freeze ();
4094 playlist->remove_region (*rl);
4095 if (Config->get_edit_mode() == Ripple)
4096 playlist->ripple ((*rl)->position(), -(*rl)->length(), boost::shared_ptr<Region>());
4100 vector<boost::shared_ptr<Playlist> >::iterator pl;
4102 for (pl = playlists.begin(); pl != playlists.end(); ++pl) {
4105 /* We might have removed regions, which alters other regions' layering_index,
4106 so we need to do a recursive diff here.
4108 vector<Command*> cmds;
4109 (*pl)->rdiff (cmds);
4110 _session->add_commands (cmds);
4112 _session->add_command(new StatefulDiffCommand (*pl));
4115 commit_reversible_command ();
4118 /** Cut, copy or clear selected regions.
4119 * @param op Operation (Cut, Copy or Clear)
4122 Editor::cut_copy_regions (CutCopyOp op, RegionSelection& rs)
4124 /* we can't use a std::map here because the ordering is important, and we can't trivially sort
4125 a map when we want ordered access to both elements. i think.
4128 vector<PlaylistMapping> pmap;
4130 framepos_t first_position = max_framepos;
4132 typedef set<boost::shared_ptr<Playlist> > FreezeList;
4133 FreezeList freezelist;
4135 /* get ordering correct before we cut/copy */
4137 rs.sort_by_position_and_track ();
4139 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
4141 first_position = min ((framepos_t) (*x)->region()->position(), first_position);
4143 if (op == Cut || op == Clear || op == Delete) {
4144 boost::shared_ptr<Playlist> pl = (*x)->region()->playlist();
4147 FreezeList::iterator fl;
4149 // only take state if this is a new playlist.
4150 for (fl = freezelist.begin(); fl != freezelist.end(); ++fl) {
4156 if (fl == freezelist.end()) {
4157 pl->clear_changes();
4158 pl->clear_owned_changes ();
4160 freezelist.insert (pl);
4165 TimeAxisView* tv = &(*x)->get_time_axis_view();
4166 vector<PlaylistMapping>::iterator z;
4168 for (z = pmap.begin(); z != pmap.end(); ++z) {
4169 if ((*z).tv == tv) {
4174 if (z == pmap.end()) {
4175 pmap.push_back (PlaylistMapping (tv));
4179 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ) {
4181 boost::shared_ptr<Playlist> pl = (*x)->region()->playlist();
4184 /* region not yet associated with a playlist (e.g. unfinished
4191 TimeAxisView& tv = (*x)->get_time_axis_view();
4192 boost::shared_ptr<Playlist> npl;
4193 RegionSelection::iterator tmp;
4200 vector<PlaylistMapping>::iterator z;
4202 for (z = pmap.begin(); z != pmap.end(); ++z) {
4203 if ((*z).tv == &tv) {
4208 assert (z != pmap.end());
4211 npl = PlaylistFactory::create (pl->data_type(), *_session, "cutlist", true);
4219 boost::shared_ptr<Region> r = (*x)->region();
4220 boost::shared_ptr<Region> _xx;
4226 pl->remove_region (r);
4227 if (Config->get_edit_mode() == Ripple)
4228 pl->ripple (r->position(), -r->length(), boost::shared_ptr<Region>());
4232 _xx = RegionFactory::create (r);
4233 npl->add_region (_xx, r->position() - first_position);
4234 pl->remove_region (r);
4235 if (Config->get_edit_mode() == Ripple)
4236 pl->ripple (r->position(), -r->length(), boost::shared_ptr<Region>());
4240 /* copy region before adding, so we're not putting same object into two different playlists */
4241 npl->add_region (RegionFactory::create (r), r->position() - first_position);
4245 pl->remove_region (r);
4246 if (Config->get_edit_mode() == Ripple)
4247 pl->ripple (r->position(), -r->length(), boost::shared_ptr<Region>());
4256 list<boost::shared_ptr<Playlist> > foo;
4258 /* the pmap is in the same order as the tracks in which selected regions occured */
4260 for (vector<PlaylistMapping>::iterator i = pmap.begin(); i != pmap.end(); ++i) {
4263 foo.push_back ((*i).pl);
4268 cut_buffer->set (foo);
4272 _last_cut_copy_source_track = 0;
4274 _last_cut_copy_source_track = pmap.front().tv;
4278 for (FreezeList::iterator pl = freezelist.begin(); pl != freezelist.end(); ++pl) {
4281 /* We might have removed regions, which alters other regions' layering_index,
4282 so we need to do a recursive diff here.
4284 vector<Command*> cmds;
4285 (*pl)->rdiff (cmds);
4286 _session->add_commands (cmds);
4288 _session->add_command (new StatefulDiffCommand (*pl));
4293 Editor::cut_copy_ranges (CutCopyOp op)
4295 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4297 /* Sort the track selection now, so that it if is used, the playlists
4298 selected by the calls below to cut_copy_clear are in the order that
4299 their tracks appear in the editor. This makes things like paste
4300 of ranges work properly.
4303 sort_track_selection (ts);
4306 if (!entered_track) {
4309 ts.push_back (entered_track);
4312 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4313 (*i)->cut_copy_clear (*selection, op);
4318 Editor::paste (float times, bool from_context)
4320 DEBUG_TRACE (DEBUG::CutNPaste, "paste to preferred edit pos\n");
4322 paste_internal (get_preferred_edit_position (false, from_context), times);
4326 Editor::mouse_paste ()
4331 if (!mouse_frame (where, ignored)) {
4336 paste_internal (where, 1);
4340 Editor::paste_internal (framepos_t position, float times)
4342 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("apparent paste position is %1\n", position));
4344 if (internal_editing()) {
4345 if (cut_buffer->midi_notes.empty()) {
4349 if (cut_buffer->empty()) {
4354 if (position == max_framepos) {
4355 position = get_preferred_edit_position();
4356 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("preferred edit position is %1\n", position));
4360 TrackViewList::iterator i;
4363 /* get everything in the correct order */
4365 if (_edit_point == Editing::EditAtMouse && entered_track) {
4366 /* With the mouse edit point, paste onto the track under the mouse */
4367 ts.push_back (entered_track);
4368 } else if (!selection->tracks.empty()) {
4369 /* Otherwise, if there are some selected tracks, paste to them */
4370 ts = selection->tracks.filter_to_unique_playlists ();
4371 sort_track_selection (ts);
4372 } else if (_last_cut_copy_source_track) {
4373 /* Otherwise paste to the track that the cut/copy came from;
4374 see discussion in mantis #3333.
4376 ts.push_back (_last_cut_copy_source_track);
4379 if (internal_editing ()) {
4381 /* undo/redo is handled by individual tracks/regions */
4383 for (nth = 0, i = ts.begin(); i != ts.end(); ++i, ++nth) {
4386 RegionSelection::iterator r;
4387 MidiNoteSelection::iterator cb;
4389 get_regions_at (rs, position, ts);
4391 for (cb = cut_buffer->midi_notes.begin(), r = rs.begin();
4392 cb != cut_buffer->midi_notes.end() && r != rs.end(); ++r) {
4393 MidiRegionView* mrv = dynamic_cast<MidiRegionView*> (*r);
4395 mrv->paste (position, times, **cb);
4403 /* we do redo (do you do voodoo?) */
4405 begin_reversible_command (Operations::paste);
4407 for (nth = 0, i = ts.begin(); i != ts.end(); ++i, ++nth) {
4408 (*i)->paste (position, times, *cut_buffer, nth);
4411 commit_reversible_command ();
4416 Editor::duplicate_some_regions (RegionSelection& regions, float times)
4418 boost::shared_ptr<Playlist> playlist;
4419 RegionSelection sel = regions; // clear (below) may clear the argument list if its the current region selection
4420 RegionSelection foo;
4422 framepos_t const start_frame = regions.start ();
4423 framepos_t const end_frame = regions.end_frame ();
4425 begin_reversible_command (Operations::duplicate_region);
4427 selection->clear_regions ();
4429 for (RegionSelection::iterator i = sel.begin(); i != sel.end(); ++i) {
4431 boost::shared_ptr<Region> r ((*i)->region());
4433 TimeAxisView& tv = (*i)->get_time_axis_view();
4434 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (&tv);
4435 latest_regionviews.clear ();
4436 sigc::connection c = rtv->view()->RegionViewAdded.connect (sigc::mem_fun(*this, &Editor::collect_new_region_view));
4438 playlist = (*i)->region()->playlist();
4439 playlist->clear_changes ();
4440 playlist->duplicate (r, end_frame + (r->first_frame() - start_frame), times);
4441 _session->add_command(new StatefulDiffCommand (playlist));
4445 foo.insert (foo.end(), latest_regionviews.begin(), latest_regionviews.end());
4448 commit_reversible_command ();
4451 selection->set (foo);
4456 Editor::duplicate_selection (float times)
4458 if (selection->time.empty() || selection->tracks.empty()) {
4462 boost::shared_ptr<Playlist> playlist;
4463 vector<boost::shared_ptr<Region> > new_regions;
4464 vector<boost::shared_ptr<Region> >::iterator ri;
4466 create_region_from_selection (new_regions);
4468 if (new_regions.empty()) {
4472 begin_reversible_command (_("duplicate selection"));
4474 ri = new_regions.begin();
4476 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4478 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4479 if ((playlist = (*i)->playlist()) == 0) {
4482 playlist->clear_changes ();
4483 playlist->duplicate (*ri, selection->time[clicked_selection].end, times);
4484 _session->add_command (new StatefulDiffCommand (playlist));
4487 if (ri == new_regions.end()) {
4492 commit_reversible_command ();
4495 /** Reset all selected points to the relevant default value */
4497 Editor::reset_point_selection ()
4499 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
4500 ARDOUR::AutomationList::iterator j = (*i)->model ();
4501 (*j)->value = (*i)->line().the_list()->default_value ();
4506 Editor::center_playhead ()
4508 float const page = _visible_canvas_width * samples_per_pixel;
4509 center_screen_internal (playhead_cursor->current_frame (), page);
4513 Editor::center_edit_point ()
4515 float const page = _visible_canvas_width * samples_per_pixel;
4516 center_screen_internal (get_preferred_edit_position(), page);
4519 /** Caller must begin and commit a reversible command */
4521 Editor::clear_playlist (boost::shared_ptr<Playlist> playlist)
4523 playlist->clear_changes ();
4525 _session->add_command (new StatefulDiffCommand (playlist));
4529 Editor::nudge_track (bool use_edit, bool forwards)
4531 boost::shared_ptr<Playlist> playlist;
4532 framepos_t distance;
4533 framepos_t next_distance;
4537 start = get_preferred_edit_position();
4542 if ((distance = get_nudge_distance (start, next_distance)) == 0) {
4546 if (selection->tracks.empty()) {
4550 begin_reversible_command (_("nudge track"));
4552 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4554 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4556 if ((playlist = (*i)->playlist()) == 0) {
4560 playlist->clear_changes ();
4561 playlist->clear_owned_changes ();
4563 playlist->nudge_after (start, distance, forwards);
4565 vector<Command*> cmds;
4567 playlist->rdiff (cmds);
4568 _session->add_commands (cmds);
4570 _session->add_command (new StatefulDiffCommand (playlist));
4573 commit_reversible_command ();
4577 Editor::remove_last_capture ()
4579 vector<string> choices;
4586 if (Config->get_verify_remove_last_capture()) {
4587 prompt = _("Do you really want to destroy the last capture?"
4588 "\n(This is destructive and cannot be undone)");
4590 choices.push_back (_("No, do nothing."));
4591 choices.push_back (_("Yes, destroy it."));
4593 Gtkmm2ext::Choice prompter (_("Destroy last capture"), prompt, choices);
4595 if (prompter.run () == 1) {
4596 _session->remove_last_capture ();
4597 _regions->redisplay ();
4601 _session->remove_last_capture();
4602 _regions->redisplay ();
4607 Editor::normalize_region ()
4613 RegionSelection rs = get_regions_from_selection_and_entered ();
4619 NormalizeDialog dialog (rs.size() > 1);
4621 if (dialog.run () == RESPONSE_CANCEL) {
4625 set_canvas_cursor (_cursors->wait);
4628 /* XXX: should really only count audio regions here */
4629 int const regions = rs.size ();
4631 /* Make a list of the selected audio regions' maximum amplitudes, and also
4632 obtain the maximum amplitude of them all.
4634 list<double> max_amps;
4636 for (RegionSelection::const_iterator i = rs.begin(); i != rs.end(); ++i) {
4637 AudioRegionView const * arv = dynamic_cast<AudioRegionView const *> (*i);
4639 dialog.descend (1.0 / regions);
4640 double const a = arv->audio_region()->maximum_amplitude (&dialog);
4643 /* the user cancelled the operation */
4644 set_canvas_cursor (current_canvas_cursor);
4648 max_amps.push_back (a);
4649 max_amp = max (max_amp, a);
4654 begin_reversible_command (_("normalize"));
4656 list<double>::const_iterator a = max_amps.begin ();
4658 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
4659 AudioRegionView* const arv = dynamic_cast<AudioRegionView*> (*r);
4664 arv->region()->clear_changes ();
4666 double const amp = dialog.normalize_individually() ? *a : max_amp;
4668 arv->audio_region()->normalize (amp, dialog.target ());
4669 _session->add_command (new StatefulDiffCommand (arv->region()));
4674 commit_reversible_command ();
4675 set_canvas_cursor (current_canvas_cursor);
4680 Editor::reset_region_scale_amplitude ()
4686 RegionSelection rs = get_regions_from_selection_and_entered ();
4692 begin_reversible_command ("reset gain");
4694 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
4695 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
4698 arv->region()->clear_changes ();
4699 arv->audio_region()->set_scale_amplitude (1.0f);
4700 _session->add_command (new StatefulDiffCommand (arv->region()));
4703 commit_reversible_command ();
4707 Editor::adjust_region_gain (bool up)
4709 RegionSelection rs = get_regions_from_selection_and_entered ();
4711 if (!_session || rs.empty()) {
4715 begin_reversible_command ("adjust region gain");
4717 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
4718 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
4723 arv->region()->clear_changes ();
4725 double dB = accurate_coefficient_to_dB (arv->audio_region()->scale_amplitude ());
4733 arv->audio_region()->set_scale_amplitude (dB_to_coefficient (dB));
4734 _session->add_command (new StatefulDiffCommand (arv->region()));
4737 commit_reversible_command ();
4742 Editor::reverse_region ()
4748 Reverse rev (*_session);
4749 apply_filter (rev, _("reverse regions"));
4753 Editor::strip_region_silence ()
4759 RegionSelection rs = get_regions_from_selection_and_entered ();
4765 std::list<RegionView*> audio_only;
4767 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
4768 AudioRegionView* const arv = dynamic_cast<AudioRegionView*> (*i);
4770 audio_only.push_back (arv);
4774 StripSilenceDialog d (_session, audio_only);
4775 int const r = d.run ();
4779 if (r == Gtk::RESPONSE_OK) {
4780 ARDOUR::AudioIntervalMap silences;
4781 d.silences (silences);
4782 StripSilence s (*_session, silences, d.fade_length());
4783 apply_filter (s, _("strip silence"), &d);
4788 Editor::apply_midi_note_edit_op_to_region (MidiOperator& op, MidiRegionView& mrv)
4790 Evoral::Sequence<Evoral::MusicalTime>::Notes selected;
4791 mrv.selection_as_notelist (selected, true);
4793 vector<Evoral::Sequence<Evoral::MusicalTime>::Notes> v;
4794 v.push_back (selected);
4796 framepos_t pos_frames = mrv.midi_region()->position() - mrv.midi_region()->start();
4797 double pos_beats = _session->tempo_map().framewalk_to_beats(0, pos_frames);
4799 return op (mrv.midi_region()->model(), pos_beats, v);
4803 Editor::apply_midi_note_edit_op (MidiOperator& op)
4807 RegionSelection rs = get_regions_from_selection_and_entered ();
4813 begin_reversible_command (op.name ());
4815 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
4816 RegionSelection::iterator tmp = r;
4819 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*r);
4822 cmd = apply_midi_note_edit_op_to_region (op, *mrv);
4825 _session->add_command (cmd);
4832 commit_reversible_command ();
4836 Editor::fork_region ()
4838 RegionSelection rs = get_regions_from_selection_and_entered ();
4844 begin_reversible_command (_("Fork Region(s)"));
4846 set_canvas_cursor (_cursors->wait);
4849 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
4850 RegionSelection::iterator tmp = r;
4853 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*>(*r);
4857 boost::shared_ptr<Playlist> playlist = mrv->region()->playlist();
4858 boost::shared_ptr<MidiSource> new_source = _session->create_midi_source_by_stealing_name (mrv->midi_view()->track());
4859 boost::shared_ptr<MidiRegion> newregion = mrv->midi_region()->clone (new_source);
4861 playlist->clear_changes ();
4862 playlist->replace_region (mrv->region(), newregion, mrv->region()->position());
4863 _session->add_command(new StatefulDiffCommand (playlist));
4865 error << string_compose (_("Could not unlink %1"), mrv->region()->name()) << endmsg;
4872 commit_reversible_command ();
4874 set_canvas_cursor (current_canvas_cursor);
4878 Editor::quantize_region ()
4880 int selected_midi_region_cnt = 0;
4886 RegionSelection rs = get_regions_from_selection_and_entered ();
4892 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
4893 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*r);
4895 selected_midi_region_cnt++;
4899 if (selected_midi_region_cnt == 0) {
4903 QuantizeDialog* qd = new QuantizeDialog (*this);
4906 const int r = qd->run ();
4909 if (r == Gtk::RESPONSE_OK) {
4910 Quantize quant (*_session, qd->snap_start(), qd->snap_end(),
4911 qd->start_grid_size(), qd->end_grid_size(),
4912 qd->strength(), qd->swing(), qd->threshold());
4914 apply_midi_note_edit_op (quant);
4919 Editor::insert_patch_change (bool from_context)
4921 RegionSelection rs = get_regions_from_selection_and_entered ();
4927 const framepos_t p = get_preferred_edit_position (false, from_context);
4929 /* XXX: bit of a hack; use the MIDNAM from the first selected region;
4930 there may be more than one, but the PatchChangeDialog can only offer
4931 one set of patch menus.
4933 MidiRegionView* first = dynamic_cast<MidiRegionView*> (rs.front ());
4935 Evoral::PatchChange<Evoral::MusicalTime> empty (0, 0, 0, 0);
4936 PatchChangeDialog d (0, _session, empty, first->instrument_info(), Gtk::Stock::ADD);
4938 if (d.run() == RESPONSE_CANCEL) {
4942 for (RegionSelection::iterator i = rs.begin (); i != rs.end(); ++i) {
4943 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*i);
4945 if (p >= mrv->region()->first_frame() && p <= mrv->region()->last_frame()) {
4946 mrv->add_patch_change (p - mrv->region()->position(), d.patch ());
4953 Editor::apply_filter (Filter& filter, string command, ProgressReporter* progress)
4955 RegionSelection rs = get_regions_from_selection_and_entered ();
4961 begin_reversible_command (command);
4963 set_canvas_cursor (_cursors->wait);
4967 int const N = rs.size ();
4969 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
4970 RegionSelection::iterator tmp = r;
4973 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
4975 boost::shared_ptr<Playlist> playlist = arv->region()->playlist();
4978 progress->descend (1.0 / N);
4981 if (arv->audio_region()->apply (filter, progress) == 0) {
4983 playlist->clear_changes ();
4984 playlist->clear_owned_changes ();
4986 if (filter.results.empty ()) {
4988 /* no regions returned; remove the old one */
4989 playlist->remove_region (arv->region ());
4993 std::vector<boost::shared_ptr<Region> >::iterator res = filter.results.begin ();
4995 /* first region replaces the old one */
4996 playlist->replace_region (arv->region(), *res, (*res)->position());
5000 while (res != filter.results.end()) {
5001 playlist->add_region (*res, (*res)->position());
5007 /* We might have removed regions, which alters other regions' layering_index,
5008 so we need to do a recursive diff here.
5010 vector<Command*> cmds;
5011 playlist->rdiff (cmds);
5012 _session->add_commands (cmds);
5014 _session->add_command(new StatefulDiffCommand (playlist));
5020 progress->ascend ();
5028 commit_reversible_command ();
5031 set_canvas_cursor (current_canvas_cursor);
5035 Editor::external_edit_region ()
5041 Editor::reset_region_gain_envelopes ()
5043 RegionSelection rs = get_regions_from_selection_and_entered ();
5045 if (!_session || rs.empty()) {
5049 _session->begin_reversible_command (_("reset region gain"));
5051 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5052 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
5054 boost::shared_ptr<AutomationList> alist (arv->audio_region()->envelope());
5055 XMLNode& before (alist->get_state());
5057 arv->audio_region()->set_default_envelope ();
5058 _session->add_command (new MementoCommand<AutomationList>(*arv->audio_region()->envelope().get(), &before, &alist->get_state()));
5062 _session->commit_reversible_command ();
5066 Editor::set_region_gain_visibility (RegionView* rv)
5068 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (rv);
5070 arv->update_envelope_visibility();
5075 Editor::set_gain_envelope_visibility ()
5081 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5082 AudioTimeAxisView* v = dynamic_cast<AudioTimeAxisView*>(*i);
5084 v->audio_view()->foreach_regionview (sigc::mem_fun (this, &Editor::set_region_gain_visibility));
5090 Editor::toggle_gain_envelope_active ()
5092 if (_ignore_region_action) {
5096 RegionSelection rs = get_regions_from_selection_and_entered ();
5098 if (!_session || rs.empty()) {
5102 _session->begin_reversible_command (_("region gain envelope active"));
5104 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5105 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
5107 arv->region()->clear_changes ();
5108 arv->audio_region()->set_envelope_active (!arv->audio_region()->envelope_active());
5109 _session->add_command (new StatefulDiffCommand (arv->region()));
5113 _session->commit_reversible_command ();
5117 Editor::toggle_region_lock ()
5119 if (_ignore_region_action) {
5123 RegionSelection rs = get_regions_from_selection_and_entered ();
5125 if (!_session || rs.empty()) {
5129 _session->begin_reversible_command (_("toggle region lock"));
5131 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5132 (*i)->region()->clear_changes ();
5133 (*i)->region()->set_locked (!(*i)->region()->locked());
5134 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5137 _session->commit_reversible_command ();
5141 Editor::toggle_region_video_lock ()
5143 if (_ignore_region_action) {
5147 RegionSelection rs = get_regions_from_selection_and_entered ();
5149 if (!_session || rs.empty()) {
5153 _session->begin_reversible_command (_("Toggle Video Lock"));
5155 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5156 (*i)->region()->clear_changes ();
5157 (*i)->region()->set_video_locked (!(*i)->region()->video_locked());
5158 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5161 _session->commit_reversible_command ();
5165 Editor::toggle_region_lock_style ()
5167 if (_ignore_region_action) {
5171 RegionSelection rs = get_regions_from_selection_and_entered ();
5173 if (!_session || rs.empty()) {
5177 _session->begin_reversible_command (_("region lock style"));
5179 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5180 (*i)->region()->clear_changes ();
5181 PositionLockStyle const ns = (*i)->region()->position_lock_style() == AudioTime ? MusicTime : AudioTime;
5182 (*i)->region()->set_position_lock_style (ns);
5183 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5186 _session->commit_reversible_command ();
5190 Editor::toggle_opaque_region ()
5192 if (_ignore_region_action) {
5196 RegionSelection rs = get_regions_from_selection_and_entered ();
5198 if (!_session || rs.empty()) {
5202 _session->begin_reversible_command (_("change region opacity"));
5204 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5205 (*i)->region()->clear_changes ();
5206 (*i)->region()->set_opaque (!(*i)->region()->opaque());
5207 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5210 _session->commit_reversible_command ();
5214 Editor::toggle_record_enable ()
5216 bool new_state = false;
5218 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5219 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5222 if (!rtav->is_track())
5226 new_state = !rtav->track()->record_enabled();
5230 rtav->track()->set_record_enabled (new_state, this);
5235 Editor::toggle_solo ()
5237 bool new_state = false;
5239 boost::shared_ptr<RouteList> rl (new RouteList);
5241 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5242 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5249 new_state = !rtav->route()->soloed ();
5253 rl->push_back (rtav->route());
5256 _session->set_solo (rl, new_state, Session::rt_cleanup, true);
5260 Editor::toggle_mute ()
5262 bool new_state = false;
5264 boost::shared_ptr<RouteList> rl (new RouteList);
5266 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5267 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5274 new_state = !rtav->route()->muted();
5278 rl->push_back (rtav->route());
5281 _session->set_mute (rl, new_state, Session::rt_cleanup, true);
5285 Editor::toggle_solo_isolate ()
5290 Editor::set_fade_length (bool in)
5292 RegionSelection rs = get_regions_from_selection_and_entered ();
5298 /* we need a region to measure the offset from the start */
5300 RegionView* rv = rs.front ();
5302 framepos_t pos = get_preferred_edit_position();
5306 if (pos > rv->region()->last_frame() || pos < rv->region()->first_frame()) {
5307 /* edit point is outside the relevant region */
5312 if (pos <= rv->region()->position()) {
5316 len = pos - rv->region()->position();
5317 cmd = _("set fade in length");
5319 if (pos >= rv->region()->last_frame()) {
5323 len = rv->region()->last_frame() - pos;
5324 cmd = _("set fade out length");
5327 begin_reversible_command (cmd);
5329 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5330 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5336 boost::shared_ptr<AutomationList> alist;
5338 alist = tmp->audio_region()->fade_in();
5340 alist = tmp->audio_region()->fade_out();
5343 XMLNode &before = alist->get_state();
5346 tmp->audio_region()->set_fade_in_length (len);
5347 tmp->audio_region()->set_fade_in_active (true);
5349 tmp->audio_region()->set_fade_out_length (len);
5350 tmp->audio_region()->set_fade_out_active (true);
5353 XMLNode &after = alist->get_state();
5354 _session->add_command(new MementoCommand<AutomationList>(*alist, &before, &after));
5357 commit_reversible_command ();
5361 Editor::set_fade_in_shape (FadeShape shape)
5363 RegionSelection rs = get_regions_from_selection_and_entered ();
5369 begin_reversible_command (_("set fade in shape"));
5371 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5372 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5378 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_in();
5379 XMLNode &before = alist->get_state();
5381 tmp->audio_region()->set_fade_in_shape (shape);
5383 XMLNode &after = alist->get_state();
5384 _session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
5387 commit_reversible_command ();
5392 Editor::set_fade_out_shape (FadeShape shape)
5394 RegionSelection rs = get_regions_from_selection_and_entered ();
5400 begin_reversible_command (_("set fade out shape"));
5402 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5403 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5409 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_out();
5410 XMLNode &before = alist->get_state();
5412 tmp->audio_region()->set_fade_out_shape (shape);
5414 XMLNode &after = alist->get_state();
5415 _session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
5418 commit_reversible_command ();
5422 Editor::set_fade_in_active (bool yn)
5424 RegionSelection rs = get_regions_from_selection_and_entered ();
5430 begin_reversible_command (_("set fade in active"));
5432 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5433 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5440 boost::shared_ptr<AudioRegion> ar (tmp->audio_region());
5442 ar->clear_changes ();
5443 ar->set_fade_in_active (yn);
5444 _session->add_command (new StatefulDiffCommand (ar));
5447 commit_reversible_command ();
5451 Editor::set_fade_out_active (bool yn)
5453 RegionSelection rs = get_regions_from_selection_and_entered ();
5459 begin_reversible_command (_("set fade out active"));
5461 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5462 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5468 boost::shared_ptr<AudioRegion> ar (tmp->audio_region());
5470 ar->clear_changes ();
5471 ar->set_fade_out_active (yn);
5472 _session->add_command(new StatefulDiffCommand (ar));
5475 commit_reversible_command ();
5479 Editor::toggle_region_fades (int dir)
5481 if (_ignore_region_action) {
5485 boost::shared_ptr<AudioRegion> ar;
5488 RegionSelection rs = get_regions_from_selection_and_entered ();
5494 RegionSelection::iterator i;
5495 for (i = rs.begin(); i != rs.end(); ++i) {
5496 if ((ar = boost::dynamic_pointer_cast<AudioRegion>((*i)->region())) != 0) {
5498 yn = ar->fade_out_active ();
5500 yn = ar->fade_in_active ();
5506 if (i == rs.end()) {
5510 /* XXX should this undo-able? */
5512 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5513 if ((ar = boost::dynamic_pointer_cast<AudioRegion>((*i)->region())) == 0) {
5516 if (dir == 1 || dir == 0) {
5517 ar->set_fade_in_active (!yn);
5520 if (dir == -1 || dir == 0) {
5521 ar->set_fade_out_active (!yn);
5527 /** Update region fade visibility after its configuration has been changed */
5529 Editor::update_region_fade_visibility ()
5531 bool _fade_visibility = _session->config.get_show_region_fades ();
5533 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5534 AudioTimeAxisView* v = dynamic_cast<AudioTimeAxisView*>(*i);
5536 if (_fade_visibility) {
5537 v->audio_view()->show_all_fades ();
5539 v->audio_view()->hide_all_fades ();
5546 Editor::set_edit_point ()
5551 if (!mouse_frame (where, ignored)) {
5557 if (selection->markers.empty()) {
5559 mouse_add_new_marker (where);
5564 Location* loc = find_location_from_marker (selection->markers.front(), ignored);
5567 loc->move_to (where);
5573 Editor::set_playhead_cursor ()
5575 if (entered_marker) {
5576 _session->request_locate (entered_marker->position(), _session->transport_rolling());
5581 if (!mouse_frame (where, ignored)) {
5588 _session->request_locate (where, _session->transport_rolling());
5592 if ( Config->get_follow_edits() )
5593 cancel_time_selection();
5597 Editor::split_region ()
5599 if ( !selection->time.empty()) {
5600 separate_regions_between (selection->time);
5604 RegionSelection rs = get_regions_from_selection_and_edit_point ();
5606 framepos_t where = get_preferred_edit_position ();
5612 split_regions_at (where, rs);
5615 struct EditorOrderRouteSorter {
5616 bool operator() (boost::shared_ptr<Route> a, boost::shared_ptr<Route> b) {
5617 return a->order_key () < b->order_key ();
5622 Editor::select_next_route()
5624 if (selection->tracks.empty()) {
5625 selection->set (track_views.front());
5629 TimeAxisView* current = selection->tracks.front();
5633 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5634 if (*i == current) {
5636 if (i != track_views.end()) {
5639 current = (*(track_views.begin()));
5640 //selection->set (*(track_views.begin()));
5645 rui = dynamic_cast<RouteUI *>(current);
5646 } while ( current->hidden() || (rui != NULL && !rui->route()->active()));
5648 selection->set(current);
5650 ensure_time_axis_view_is_visible (*current);
5654 Editor::select_prev_route()
5656 if (selection->tracks.empty()) {
5657 selection->set (track_views.front());
5661 TimeAxisView* current = selection->tracks.front();
5665 for (TrackViewList::reverse_iterator i = track_views.rbegin(); i != track_views.rend(); ++i) {
5666 if (*i == current) {
5668 if (i != track_views.rend()) {
5671 current = *(track_views.rbegin());
5676 rui = dynamic_cast<RouteUI *>(current);
5677 } while ( current->hidden() || (rui != NULL && !rui->route()->active()));
5679 selection->set (current);
5681 ensure_time_axis_view_is_visible (*current);
5685 Editor::set_loop_from_selection (bool play)
5687 if (_session == 0 || selection->time.empty()) {
5691 framepos_t start = selection->time[clicked_selection].start;
5692 framepos_t end = selection->time[clicked_selection].end;
5694 set_loop_range (start, end, _("set loop range from selection"));
5697 _session->request_play_loop (true);
5698 _session->request_locate (start, true);
5703 Editor::set_loop_from_edit_range (bool play)
5705 if (_session == 0) {
5712 if (!get_edit_op_range (start, end)) {
5716 set_loop_range (start, end, _("set loop range from edit range"));
5719 _session->request_play_loop (true);
5720 _session->request_locate (start, true);
5725 Editor::set_loop_from_region (bool play)
5727 framepos_t start = max_framepos;
5730 RegionSelection rs = get_regions_from_selection_and_entered ();
5736 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5737 if ((*i)->region()->position() < start) {
5738 start = (*i)->region()->position();
5740 if ((*i)->region()->last_frame() + 1 > end) {
5741 end = (*i)->region()->last_frame() + 1;
5745 set_loop_range (start, end, _("set loop range from region"));
5748 _session->request_play_loop (true);
5749 _session->request_locate (start, true);
5754 Editor::set_punch_from_selection ()
5756 if (_session == 0 || selection->time.empty()) {
5760 framepos_t start = selection->time[clicked_selection].start;
5761 framepos_t end = selection->time[clicked_selection].end;
5763 set_punch_range (start, end, _("set punch range from selection"));
5767 Editor::set_punch_from_edit_range ()
5769 if (_session == 0) {
5776 if (!get_edit_op_range (start, end)) {
5780 set_punch_range (start, end, _("set punch range from edit range"));
5784 Editor::set_punch_from_region ()
5786 framepos_t start = max_framepos;
5789 RegionSelection rs = get_regions_from_selection_and_entered ();
5795 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5796 if ((*i)->region()->position() < start) {
5797 start = (*i)->region()->position();
5799 if ((*i)->region()->last_frame() + 1 > end) {
5800 end = (*i)->region()->last_frame() + 1;
5804 set_punch_range (start, end, _("set punch range from region"));
5808 Editor::pitch_shift_region ()
5810 RegionSelection rs = get_regions_from_selection_and_entered ();
5812 RegionSelection audio_rs;
5813 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5814 if (dynamic_cast<AudioRegionView*> (*i)) {
5815 audio_rs.push_back (*i);
5819 if (audio_rs.empty()) {
5823 pitch_shift (audio_rs, 1.2);
5827 Editor::transpose_region ()
5829 RegionSelection rs = get_regions_from_selection_and_entered ();
5831 list<MidiRegionView*> midi_region_views;
5832 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5833 MidiRegionView* mrv = dynamic_cast<MidiRegionView*> (*i);
5835 midi_region_views.push_back (mrv);
5840 int const r = d.run ();
5841 if (r != RESPONSE_ACCEPT) {
5845 for (list<MidiRegionView*>::iterator i = midi_region_views.begin(); i != midi_region_views.end(); ++i) {
5846 (*i)->midi_region()->transpose (d.semitones ());
5851 Editor::set_tempo_from_region ()
5853 RegionSelection rs = get_regions_from_selection_and_entered ();
5855 if (!_session || rs.empty()) {
5859 RegionView* rv = rs.front();
5861 define_one_bar (rv->region()->position(), rv->region()->last_frame() + 1);
5865 Editor::use_range_as_bar ()
5867 framepos_t start, end;
5868 if (get_edit_op_range (start, end)) {
5869 define_one_bar (start, end);
5874 Editor::define_one_bar (framepos_t start, framepos_t end)
5876 framepos_t length = end - start;
5878 const Meter& m (_session->tempo_map().meter_at (start));
5880 /* length = 1 bar */
5882 /* now we want frames per beat.
5883 we have frames per bar, and beats per bar, so ...
5886 /* XXXX METER MATH */
5888 double frames_per_beat = length / m.divisions_per_bar();
5890 /* beats per minute = */
5892 double beats_per_minute = (_session->frame_rate() * 60.0) / frames_per_beat;
5894 /* now decide whether to:
5896 (a) set global tempo
5897 (b) add a new tempo marker
5901 const TempoSection& t (_session->tempo_map().tempo_section_at (start));
5903 bool do_global = false;
5905 if ((_session->tempo_map().n_tempos() == 1) && (_session->tempo_map().n_meters() == 1)) {
5907 /* only 1 tempo & 1 meter: ask if the user wants to set the tempo
5908 at the start, or create a new marker
5911 vector<string> options;
5912 options.push_back (_("Cancel"));
5913 options.push_back (_("Add new marker"));
5914 options.push_back (_("Set global tempo"));
5917 _("Define one bar"),
5918 _("Do you want to set the global tempo or add a new tempo marker?"),
5922 c.set_default_response (2);
5938 /* more than 1 tempo and/or meter section already, go ahead do the "usual":
5939 if the marker is at the region starter, change it, otherwise add
5944 begin_reversible_command (_("set tempo from region"));
5945 XMLNode& before (_session->tempo_map().get_state());
5948 _session->tempo_map().change_initial_tempo (beats_per_minute, t.note_type());
5949 } else if (t.frame() == start) {
5950 _session->tempo_map().change_existing_tempo_at (start, beats_per_minute, t.note_type());
5952 Timecode::BBT_Time bbt;
5953 _session->tempo_map().bbt_time (start, bbt);
5954 _session->tempo_map().add_tempo (Tempo (beats_per_minute, t.note_type()), bbt);
5957 XMLNode& after (_session->tempo_map().get_state());
5959 _session->add_command (new MementoCommand<TempoMap>(_session->tempo_map(), &before, &after));
5960 commit_reversible_command ();
5964 Editor::split_region_at_transients ()
5966 AnalysisFeatureList positions;
5968 RegionSelection rs = get_regions_from_selection_and_entered ();
5970 if (!_session || rs.empty()) {
5974 _session->begin_reversible_command (_("split regions"));
5976 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ) {
5978 RegionSelection::iterator tmp;
5983 boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion> ((*i)->region());
5985 if (ar && (ar->get_transients (positions) == 0)) {
5986 split_region_at_points ((*i)->region(), positions, true);
5993 _session->commit_reversible_command ();
5998 Editor::split_region_at_points (boost::shared_ptr<Region> r, AnalysisFeatureList& positions, bool can_ferret, bool select_new)
6000 bool use_rhythmic_rodent = false;
6002 boost::shared_ptr<Playlist> pl = r->playlist();
6004 list<boost::shared_ptr<Region> > new_regions;
6010 if (positions.empty()) {
6015 if (positions.size() > 20 && can_ferret) {
6016 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);
6017 MessageDialog msg (msgstr,
6020 Gtk::BUTTONS_OK_CANCEL);
6023 msg.add_button (_("Call for the Ferret!"), RESPONSE_APPLY);
6024 msg.set_secondary_text (_("Press OK to continue with this split operation\nor ask the Ferret dialog to tune the analysis"));
6026 msg.set_secondary_text (_("Press OK to continue with this split operation"));
6029 msg.set_title (_("Excessive split?"));
6032 int response = msg.run();
6038 case RESPONSE_APPLY:
6039 use_rhythmic_rodent = true;
6046 if (use_rhythmic_rodent) {
6047 show_rhythm_ferret ();
6051 AnalysisFeatureList::const_iterator x;
6053 pl->clear_changes ();
6054 pl->clear_owned_changes ();
6056 x = positions.begin();
6058 if (x == positions.end()) {
6063 pl->remove_region (r);
6067 while (x != positions.end()) {
6069 /* deal with positons that are out of scope of present region bounds */
6070 if (*x <= 0 || *x > r->length()) {
6075 /* file start = original start + how far we from the initial position ?
6078 framepos_t file_start = r->start() + pos;
6080 /* length = next position - current position
6083 framepos_t len = (*x) - pos;
6085 /* XXX we do we really want to allow even single-sample regions?
6086 shouldn't we have some kind of lower limit on region size?
6095 if (RegionFactory::region_name (new_name, r->name())) {
6099 /* do NOT announce new regions 1 by one, just wait till they are all done */
6103 plist.add (ARDOUR::Properties::start, file_start);
6104 plist.add (ARDOUR::Properties::length, len);
6105 plist.add (ARDOUR::Properties::name, new_name);
6106 plist.add (ARDOUR::Properties::layer, 0);
6108 boost::shared_ptr<Region> nr = RegionFactory::create (r->sources(), plist, false);
6109 /* because we set annouce to false, manually add the new region to the
6112 RegionFactory::map_add (nr);
6114 pl->add_region (nr, r->position() + pos);
6117 new_regions.push_front(nr);
6126 RegionFactory::region_name (new_name, r->name());
6128 /* Add the final region */
6131 plist.add (ARDOUR::Properties::start, r->start() + pos);
6132 plist.add (ARDOUR::Properties::length, r->last_frame() - (r->position() + pos) + 1);
6133 plist.add (ARDOUR::Properties::name, new_name);
6134 plist.add (ARDOUR::Properties::layer, 0);
6136 boost::shared_ptr<Region> nr = RegionFactory::create (r->sources(), plist, false);
6137 /* because we set annouce to false, manually add the new region to the
6140 RegionFactory::map_add (nr);
6141 pl->add_region (nr, r->position() + pos);
6144 new_regions.push_front(nr);
6149 /* We might have removed regions, which alters other regions' layering_index,
6150 so we need to do a recursive diff here.
6152 vector<Command*> cmds;
6154 _session->add_commands (cmds);
6156 _session->add_command (new StatefulDiffCommand (pl));
6160 for (list<boost::shared_ptr<Region> >::iterator i = new_regions.begin(); i != new_regions.end(); ++i){
6161 set_selected_regionview_from_region_list ((*i), Selection::Add);
6167 Editor::place_transient()
6173 RegionSelection rs = get_regions_from_selection_and_edit_point ();
6179 framepos_t where = get_preferred_edit_position();
6181 _session->begin_reversible_command (_("place transient"));
6183 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6184 framepos_t position = (*r)->region()->position();
6185 (*r)->region()->add_transient(where - position);
6188 _session->commit_reversible_command ();
6192 Editor::remove_transient(ArdourCanvas::Item* item)
6198 ArdourCanvas::Line* _line = reinterpret_cast<ArdourCanvas::Line*> (item);
6201 AudioRegionView* _arv = reinterpret_cast<AudioRegionView*> (item->get_data ("regionview"));
6202 _arv->remove_transient (*(float*) _line->get_data ("position"));
6206 Editor::snap_regions_to_grid ()
6208 list <boost::shared_ptr<Playlist > > used_playlists;
6210 RegionSelection rs = get_regions_from_selection_and_entered ();
6212 if (!_session || rs.empty()) {
6216 _session->begin_reversible_command (_("snap regions to grid"));
6218 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6220 boost::shared_ptr<Playlist> pl = (*r)->region()->playlist();
6222 if (!pl->frozen()) {
6223 /* we haven't seen this playlist before */
6225 /* remember used playlists so we can thaw them later */
6226 used_playlists.push_back(pl);
6230 framepos_t start_frame = (*r)->region()->first_frame ();
6231 snap_to (start_frame);
6232 (*r)->region()->set_position (start_frame);
6235 while (used_playlists.size() > 0) {
6236 list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
6238 used_playlists.pop_front();
6241 _session->commit_reversible_command ();
6245 Editor::close_region_gaps ()
6247 list <boost::shared_ptr<Playlist > > used_playlists;
6249 RegionSelection rs = get_regions_from_selection_and_entered ();
6251 if (!_session || rs.empty()) {
6255 Dialog dialog (_("Close Region Gaps"));
6258 table.set_spacings (12);
6259 table.set_border_width (12);
6260 Label* l = manage (left_aligned_label (_("Crossfade length")));
6261 table.attach (*l, 0, 1, 0, 1);
6263 SpinButton spin_crossfade (1, 0);
6264 spin_crossfade.set_range (0, 15);
6265 spin_crossfade.set_increments (1, 1);
6266 spin_crossfade.set_value (5);
6267 table.attach (spin_crossfade, 1, 2, 0, 1);
6269 table.attach (*manage (new Label (_("ms"))), 2, 3, 0, 1);
6271 l = manage (left_aligned_label (_("Pull-back length")));
6272 table.attach (*l, 0, 1, 1, 2);
6274 SpinButton spin_pullback (1, 0);
6275 spin_pullback.set_range (0, 100);
6276 spin_pullback.set_increments (1, 1);
6277 spin_pullback.set_value(30);
6278 table.attach (spin_pullback, 1, 2, 1, 2);
6280 table.attach (*manage (new Label (_("ms"))), 2, 3, 1, 2);
6282 dialog.get_vbox()->pack_start (table);
6283 dialog.add_button (Stock::CANCEL, RESPONSE_CANCEL);
6284 dialog.add_button (_("Ok"), RESPONSE_ACCEPT);
6287 if (dialog.run () == RESPONSE_CANCEL) {
6291 framepos_t crossfade_len = spin_crossfade.get_value();
6292 framepos_t pull_back_frames = spin_pullback.get_value();
6294 crossfade_len = lrintf (crossfade_len * _session->frame_rate()/1000);
6295 pull_back_frames = lrintf (pull_back_frames * _session->frame_rate()/1000);
6297 /* Iterate over the region list and make adjacent regions overlap by crossfade_len_ms */
6299 _session->begin_reversible_command (_("close region gaps"));
6302 boost::shared_ptr<Region> last_region;
6304 rs.sort_by_position_and_track();
6306 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6308 boost::shared_ptr<Playlist> pl = (*r)->region()->playlist();
6310 if (!pl->frozen()) {
6311 /* we haven't seen this playlist before */
6313 /* remember used playlists so we can thaw them later */
6314 used_playlists.push_back(pl);
6318 framepos_t position = (*r)->region()->position();
6320 if (idx == 0 || position < last_region->position()){
6321 last_region = (*r)->region();
6326 (*r)->region()->trim_front( (position - pull_back_frames));
6327 last_region->trim_end( (position - pull_back_frames + crossfade_len));
6329 last_region = (*r)->region();
6334 while (used_playlists.size() > 0) {
6335 list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
6337 used_playlists.pop_front();
6340 _session->commit_reversible_command ();
6344 Editor::tab_to_transient (bool forward)
6346 AnalysisFeatureList positions;
6348 RegionSelection rs = get_regions_from_selection_and_entered ();
6354 framepos_t pos = _session->audible_frame ();
6356 if (!selection->tracks.empty()) {
6358 /* don't waste time searching for transients in duplicate playlists.
6361 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
6363 for (TrackViewList::iterator t = ts.begin(); t != ts.end(); ++t) {
6365 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*t);
6368 boost::shared_ptr<Track> tr = rtv->track();
6370 boost::shared_ptr<Playlist> pl = tr->playlist ();
6372 framepos_t result = pl->find_next_transient (pos, forward ? 1 : -1);
6375 positions.push_back (result);
6388 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6389 (*r)->region()->get_transients (positions);
6393 TransientDetector::cleanup_transients (positions, _session->frame_rate(), 3.0);
6396 AnalysisFeatureList::iterator x;
6398 for (x = positions.begin(); x != positions.end(); ++x) {
6404 if (x != positions.end ()) {
6405 _session->request_locate (*x);
6409 AnalysisFeatureList::reverse_iterator x;
6411 for (x = positions.rbegin(); x != positions.rend(); ++x) {
6417 if (x != positions.rend ()) {
6418 _session->request_locate (*x);
6424 Editor::playhead_forward_to_grid ()
6430 framepos_t pos = playhead_cursor->current_frame ();
6431 if (pos < max_framepos - 1) {
6433 snap_to_internal (pos, 1, false);
6434 _session->request_locate (pos);
6440 Editor::playhead_backward_to_grid ()
6446 framepos_t pos = playhead_cursor->current_frame ();
6449 snap_to_internal (pos, -1, false);
6450 _session->request_locate (pos);
6455 Editor::set_track_height (Height h)
6457 TrackSelection& ts (selection->tracks);
6459 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
6460 (*x)->set_height_enum (h);
6465 Editor::toggle_tracks_active ()
6467 TrackSelection& ts (selection->tracks);
6469 bool target = false;
6475 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
6476 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*x);
6480 target = !rtv->_route->active();
6483 rtv->_route->set_active (target, this);
6489 Editor::remove_tracks ()
6491 TrackSelection& ts (selection->tracks);
6497 vector<string> choices;
6501 const char* trackstr;
6503 vector<boost::shared_ptr<Route> > routes;
6504 bool special_bus = false;
6506 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
6507 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*x);
6511 if (rtv->is_track()) {
6516 routes.push_back (rtv->_route);
6518 if (rtv->route()->is_master() || rtv->route()->is_monitor()) {
6523 if (special_bus && !Config->get_allow_special_bus_removal()) {
6524 MessageDialog msg (_("That would be bad news ...."),
6528 msg.set_secondary_text (string_compose (_(
6529 "Removing the master or monitor bus is such a bad idea\n\
6530 that %1 is not going to allow it.\n\
6532 If you really want to do this sort of thing\n\
6533 edit your ardour.rc file to set the\n\
6534 \"allow-special-bus-removal\" option to be \"yes\""), PROGRAM_NAME));
6541 if (ntracks + nbusses == 0) {
6546 trackstr = _("tracks");
6548 trackstr = _("track");
6552 busstr = _("busses");
6559 prompt = string_compose (_("Do you really want to remove %1 %2 and %3 %4?\n"
6560 "(You may also lose the playlists associated with the %2)\n\n"
6561 "This action cannot be undone, and the session file will be overwritten!"),
6562 ntracks, trackstr, nbusses, busstr);
6564 prompt = string_compose (_("Do you really want to remove %1 %2?\n"
6565 "(You may also lose the playlists associated with the %2)\n\n"
6566 "This action cannot be undone, and the session file will be overwritten!"),
6569 } else if (nbusses) {
6570 prompt = string_compose (_("Do you really want to remove %1 %2?\n\n"
6571 "This action cannot be undon, and the session file will be overwritten"),
6575 choices.push_back (_("No, do nothing."));
6576 if (ntracks + nbusses > 1) {
6577 choices.push_back (_("Yes, remove them."));
6579 choices.push_back (_("Yes, remove it."));
6584 title = string_compose (_("Remove %1"), trackstr);
6586 title = string_compose (_("Remove %1"), busstr);
6589 Choice prompter (title, prompt, choices);
6591 if (prompter.run () != 1) {
6596 Session::StateProtector sp (_session);
6597 for (vector<boost::shared_ptr<Route> >::iterator x = routes.begin(); x != routes.end(); ++x) {
6598 _session->remove_route (*x);
6604 Editor::do_insert_time ()
6606 if (selection->tracks.empty()) {
6610 InsertTimeDialog d (*this);
6611 int response = d.run ();
6613 if (response != RESPONSE_OK) {
6617 if (d.distance() == 0) {
6621 InsertTimeOption opt = d.intersected_region_action ();
6624 get_preferred_edit_position(),
6630 d.move_glued_markers(),
6631 d.move_locked_markers(),
6637 Editor::insert_time (
6638 framepos_t pos, framecnt_t frames, InsertTimeOption opt,
6639 bool all_playlists, bool ignore_music_glue, bool markers_too, bool glued_markers_too, bool locked_markers_too, bool tempo_too
6642 bool commit = false;
6644 if (Config->get_edit_mode() == Lock) {
6648 begin_reversible_command (_("insert time"));
6650 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
6652 for (TrackViewList::iterator x = ts.begin(); x != ts.end(); ++x) {
6656 /* don't operate on any playlist more than once, which could
6657 * happen if "all playlists" is enabled, but there is more
6658 * than 1 track using playlists "from" a given track.
6661 set<boost::shared_ptr<Playlist> > pl;
6663 if (all_playlists) {
6664 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*x);
6666 vector<boost::shared_ptr<Playlist> > all = _session->playlists->playlists_for_track (rtav->track ());
6667 for (vector<boost::shared_ptr<Playlist> >::iterator p = all.begin(); p != all.end(); ++p) {
6672 if ((*x)->playlist ()) {
6673 pl.insert ((*x)->playlist ());
6677 for (set<boost::shared_ptr<Playlist> >::iterator i = pl.begin(); i != pl.end(); ++i) {
6679 (*i)->clear_changes ();
6680 (*i)->clear_owned_changes ();
6682 if (opt == SplitIntersected) {
6686 (*i)->shift (pos, frames, (opt == MoveIntersected), ignore_music_glue);
6688 vector<Command*> cmds;
6690 _session->add_commands (cmds);
6692 _session->add_command (new StatefulDiffCommand (*i));
6697 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*x);
6699 rtav->route ()->shift (pos, frames);
6707 XMLNode& before (_session->locations()->get_state());
6708 Locations::LocationList copy (_session->locations()->list());
6710 for (Locations::LocationList::iterator i = copy.begin(); i != copy.end(); ++i) {
6712 Locations::LocationList::const_iterator tmp;
6714 bool const was_locked = (*i)->locked ();
6715 if (locked_markers_too) {
6719 if ((*i)->position_lock_style() == AudioTime || glued_markers_too) {
6721 if ((*i)->start() >= pos) {
6722 (*i)->set_start ((*i)->start() + frames);
6723 if (!(*i)->is_mark()) {
6724 (*i)->set_end ((*i)->end() + frames);
6737 XMLNode& after (_session->locations()->get_state());
6738 _session->add_command (new MementoCommand<Locations>(*_session->locations(), &before, &after));
6743 _session->tempo_map().insert_time (pos, frames);
6747 commit_reversible_command ();
6752 Editor::fit_selected_tracks ()
6754 if (!selection->tracks.empty()) {
6755 fit_tracks (selection->tracks);
6759 /* no selected tracks - use tracks with selected regions */
6761 if (!selection->regions.empty()) {
6762 for (RegionSelection::iterator r = selection->regions.begin(); r != selection->regions.end(); ++r) {
6763 tvl.push_back (&(*r)->get_time_axis_view ());
6769 } else if (internal_editing()) {
6770 /* no selected tracks, or regions, but in internal edit mode, so follow the mouse and use
6773 if (entered_track) {
6774 tvl.push_back (entered_track);
6782 Editor::fit_tracks (TrackViewList & tracks)
6784 if (tracks.empty()) {
6788 uint32_t child_heights = 0;
6789 int visible_tracks = 0;
6791 for (TrackSelection::iterator t = tracks.begin(); t != tracks.end(); ++t) {
6793 if (!(*t)->marked_for_display()) {
6797 child_heights += (*t)->effective_height() - (*t)->current_height();
6801 /* compute the per-track height from:
6803 total canvas visible height -
6804 height that will be taken by visible children of selected
6805 tracks - height of the ruler/hscroll area
6807 uint32_t h = (uint32_t) floor ((_visible_canvas_height - (child_heights + _trackview_group->canvas_origin().y)) / visible_tracks);
6808 double first_y_pos = DBL_MAX;
6810 if (h < TimeAxisView::preset_height (HeightSmall)) {
6811 MessageDialog msg (*this, _("There are too many tracks to fit in the current window"));
6812 /* too small to be displayed */
6816 undo_visual_stack.push_back (current_visual_state (true));
6817 no_save_visual = true;
6819 /* build a list of all tracks, including children */
6822 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
6824 TimeAxisView::Children c = (*i)->get_child_list ();
6825 for (TimeAxisView::Children::iterator j = c.begin(); j != c.end(); ++j) {
6826 all.push_back (j->get());
6830 /* operate on all tracks, hide unselected ones that are in the middle of selected ones */
6832 bool within_selected = false;
6834 for (TrackViewList::iterator t = all.begin(); t != all.end(); ++t) {
6836 TrackViewList::iterator next;
6841 if ((*t)->marked_for_display ()) {
6842 if (tracks.contains (*t)) {
6843 (*t)->set_height (h);
6844 first_y_pos = std::min ((*t)->y_position (), first_y_pos);
6845 within_selected = true;
6846 } else if (within_selected) {
6847 hide_track_in_display (*t);
6853 set the controls_layout height now, because waiting for its size
6854 request signal handler will cause the vertical adjustment setting to fail
6857 controls_layout.property_height () = _full_canvas_height;
6858 vertical_adjustment.set_value (first_y_pos);
6860 redo_visual_stack.push_back (current_visual_state (true));
6864 Editor::save_visual_state (uint32_t n)
6866 while (visual_states.size() <= n) {
6867 visual_states.push_back (0);
6870 if (visual_states[n] != 0) {
6871 delete visual_states[n];
6874 visual_states[n] = current_visual_state (true);
6879 Editor::goto_visual_state (uint32_t n)
6881 if (visual_states.size() <= n) {
6885 if (visual_states[n] == 0) {
6889 use_visual_state (*visual_states[n]);
6893 Editor::start_visual_state_op (uint32_t n)
6895 save_visual_state (n);
6897 PopUp* pup = new PopUp (WIN_POS_MOUSE, 1000, true);
6899 snprintf (buf, sizeof (buf), _("Saved view %u"), n+1);
6900 pup->set_text (buf);
6905 Editor::cancel_visual_state_op (uint32_t n)
6907 goto_visual_state (n);
6911 Editor::toggle_region_mute ()
6913 if (_ignore_region_action) {
6917 RegionSelection rs = get_regions_from_selection_and_entered ();
6923 if (rs.size() > 1) {
6924 begin_reversible_command (_("mute regions"));
6926 begin_reversible_command (_("mute region"));
6929 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
6931 (*i)->region()->playlist()->clear_changes ();
6932 (*i)->region()->set_muted (!(*i)->region()->muted ());
6933 _session->add_command (new StatefulDiffCommand ((*i)->region()->playlist()));
6937 commit_reversible_command ();
6941 Editor::combine_regions ()
6943 /* foreach track with selected regions, take all selected regions
6944 and join them into a new region containing the subregions (as a
6948 typedef set<RouteTimeAxisView*> RTVS;
6951 if (selection->regions.empty()) {
6955 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
6956 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(&(*i)->get_time_axis_view());
6959 tracks.insert (rtv);
6963 begin_reversible_command (_("combine regions"));
6965 vector<RegionView*> new_selection;
6967 for (RTVS::iterator i = tracks.begin(); i != tracks.end(); ++i) {
6970 if ((rv = (*i)->combine_regions ()) != 0) {
6971 new_selection.push_back (rv);
6975 selection->clear_regions ();
6976 for (vector<RegionView*>::iterator i = new_selection.begin(); i != new_selection.end(); ++i) {
6977 selection->add (*i);
6980 commit_reversible_command ();
6984 Editor::uncombine_regions ()
6986 typedef set<RouteTimeAxisView*> RTVS;
6989 if (selection->regions.empty()) {
6993 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
6994 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(&(*i)->get_time_axis_view());
6997 tracks.insert (rtv);
7001 begin_reversible_command (_("uncombine regions"));
7003 for (RTVS::iterator i = tracks.begin(); i != tracks.end(); ++i) {
7004 (*i)->uncombine_regions ();
7007 commit_reversible_command ();
7011 Editor::toggle_midi_input_active (bool flip_others)
7014 boost::shared_ptr<RouteList> rl (new RouteList);
7016 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
7017 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
7023 boost::shared_ptr<MidiTrack> mt = rtav->midi_track();
7026 rl->push_back (rtav->route());
7027 onoff = !mt->input_active();
7031 _session->set_exclusive_input_active (rl, onoff, flip_others);
7038 lock_dialog = new Gtk::Dialog (string_compose (_("%1: Locked"), PROGRAM_NAME), true);
7040 Gtk::Image* padlock = manage (new Gtk::Image (ARDOUR_UI_UTILS::get_icon ("padlock_closed")));
7041 lock_dialog->get_vbox()->pack_start (*padlock);
7043 ArdourButton* b = manage (new ArdourButton);
7044 b->set_name ("lock button");
7045 b->set_markup (string_compose ("<span size=\"large\" weight=\"bold\">%1</span>", _("Click to unlock")));
7046 b->signal_clicked.connect (sigc::mem_fun (*this, &Editor::unlock));
7047 lock_dialog->get_vbox()->pack_start (*b);
7049 lock_dialog->get_vbox()->show_all ();
7050 lock_dialog->set_size_request (200, 200);
7054 /* The global menu bar continues to be accessible to applications
7055 with modal dialogs, which means that we need to desensitize
7056 all items in the menu bar. Since those items are really just
7057 proxies for actions, that means disabling all actions.
7059 ActionManager::disable_all_actions ();
7061 lock_dialog->present ();
7067 lock_dialog->hide ();
7070 ActionManager::pop_action_state ();
7073 if (ARDOUR_UI::config()->get_lock_gui_after_seconds()) {
7074 start_lock_event_timing ();