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;
138 if (regions.empty()) {
142 begin_reversible_command (_("split"));
144 // if splitting a single region, and snap-to is using
145 // region boundaries, don't pay attention to them
147 if (regions.size() == 1) {
148 switch (_snap_type) {
149 case SnapToRegionStart:
150 case SnapToRegionSync:
151 case SnapToRegionEnd:
160 EditorFreeze(); /* Emit Signal */
163 for (RegionSelection::iterator a = regions.begin(); a != regions.end(); ) {
165 RegionSelection::iterator tmp;
167 /* XXX this test needs to be more complicated, to make sure we really
168 have something to split.
171 if (!(*a)->region()->covers (where)) {
179 boost::shared_ptr<Playlist> pl = (*a)->region()->playlist();
187 /* we haven't seen this playlist before */
189 /* remember used playlists so we can thaw them later */
190 used_playlists.push_back(pl);
195 pl->clear_changes ();
196 pl->split_region ((*a)->region(), where);
197 _session->add_command (new StatefulDiffCommand (pl));
203 while (used_playlists.size() > 0) {
204 list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
206 used_playlists.pop_front();
209 commit_reversible_command ();
212 EditorThaw(); /* Emit Signal */
216 /** Move one extreme of the current range selection. If more than one range is selected,
217 * the start of the earliest range or the end of the latest range is moved.
219 * @param move_end true to move the end of the current range selection, false to move
221 * @param next true to move the extreme to the next region boundary, false to move to
225 Editor::move_range_selection_start_or_end_to_region_boundary (bool move_end, bool next)
227 if (selection->time.start() == selection->time.end_frame()) {
231 framepos_t start = selection->time.start ();
232 framepos_t end = selection->time.end_frame ();
234 /* the position of the thing we may move */
235 framepos_t pos = move_end ? end : start;
236 int dir = next ? 1 : -1;
238 /* so we don't find the current region again */
239 if (dir > 0 || pos > 0) {
243 framepos_t const target = get_region_boundary (pos, dir, true, false);
258 begin_reversible_command (_("alter selection"));
259 selection->set_preserving_all_ranges (start, end);
260 commit_reversible_command ();
264 Editor::nudge_forward_release (GdkEventButton* ev)
266 if (ev->state & Keyboard::PrimaryModifier) {
267 nudge_forward (false, true);
269 nudge_forward (false, false);
275 Editor::nudge_backward_release (GdkEventButton* ev)
277 if (ev->state & Keyboard::PrimaryModifier) {
278 nudge_backward (false, true);
280 nudge_backward (false, false);
287 Editor::nudge_forward (bool next, bool force_playhead)
290 framepos_t next_distance;
296 RegionSelection rs = get_regions_from_selection_and_entered ();
298 if (!force_playhead && !rs.empty()) {
300 begin_reversible_command (_("nudge regions forward"));
302 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
303 boost::shared_ptr<Region> r ((*i)->region());
305 distance = get_nudge_distance (r->position(), next_distance);
308 distance = next_distance;
312 r->set_position (r->position() + distance);
313 _session->add_command (new StatefulDiffCommand (r));
316 commit_reversible_command ();
319 } else if (!force_playhead && !selection->markers.empty()) {
323 begin_reversible_command (_("nudge location forward"));
325 for (MarkerSelection::iterator i = selection->markers.begin(); i != selection->markers.end(); ++i) {
327 Location* loc = find_location_from_marker ((*i), is_start);
331 XMLNode& before (loc->get_state());
334 distance = get_nudge_distance (loc->start(), next_distance);
336 distance = next_distance;
338 if (max_framepos - distance > loc->start() + loc->length()) {
339 loc->set_start (loc->start() + distance);
341 loc->set_start (max_framepos - loc->length());
344 distance = get_nudge_distance (loc->end(), next_distance);
346 distance = next_distance;
348 if (max_framepos - distance > loc->end()) {
349 loc->set_end (loc->end() + distance);
351 loc->set_end (max_framepos);
354 XMLNode& after (loc->get_state());
355 _session->add_command (new MementoCommand<Location>(*loc, &before, &after));
359 commit_reversible_command ();
362 distance = get_nudge_distance (playhead_cursor->current_frame (), next_distance);
363 _session->request_locate (playhead_cursor->current_frame () + distance);
368 Editor::nudge_backward (bool next, bool force_playhead)
371 framepos_t next_distance;
377 RegionSelection rs = get_regions_from_selection_and_entered ();
379 if (!force_playhead && !rs.empty()) {
381 begin_reversible_command (_("nudge regions backward"));
383 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
384 boost::shared_ptr<Region> r ((*i)->region());
386 distance = get_nudge_distance (r->position(), next_distance);
389 distance = next_distance;
394 if (r->position() > distance) {
395 r->set_position (r->position() - distance);
399 _session->add_command (new StatefulDiffCommand (r));
402 commit_reversible_command ();
404 } else if (!force_playhead && !selection->markers.empty()) {
408 begin_reversible_command (_("nudge location forward"));
410 for (MarkerSelection::iterator i = selection->markers.begin(); i != selection->markers.end(); ++i) {
412 Location* loc = find_location_from_marker ((*i), is_start);
416 XMLNode& before (loc->get_state());
419 distance = get_nudge_distance (loc->start(), next_distance);
421 distance = next_distance;
423 if (distance < loc->start()) {
424 loc->set_start (loc->start() - distance);
429 distance = get_nudge_distance (loc->end(), next_distance);
432 distance = next_distance;
435 if (distance < loc->end() - loc->length()) {
436 loc->set_end (loc->end() - distance);
438 loc->set_end (loc->length());
442 XMLNode& after (loc->get_state());
443 _session->add_command (new MementoCommand<Location>(*loc, &before, &after));
447 commit_reversible_command ();
451 distance = get_nudge_distance (playhead_cursor->current_frame (), next_distance);
453 if (playhead_cursor->current_frame () > distance) {
454 _session->request_locate (playhead_cursor->current_frame () - distance);
456 _session->goto_start();
462 Editor::nudge_forward_capture_offset ()
464 RegionSelection rs = get_regions_from_selection_and_entered ();
466 if (!_session || rs.empty()) {
470 begin_reversible_command (_("nudge forward"));
472 framepos_t const distance = _session->worst_output_latency();
474 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
475 boost::shared_ptr<Region> r ((*i)->region());
478 r->set_position (r->position() + distance);
479 _session->add_command(new StatefulDiffCommand (r));
482 commit_reversible_command ();
486 Editor::nudge_backward_capture_offset ()
488 RegionSelection rs = get_regions_from_selection_and_entered ();
490 if (!_session || rs.empty()) {
494 begin_reversible_command (_("nudge backward"));
496 framepos_t const distance = _session->worst_output_latency();
498 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
499 boost::shared_ptr<Region> r ((*i)->region());
503 if (r->position() > distance) {
504 r->set_position (r->position() - distance);
508 _session->add_command(new StatefulDiffCommand (r));
511 commit_reversible_command ();
514 struct RegionSelectionPositionSorter {
515 bool operator() (RegionView* a, RegionView* b) {
516 return a->region()->position() < b->region()->position();
521 Editor::sequence_regions ()
524 framepos_t r_end_prev;
532 RegionSelection rs = get_regions_from_selection_and_entered ();
533 rs.sort(RegionSelectionPositionSorter());
537 begin_reversible_command (_("sequence regions"));
538 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
539 boost::shared_ptr<Region> r ((*i)->region());
547 if(r->position_locked())
554 r->set_position(r_end_prev);
557 _session->add_command (new StatefulDiffCommand (r));
559 r_end=r->position() + r->length();
563 commit_reversible_command ();
571 Editor::move_to_start ()
573 _session->goto_start ();
577 Editor::move_to_end ()
580 _session->request_locate (_session->current_end_frame());
584 Editor::build_region_boundary_cache ()
587 vector<RegionPoint> interesting_points;
588 boost::shared_ptr<Region> r;
589 TrackViewList tracks;
592 region_boundary_cache.clear ();
598 switch (_snap_type) {
599 case SnapToRegionStart:
600 interesting_points.push_back (Start);
602 case SnapToRegionEnd:
603 interesting_points.push_back (End);
605 case SnapToRegionSync:
606 interesting_points.push_back (SyncPoint);
608 case SnapToRegionBoundary:
609 interesting_points.push_back (Start);
610 interesting_points.push_back (End);
613 fatal << string_compose (_("build_region_boundary_cache called with snap_type = %1"), _snap_type) << endmsg;
618 TimeAxisView *ontrack = 0;
621 if (!selection->tracks.empty()) {
622 tlist = selection->tracks.filter_to_unique_playlists ();
624 tlist = track_views.filter_to_unique_playlists ();
627 while (pos < _session->current_end_frame() && !at_end) {
630 framepos_t lpos = max_framepos;
632 for (vector<RegionPoint>::iterator p = interesting_points.begin(); p != interesting_points.end(); ++p) {
634 if ((r = find_next_region (pos, *p, 1, tlist, &ontrack)) == 0) {
635 if (*p == interesting_points.back()) {
638 /* move to next point type */
644 rpos = r->first_frame();
648 rpos = r->last_frame();
652 rpos = r->sync_position ();
660 RouteTimeAxisView *rtav;
662 if (ontrack != 0 && (rtav = dynamic_cast<RouteTimeAxisView*>(ontrack)) != 0 ) {
663 if (rtav->track() != 0) {
664 speed = rtav->track()->speed();
668 rpos = track_frame_to_session_frame (rpos, speed);
674 /* prevent duplicates, but we don't use set<> because we want to be able
678 vector<framepos_t>::iterator ri;
680 for (ri = region_boundary_cache.begin(); ri != region_boundary_cache.end(); ++ri) {
686 if (ri == region_boundary_cache.end()) {
687 region_boundary_cache.push_back (rpos);
694 /* finally sort to be sure that the order is correct */
696 sort (region_boundary_cache.begin(), region_boundary_cache.end());
699 boost::shared_ptr<Region>
700 Editor::find_next_region (framepos_t frame, RegionPoint point, int32_t dir, TrackViewList& tracks, TimeAxisView **ontrack)
702 TrackViewList::iterator i;
703 framepos_t closest = max_framepos;
704 boost::shared_ptr<Region> ret;
708 framepos_t track_frame;
709 RouteTimeAxisView *rtav;
711 for (i = tracks.begin(); i != tracks.end(); ++i) {
714 boost::shared_ptr<Region> r;
717 if ( (rtav = dynamic_cast<RouteTimeAxisView*>(*i)) != 0 ) {
718 if (rtav->track()!=0)
719 track_speed = rtav->track()->speed();
722 track_frame = session_frame_to_track_frame(frame, track_speed);
724 if ((r = (*i)->find_next_region (track_frame, point, dir)) == 0) {
730 rpos = r->first_frame ();
734 rpos = r->last_frame ();
738 rpos = r->sync_position ();
742 // rpos is a "track frame", converting it to "_session frame"
743 rpos = track_frame_to_session_frame(rpos, track_speed);
746 distance = rpos - frame;
748 distance = frame - rpos;
751 if (distance < closest) {
763 Editor::find_next_region_boundary (framepos_t pos, int32_t dir, const TrackViewList& tracks)
765 framecnt_t distance = max_framepos;
766 framepos_t current_nearest = -1;
768 for (TrackViewList::const_iterator i = tracks.begin(); i != tracks.end(); ++i) {
769 framepos_t contender;
772 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*i);
778 if ((contender = rtv->find_next_region_boundary (pos, dir)) < 0) {
782 d = ::llabs (pos - contender);
785 current_nearest = contender;
790 return current_nearest;
794 Editor::get_region_boundary (framepos_t pos, int32_t dir, bool with_selection, bool only_onscreen)
799 if (with_selection && Config->get_region_boundaries_from_selected_tracks()) {
801 if (!selection->tracks.empty()) {
803 target = find_next_region_boundary (pos, dir, selection->tracks);
807 if (only_onscreen || Config->get_region_boundaries_from_onscreen_tracks()) {
808 get_onscreen_tracks (tvl);
809 target = find_next_region_boundary (pos, dir, tvl);
811 target = find_next_region_boundary (pos, dir, track_views);
817 if (only_onscreen || Config->get_region_boundaries_from_onscreen_tracks()) {
818 get_onscreen_tracks (tvl);
819 target = find_next_region_boundary (pos, dir, tvl);
821 target = find_next_region_boundary (pos, dir, track_views);
829 Editor::cursor_to_region_boundary (bool with_selection, int32_t dir)
831 framepos_t pos = playhead_cursor->current_frame ();
838 // so we don't find the current region again..
839 if (dir > 0 || pos > 0) {
843 if ((target = get_region_boundary (pos, dir, with_selection, false)) < 0) {
847 _session->request_locate (target);
851 Editor::cursor_to_next_region_boundary (bool with_selection)
853 cursor_to_region_boundary (with_selection, 1);
857 Editor::cursor_to_previous_region_boundary (bool with_selection)
859 cursor_to_region_boundary (with_selection, -1);
863 Editor::cursor_to_region_point (EditorCursor* cursor, RegionPoint point, int32_t dir)
865 boost::shared_ptr<Region> r;
866 framepos_t pos = cursor->current_frame ();
872 TimeAxisView *ontrack = 0;
874 // so we don't find the current region again..
878 if (!selection->tracks.empty()) {
880 r = find_next_region (pos, point, dir, selection->tracks, &ontrack);
882 } else if (clicked_axisview) {
885 t.push_back (clicked_axisview);
887 r = find_next_region (pos, point, dir, t, &ontrack);
891 r = find_next_region (pos, point, dir, track_views, &ontrack);
900 pos = r->first_frame ();
904 pos = r->last_frame ();
908 pos = r->sync_position ();
913 RouteTimeAxisView *rtav;
915 if ( ontrack != 0 && (rtav = dynamic_cast<RouteTimeAxisView*>(ontrack)) != 0 ) {
916 if (rtav->track() != 0) {
917 speed = rtav->track()->speed();
921 pos = track_frame_to_session_frame(pos, speed);
923 if (cursor == playhead_cursor) {
924 _session->request_locate (pos);
926 cursor->set_position (pos);
931 Editor::cursor_to_next_region_point (EditorCursor* cursor, RegionPoint point)
933 cursor_to_region_point (cursor, point, 1);
937 Editor::cursor_to_previous_region_point (EditorCursor* cursor, RegionPoint point)
939 cursor_to_region_point (cursor, point, -1);
943 Editor::cursor_to_selection_start (EditorCursor *cursor)
947 switch (mouse_mode) {
949 if (!selection->regions.empty()) {
950 pos = selection->regions.start();
955 if (!selection->time.empty()) {
956 pos = selection->time.start ();
964 if (cursor == playhead_cursor) {
965 _session->request_locate (pos);
967 cursor->set_position (pos);
972 Editor::cursor_to_selection_end (EditorCursor *cursor)
976 switch (mouse_mode) {
978 if (!selection->regions.empty()) {
979 pos = selection->regions.end_frame();
984 if (!selection->time.empty()) {
985 pos = selection->time.end_frame ();
993 if (cursor == playhead_cursor) {
994 _session->request_locate (pos);
996 cursor->set_position (pos);
1001 Editor::selected_marker_to_region_boundary (bool with_selection, int32_t dir)
1011 if (selection->markers.empty()) {
1015 if (!mouse_frame (mouse, ignored)) {
1019 add_location_mark (mouse);
1022 if ((loc = find_location_from_marker (selection->markers.front(), ignored)) == 0) {
1026 framepos_t pos = loc->start();
1028 // so we don't find the current region again..
1029 if (dir > 0 || pos > 0) {
1033 if ((target = get_region_boundary (pos, dir, with_selection, false)) < 0) {
1037 loc->move_to (target);
1041 Editor::selected_marker_to_next_region_boundary (bool with_selection)
1043 selected_marker_to_region_boundary (with_selection, 1);
1047 Editor::selected_marker_to_previous_region_boundary (bool with_selection)
1049 selected_marker_to_region_boundary (with_selection, -1);
1053 Editor::selected_marker_to_region_point (RegionPoint point, int32_t dir)
1055 boost::shared_ptr<Region> r;
1060 if (!_session || selection->markers.empty()) {
1064 if ((loc = find_location_from_marker (selection->markers.front(), ignored)) == 0) {
1068 TimeAxisView *ontrack = 0;
1072 // so we don't find the current region again..
1076 if (!selection->tracks.empty()) {
1078 r = find_next_region (pos, point, dir, selection->tracks, &ontrack);
1082 r = find_next_region (pos, point, dir, track_views, &ontrack);
1091 pos = r->first_frame ();
1095 pos = r->last_frame ();
1099 pos = r->adjust_to_sync (r->first_frame());
1104 RouteTimeAxisView *rtav;
1106 if (ontrack != 0 && (rtav = dynamic_cast<RouteTimeAxisView*>(ontrack)) != 0) {
1107 if (rtav->track() != 0) {
1108 speed = rtav->track()->speed();
1112 pos = track_frame_to_session_frame(pos, speed);
1118 Editor::selected_marker_to_next_region_point (RegionPoint point)
1120 selected_marker_to_region_point (point, 1);
1124 Editor::selected_marker_to_previous_region_point (RegionPoint point)
1126 selected_marker_to_region_point (point, -1);
1130 Editor::selected_marker_to_selection_start ()
1136 if (!_session || selection->markers.empty()) {
1140 if ((loc = find_location_from_marker (selection->markers.front(), ignored)) == 0) {
1144 switch (mouse_mode) {
1146 if (!selection->regions.empty()) {
1147 pos = selection->regions.start();
1152 if (!selection->time.empty()) {
1153 pos = selection->time.start ();
1165 Editor::selected_marker_to_selection_end ()
1171 if (!_session || selection->markers.empty()) {
1175 if ((loc = find_location_from_marker (selection->markers.front(), ignored)) == 0) {
1179 switch (mouse_mode) {
1181 if (!selection->regions.empty()) {
1182 pos = selection->regions.end_frame();
1187 if (!selection->time.empty()) {
1188 pos = selection->time.end_frame ();
1200 Editor::scroll_playhead (bool forward)
1202 framepos_t pos = playhead_cursor->current_frame ();
1203 framecnt_t delta = (framecnt_t) floor (current_page_samples() / 0.8);
1206 if (pos == max_framepos) {
1210 if (pos < max_framepos - delta) {
1229 _session->request_locate (pos);
1233 Editor::cursor_align (bool playhead_to_edit)
1239 if (playhead_to_edit) {
1241 if (selection->markers.empty()) {
1245 _session->request_locate (selection->markers.front()->position(), _session->transport_rolling());
1248 /* move selected markers to playhead */
1250 for (MarkerSelection::iterator i = selection->markers.begin(); i != selection->markers.end(); ++i) {
1253 Location* loc = find_location_from_marker (*i, ignored);
1255 if (loc->is_mark()) {
1256 loc->set_start (playhead_cursor->current_frame ());
1258 loc->set (playhead_cursor->current_frame (),
1259 playhead_cursor->current_frame () + loc->length());
1266 Editor::scroll_backward (float pages)
1268 framepos_t const one_page = (framepos_t) rint (_visible_canvas_width * samples_per_pixel);
1269 framepos_t const cnt = (framepos_t) floor (pages * one_page);
1272 if (leftmost_frame < cnt) {
1275 frame = leftmost_frame - cnt;
1278 reset_x_origin (frame);
1282 Editor::scroll_forward (float pages)
1284 framepos_t const one_page = (framepos_t) rint (_visible_canvas_width * samples_per_pixel);
1285 framepos_t const cnt = (framepos_t) floor (pages * one_page);
1288 if (max_framepos - cnt < leftmost_frame) {
1289 frame = max_framepos - cnt;
1291 frame = leftmost_frame + cnt;
1294 reset_x_origin (frame);
1298 Editor::scroll_tracks_down ()
1300 double vert_value = vertical_adjustment.get_value() + vertical_adjustment.get_page_size();
1301 if (vert_value > vertical_adjustment.get_upper() - _visible_canvas_height) {
1302 vert_value = vertical_adjustment.get_upper() - _visible_canvas_height;
1305 vertical_adjustment.set_value (vert_value);
1309 Editor::scroll_tracks_up ()
1311 vertical_adjustment.set_value (vertical_adjustment.get_value() - vertical_adjustment.get_page_size());
1315 Editor::scroll_tracks_down_line ()
1317 double vert_value = vertical_adjustment.get_value() + 60;
1319 if (vert_value > vertical_adjustment.get_upper() - _visible_canvas_height) {
1320 vert_value = vertical_adjustment.get_upper() - _visible_canvas_height;
1323 vertical_adjustment.set_value (vert_value);
1327 Editor::scroll_tracks_up_line ()
1329 reset_y_origin (vertical_adjustment.get_value() - 60);
1333 Editor::scroll_down_one_track ()
1335 TrackViewList::reverse_iterator next = track_views.rend();
1336 std::pair<TimeAxisView*,double> res;
1337 const double bottom_of_trackviews = vertical_adjustment.get_value() + vertical_adjustment.get_page_size() - 1;
1339 for (TrackViewList::reverse_iterator t = track_views.rbegin(); t != track_views.rend(); ++t) {
1340 if ((*t)->hidden()) {
1344 /* If this is the bottom visible trackview, we want to display
1348 res = (*t)->covers_y_position (bottom_of_trackviews);
1354 ++next; // moves "next" towards the "front" since it is a reverse iterator
1357 /* move to the track below the first one that covers the */
1359 if (next != track_views.rend()) {
1360 ensure_time_axis_view_is_visible (**next);
1368 Editor::scroll_up_one_track ()
1370 double vertical_pos = vertical_adjustment.get_value ();
1372 TrackViewList::iterator prev = track_views.end();
1373 std::pair<TimeAxisView*,double> res;
1375 for (TrackViewList::iterator t = track_views.begin(); t != track_views.end(); ++t) {
1377 if ((*t)->hidden()) {
1381 /* find the trackview at the top of the trackview group */
1382 res = (*t)->covers_y_position (vertical_pos);
1385 cerr << res.first->name() << " covers the top\n";
1392 if (prev != track_views.end()) {
1393 ensure_time_axis_view_is_visible (**prev);
1403 Editor::tav_zoom_step (bool coarser)
1405 _routes->suspend_redisplay ();
1409 if (selection->tracks.empty()) {
1412 ts = &selection->tracks;
1415 for (TrackViewList::iterator i = ts->begin(); i != ts->end(); ++i) {
1416 TimeAxisView *tv = (static_cast<TimeAxisView*>(*i));
1417 tv->step_height (coarser);
1420 _routes->resume_redisplay ();
1424 Editor::tav_zoom_smooth (bool coarser, bool force_all)
1426 _routes->suspend_redisplay ();
1430 if (selection->tracks.empty() || force_all) {
1433 ts = &selection->tracks;
1436 for (TrackViewList::iterator i = ts->begin(); i != ts->end(); ++i) {
1437 TimeAxisView *tv = (static_cast<TimeAxisView*>(*i));
1438 uint32_t h = tv->current_height ();
1443 if (h >= TimeAxisView::preset_height (HeightSmall)) {
1448 tv->set_height (h + 5);
1452 _routes->resume_redisplay ();
1456 Editor::clamp_samples_per_pixel (framecnt_t& fpp) const
1458 bool clamped = false;
1468 sr = _session->frame_rate ();
1473 const framecnt_t three_days = 3 * 24 * 60 * 60 * sr;
1474 const framecnt_t lots_of_pixels = 4000;
1476 /* if the zoom level is greater than what you'd get trying to display 3
1477 * days of audio on a really big screen, scale it down.
1480 if (fpp * lots_of_pixels > three_days) {
1481 fpp = three_days / _track_canvas->width();
1489 Editor::temporal_zoom_step (bool coarser)
1491 ENSURE_GUI_THREAD (*this, &Editor::temporal_zoom_step, coarser)
1493 framecnt_t nspp = samples_per_pixel;
1501 temporal_zoom (nspp);
1505 Editor::temporal_zoom (framecnt_t fpp)
1511 framepos_t current_page = current_page_samples();
1512 framepos_t current_leftmost = leftmost_frame;
1513 framepos_t current_rightmost;
1514 framepos_t current_center;
1515 framepos_t new_page_size;
1516 framepos_t half_page_size;
1517 framepos_t leftmost_after_zoom = 0;
1519 bool in_track_canvas;
1523 clamp_samples_per_pixel (fpp);
1524 if (fpp == samples_per_pixel) {
1528 // Imposing an arbitrary limit to zoom out as too much zoom out produces
1529 // segfaults for lack of memory. If somebody decides this is not high enough I
1530 // believe it can be raisen to higher values but some limit must be in place.
1532 // This constant represents 1 day @ 48kHz on a 1600 pixel wide display
1533 // all of which is used for the editor track displays. The whole day
1534 // would be 4147200000 samples, so 2592000 samples per pixel.
1536 nfpp = min (fpp, (framecnt_t) 2592000);
1537 nfpp = max ((framecnt_t) 1, fpp);
1539 new_page_size = (framepos_t) floor (_visible_canvas_width * nfpp);
1540 half_page_size = new_page_size / 2;
1542 switch (zoom_focus) {
1544 leftmost_after_zoom = current_leftmost;
1547 case ZoomFocusRight:
1548 current_rightmost = leftmost_frame + current_page;
1549 if (current_rightmost < new_page_size) {
1550 leftmost_after_zoom = 0;
1552 leftmost_after_zoom = current_rightmost - new_page_size;
1556 case ZoomFocusCenter:
1557 current_center = current_leftmost + (current_page/2);
1558 if (current_center < half_page_size) {
1559 leftmost_after_zoom = 0;
1561 leftmost_after_zoom = current_center - half_page_size;
1565 case ZoomFocusPlayhead:
1566 /* centre playhead */
1567 l = playhead_cursor->current_frame () - (new_page_size * 0.5);
1570 leftmost_after_zoom = 0;
1571 } else if (l > max_framepos) {
1572 leftmost_after_zoom = max_framepos - new_page_size;
1574 leftmost_after_zoom = (framepos_t) l;
1578 case ZoomFocusMouse:
1579 /* try to keep the mouse over the same point in the display */
1581 if (!mouse_frame (where, in_track_canvas)) {
1582 /* use playhead instead */
1583 where = playhead_cursor->current_frame ();
1585 if (where < half_page_size) {
1586 leftmost_after_zoom = 0;
1588 leftmost_after_zoom = where - half_page_size;
1593 l = - ((new_page_size * ((where - current_leftmost)/(double)current_page)) - where);
1596 leftmost_after_zoom = 0;
1597 } else if (l > max_framepos) {
1598 leftmost_after_zoom = max_framepos - new_page_size;
1600 leftmost_after_zoom = (framepos_t) l;
1607 /* try to keep the edit point in the same place */
1608 where = get_preferred_edit_position ();
1612 double l = - ((new_page_size * ((where - current_leftmost)/(double)current_page)) - where);
1615 leftmost_after_zoom = 0;
1616 } else if (l > max_framepos) {
1617 leftmost_after_zoom = max_framepos - new_page_size;
1619 leftmost_after_zoom = (framepos_t) l;
1623 /* edit point not defined */
1630 // leftmost_after_zoom = min (leftmost_after_zoom, _session->current_end_frame());
1632 reposition_and_zoom (leftmost_after_zoom, nfpp);
1636 Editor::temporal_zoom_region (bool both_axes)
1638 framepos_t start = max_framepos;
1640 set<TimeAxisView*> tracks;
1642 RegionSelection rs = get_regions_from_selection_and_entered ();
1648 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
1650 if ((*i)->region()->position() < start) {
1651 start = (*i)->region()->position();
1654 if ((*i)->region()->last_frame() + 1 > end) {
1655 end = (*i)->region()->last_frame() + 1;
1658 tracks.insert (&((*i)->get_time_axis_view()));
1661 /* now comes an "interesting" hack ... make sure we leave a little space
1662 at each end of the editor so that the zoom doesn't fit the region
1663 precisely to the screen.
1666 GdkScreen* screen = gdk_screen_get_default ();
1667 gint pixwidth = gdk_screen_get_width (screen);
1668 gint mmwidth = gdk_screen_get_width_mm (screen);
1669 double pix_per_mm = (double) pixwidth/ (double) mmwidth;
1670 double one_centimeter_in_pixels = pix_per_mm * 10.0;
1672 if ((start == 0 && end == 0) || end < start) {
1676 framepos_t range = end - start;
1677 double new_fpp = (double) range / (double) _visible_canvas_width;
1678 framepos_t extra_samples = (framepos_t) floor (one_centimeter_in_pixels * new_fpp);
1680 if (start > extra_samples) {
1681 start -= extra_samples;
1686 if (max_framepos - extra_samples > end) {
1687 end += extra_samples;
1692 /* if we're zooming on both axes we need to save track heights etc.
1695 undo_visual_stack.push_back (current_visual_state (both_axes));
1697 PBD::Unwinder<bool> nsv (no_save_visual, true);
1699 temporal_zoom_by_frame (start, end);
1702 uint32_t per_track_height = (uint32_t) floor ((_visible_canvas_height - 10.0) / tracks.size());
1704 /* set visible track heights appropriately */
1706 for (set<TimeAxisView*>::iterator t = tracks.begin(); t != tracks.end(); ++t) {
1707 (*t)->set_height (per_track_height);
1710 /* hide irrelevant tracks */
1712 _routes->suspend_redisplay ();
1714 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1715 if (find (tracks.begin(), tracks.end(), (*i)) == tracks.end()) {
1716 hide_track_in_display (*i);
1720 _routes->resume_redisplay ();
1722 vertical_adjustment.set_value (0.0);
1725 redo_visual_stack.push_back (current_visual_state (both_axes));
1729 Editor::zoom_to_region (bool both_axes)
1731 temporal_zoom_region (both_axes);
1735 Editor::temporal_zoom_selection ()
1737 if (!selection) return;
1739 if (selection->time.empty()) {
1743 framepos_t start = selection->time[clicked_selection].start;
1744 framepos_t end = selection->time[clicked_selection].end;
1746 temporal_zoom_by_frame (start, end);
1750 Editor::temporal_zoom_session ()
1752 ENSURE_GUI_THREAD (*this, &Editor::temporal_zoom_session)
1755 framecnt_t const l = _session->current_end_frame() - _session->current_start_frame();
1756 double s = _session->current_start_frame() - l * 0.01;
1760 framecnt_t const e = _session->current_end_frame() + l * 0.01;
1761 temporal_zoom_by_frame (framecnt_t (s), e);
1766 Editor::temporal_zoom_by_frame (framepos_t start, framepos_t end)
1768 if (!_session) return;
1770 if ((start == 0 && end == 0) || end < start) {
1774 framepos_t range = end - start;
1776 double const new_fpp = (double) range / (double) _visible_canvas_width;
1778 framepos_t new_page = (framepos_t) floor (_visible_canvas_width * new_fpp);
1779 framepos_t middle = (framepos_t) floor ((double) start + ((double) range / 2.0f));
1780 framepos_t new_leftmost = (framepos_t) floor ((double) middle - ((double) new_page / 2.0f));
1782 if (new_leftmost > middle) {
1786 if (new_leftmost < 0) {
1790 reposition_and_zoom (new_leftmost, new_fpp);
1794 Editor::temporal_zoom_to_frame (bool coarser, framepos_t frame)
1800 framecnt_t range_before = frame - leftmost_frame;
1804 if (samples_per_pixel <= 1) {
1807 new_spp = samples_per_pixel + (samples_per_pixel/2);
1809 range_before += range_before/2;
1811 if (samples_per_pixel >= 1) {
1812 new_spp = samples_per_pixel - (samples_per_pixel/2);
1814 /* could bail out here since we cannot zoom any finer,
1815 but leave that to the clamp_samples_per_pixel() and
1818 new_spp = samples_per_pixel;
1821 range_before -= range_before/2;
1824 clamp_samples_per_pixel (new_spp);
1826 if (new_spp == samples_per_pixel) {
1830 /* zoom focus is automatically taken as @param frame when this
1834 framepos_t new_leftmost = frame - (framepos_t)range_before;
1836 if (new_leftmost > frame) {
1840 if (new_leftmost < 0) {
1844 reposition_and_zoom (new_leftmost, new_spp);
1849 Editor::choose_new_marker_name(string &name) {
1851 if (!Config->get_name_new_markers()) {
1852 /* don't prompt user for a new name */
1856 ArdourPrompter dialog (true);
1858 dialog.set_prompt (_("New Name:"));
1860 dialog.set_title (_("New Location Marker"));
1862 dialog.set_name ("MarkNameWindow");
1863 dialog.set_size_request (250, -1);
1864 dialog.set_position (Gtk::WIN_POS_MOUSE);
1866 dialog.add_button (Stock::OK, RESPONSE_ACCEPT);
1867 dialog.set_initial_text (name);
1871 switch (dialog.run ()) {
1872 case RESPONSE_ACCEPT:
1878 dialog.get_result(name);
1885 Editor::add_location_from_selection ()
1889 if (selection->time.empty()) {
1893 if (_session == 0 || clicked_axisview == 0) {
1897 framepos_t start = selection->time[clicked_selection].start;
1898 framepos_t end = selection->time[clicked_selection].end;
1900 _session->locations()->next_available_name(rangename,"selection");
1901 Location *location = new Location (*_session, start, end, rangename, Location::IsRangeMarker);
1903 _session->begin_reversible_command (_("add marker"));
1904 XMLNode &before = _session->locations()->get_state();
1905 _session->locations()->add (location, true);
1906 XMLNode &after = _session->locations()->get_state();
1907 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
1908 _session->commit_reversible_command ();
1912 Editor::add_location_mark (framepos_t where)
1916 select_new_marker = true;
1918 _session->locations()->next_available_name(markername,"mark");
1919 if (!choose_new_marker_name(markername)) {
1922 Location *location = new Location (*_session, where, where, markername, Location::IsMark);
1923 _session->begin_reversible_command (_("add marker"));
1924 XMLNode &before = _session->locations()->get_state();
1925 _session->locations()->add (location, true);
1926 XMLNode &after = _session->locations()->get_state();
1927 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
1928 _session->commit_reversible_command ();
1932 Editor::add_location_from_playhead_cursor ()
1934 add_location_mark (_session->audible_frame());
1937 /** Add a range marker around each selected region */
1939 Editor::add_locations_from_region ()
1941 RegionSelection rs = get_regions_from_selection_and_entered ();
1947 _session->begin_reversible_command (selection->regions.size () > 1 ? _("add markers") : _("add marker"));
1948 XMLNode &before = _session->locations()->get_state();
1950 for (RegionSelection::iterator i = rs.begin (); i != rs.end (); ++i) {
1952 boost::shared_ptr<Region> region = (*i)->region ();
1954 Location *location = new Location (*_session, region->position(), region->last_frame(), region->name(), Location::IsRangeMarker);
1956 _session->locations()->add (location, true);
1959 XMLNode &after = _session->locations()->get_state();
1960 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
1961 _session->commit_reversible_command ();
1964 /** Add a single range marker around all selected regions */
1966 Editor::add_location_from_region ()
1968 RegionSelection rs = get_regions_from_selection_and_entered ();
1974 _session->begin_reversible_command (_("add marker"));
1975 XMLNode &before = _session->locations()->get_state();
1979 if (rs.size() > 1) {
1980 _session->locations()->next_available_name(markername, "regions");
1982 RegionView* rv = *(rs.begin());
1983 boost::shared_ptr<Region> region = rv->region();
1984 markername = region->name();
1987 if (!choose_new_marker_name(markername)) {
1991 // single range spanning all selected
1992 Location *location = new Location (*_session, selection->regions.start(), selection->regions.end_frame(), markername, Location::IsRangeMarker);
1993 _session->locations()->add (location, true);
1995 XMLNode &after = _session->locations()->get_state();
1996 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
1997 _session->commit_reversible_command ();
2003 Editor::jump_forward_to_mark ()
2009 framepos_t pos = _session->locations()->first_mark_after (playhead_cursor->current_frame());
2015 _session->request_locate (pos, _session->transport_rolling());
2019 Editor::jump_backward_to_mark ()
2025 framepos_t pos = _session->locations()->first_mark_before (playhead_cursor->current_frame());
2031 _session->request_locate (pos, _session->transport_rolling());
2037 framepos_t const pos = _session->audible_frame ();
2040 _session->locations()->next_available_name (markername, "mark");
2042 if (!choose_new_marker_name (markername)) {
2046 _session->locations()->add (new Location (*_session, pos, 0, markername, Location::IsMark), true);
2050 Editor::clear_markers ()
2053 _session->begin_reversible_command (_("clear markers"));
2054 XMLNode &before = _session->locations()->get_state();
2055 _session->locations()->clear_markers ();
2056 XMLNode &after = _session->locations()->get_state();
2057 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2058 _session->commit_reversible_command ();
2063 Editor::clear_ranges ()
2066 _session->begin_reversible_command (_("clear ranges"));
2067 XMLNode &before = _session->locations()->get_state();
2069 Location * looploc = _session->locations()->auto_loop_location();
2070 Location * punchloc = _session->locations()->auto_punch_location();
2071 Location * sessionloc = _session->locations()->session_range_location();
2073 _session->locations()->clear_ranges ();
2075 if (looploc) _session->locations()->add (looploc);
2076 if (punchloc) _session->locations()->add (punchloc);
2077 if (sessionloc) _session->locations()->add (sessionloc);
2079 XMLNode &after = _session->locations()->get_state();
2080 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2081 _session->commit_reversible_command ();
2086 Editor::clear_locations ()
2088 _session->begin_reversible_command (_("clear locations"));
2089 XMLNode &before = _session->locations()->get_state();
2090 _session->locations()->clear ();
2091 XMLNode &after = _session->locations()->get_state();
2092 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2093 _session->commit_reversible_command ();
2094 _session->locations()->clear ();
2098 Editor::unhide_markers ()
2100 for (LocationMarkerMap::iterator i = location_markers.begin(); i != location_markers.end(); ++i) {
2101 Location *l = (*i).first;
2102 if (l->is_hidden() && l->is_mark()) {
2103 l->set_hidden(false, this);
2109 Editor::unhide_ranges ()
2111 for (LocationMarkerMap::iterator i = location_markers.begin(); i != location_markers.end(); ++i) {
2112 Location *l = (*i).first;
2113 if (l->is_hidden() && l->is_range_marker()) {
2114 l->set_hidden(false, this);
2120 Editor::insert_region_list_selection (float times)
2122 RouteTimeAxisView *tv = 0;
2123 boost::shared_ptr<Playlist> playlist;
2125 if (clicked_routeview != 0) {
2126 tv = clicked_routeview;
2127 } else if (!selection->tracks.empty()) {
2128 if ((tv = dynamic_cast<RouteTimeAxisView*>(selection->tracks.front())) == 0) {
2131 } else if (entered_track != 0) {
2132 if ((tv = dynamic_cast<RouteTimeAxisView*>(entered_track)) == 0) {
2139 if ((playlist = tv->playlist()) == 0) {
2143 boost::shared_ptr<Region> region = _regions->get_single_selection ();
2148 begin_reversible_command (_("insert region"));
2149 playlist->clear_changes ();
2150 playlist->add_region ((RegionFactory::create (region, true)), get_preferred_edit_position(), times);
2151 _session->add_command(new StatefulDiffCommand (playlist));
2152 commit_reversible_command ();
2155 /* BUILT-IN EFFECTS */
2158 Editor::reverse_selection ()
2163 /* GAIN ENVELOPE EDITING */
2166 Editor::edit_envelope ()
2173 Editor::transition_to_rolling (bool fwd)
2179 if (_session->config.get_external_sync()) {
2180 switch (Config->get_sync_source()) {
2184 /* transport controlled by the master */
2189 if (_session->is_auditioning()) {
2190 _session->cancel_audition ();
2194 _session->request_transport_speed (fwd ? 1.0f : -1.0f);
2198 Editor::play_from_start ()
2200 _session->request_locate (_session->current_start_frame(), true);
2204 Editor::play_from_edit_point ()
2206 _session->request_locate (get_preferred_edit_position(), true);
2210 Editor::play_from_edit_point_and_return ()
2212 framepos_t start_frame;
2213 framepos_t return_frame;
2215 start_frame = get_preferred_edit_position (true);
2217 if (_session->transport_rolling()) {
2218 _session->request_locate (start_frame, false);
2222 /* don't reset the return frame if its already set */
2224 if ((return_frame = _session->requested_return_frame()) < 0) {
2225 return_frame = _session->audible_frame();
2228 if (start_frame >= 0) {
2229 _session->request_roll_at_and_return (start_frame, return_frame);
2234 Editor::play_selection ()
2236 if (selection->time.empty()) {
2240 _session->request_play_range (&selection->time, true);
2244 Editor::get_preroll ()
2246 return 1.0 /*Config->get_edit_preroll_seconds()*/ * _session->frame_rate();
2251 Editor::maybe_locate_with_edit_preroll ( framepos_t location )
2253 if ( _session->transport_rolling() || !Config->get_always_play_range() )
2256 location -= get_preroll();
2258 //don't try to locate before the beginning of time
2262 //if follow_playhead is on, keep the playhead on the screen
2263 if ( _follow_playhead )
2264 if ( location < leftmost_frame )
2265 location = leftmost_frame;
2267 _session->request_locate( location );
2271 Editor::play_with_preroll ()
2273 if (selection->time.empty()) {
2276 framepos_t preroll = get_preroll();
2278 framepos_t start = 0;
2279 if (selection->time[clicked_selection].start > preroll)
2280 start = selection->time[clicked_selection].start - preroll;
2282 framepos_t end = selection->time[clicked_selection].end + preroll;
2284 AudioRange ar (start, end, 0);
2285 list<AudioRange> lar;
2288 _session->request_play_range (&lar, true);
2293 Editor::play_location (Location& location)
2295 if (location.start() <= location.end()) {
2299 _session->request_bounded_roll (location.start(), location.end());
2303 Editor::loop_location (Location& location)
2305 if (location.start() <= location.end()) {
2311 if ((tll = transport_loop_location()) != 0) {
2312 tll->set (location.start(), location.end());
2314 // enable looping, reposition and start rolling
2315 _session->request_play_loop (true);
2316 _session->request_locate (tll->start(), true);
2321 Editor::do_layer_operation (LayerOperation op)
2323 if (selection->regions.empty ()) {
2327 bool const multiple = selection->regions.size() > 1;
2331 begin_reversible_command (_("raise regions"));
2333 begin_reversible_command (_("raise region"));
2339 begin_reversible_command (_("raise regions to top"));
2341 begin_reversible_command (_("raise region to top"));
2347 begin_reversible_command (_("lower regions"));
2349 begin_reversible_command (_("lower region"));
2355 begin_reversible_command (_("lower regions to bottom"));
2357 begin_reversible_command (_("lower region"));
2362 set<boost::shared_ptr<Playlist> > playlists = selection->regions.playlists ();
2363 for (set<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
2364 (*i)->clear_owned_changes ();
2367 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
2368 boost::shared_ptr<Region> r = (*i)->region ();
2380 r->lower_to_bottom ();
2384 for (set<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
2385 vector<Command*> cmds;
2387 _session->add_commands (cmds);
2390 commit_reversible_command ();
2394 Editor::raise_region ()
2396 do_layer_operation (Raise);
2400 Editor::raise_region_to_top ()
2402 do_layer_operation (RaiseToTop);
2406 Editor::lower_region ()
2408 do_layer_operation (Lower);
2412 Editor::lower_region_to_bottom ()
2414 do_layer_operation (LowerToBottom);
2417 /** Show the region editor for the selected regions */
2419 Editor::show_region_properties ()
2421 selection->foreach_regionview (&RegionView::show_region_editor);
2424 /** Show the midi list editor for the selected MIDI regions */
2426 Editor::show_midi_list_editor ()
2428 selection->foreach_midi_regionview (&MidiRegionView::show_list_editor);
2432 Editor::rename_region ()
2434 RegionSelection rs = get_regions_from_selection_and_entered ();
2440 ArdourDialog d (*this, _("Rename Region"), true, false);
2442 Label label (_("New name:"));
2445 hbox.set_spacing (6);
2446 hbox.pack_start (label, false, false);
2447 hbox.pack_start (entry, true, true);
2449 d.get_vbox()->set_border_width (12);
2450 d.get_vbox()->pack_start (hbox, false, false);
2452 d.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
2453 d.add_button(Gtk::Stock::OK, Gtk::RESPONSE_OK);
2455 d.set_size_request (300, -1);
2457 entry.set_text (rs.front()->region()->name());
2458 entry.select_region (0, -1);
2460 entry.signal_activate().connect (sigc::bind (sigc::mem_fun (d, &Dialog::response), RESPONSE_OK));
2466 int const ret = d.run();
2470 if (ret != RESPONSE_OK) {
2474 std::string str = entry.get_text();
2475 strip_whitespace_edges (str);
2477 rs.front()->region()->set_name (str);
2478 _regions->redisplay ();
2483 Editor::audition_playlist_region_via_route (boost::shared_ptr<Region> region, Route& route)
2485 if (_session->is_auditioning()) {
2486 _session->cancel_audition ();
2489 // note: some potential for creativity here, because region doesn't
2490 // have to belong to the playlist that Route is handling
2492 // bool was_soloed = route.soloed();
2494 route.set_solo (true, this);
2496 _session->request_bounded_roll (region->position(), region->position() + region->length());
2498 /* XXX how to unset the solo state ? */
2501 /** Start an audition of the first selected region */
2503 Editor::play_edit_range ()
2505 framepos_t start, end;
2507 if (get_edit_op_range (start, end)) {
2508 _session->request_bounded_roll (start, end);
2513 Editor::play_selected_region ()
2515 framepos_t start = max_framepos;
2518 RegionSelection rs = get_regions_from_selection_and_entered ();
2524 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
2525 if ((*i)->region()->position() < start) {
2526 start = (*i)->region()->position();
2528 if ((*i)->region()->last_frame() + 1 > end) {
2529 end = (*i)->region()->last_frame() + 1;
2533 _session->request_bounded_roll (start, end);
2537 Editor::audition_playlist_region_standalone (boost::shared_ptr<Region> region)
2539 _session->audition_region (region);
2543 Editor::region_from_selection ()
2545 if (clicked_axisview == 0) {
2549 if (selection->time.empty()) {
2553 framepos_t start = selection->time[clicked_selection].start;
2554 framepos_t end = selection->time[clicked_selection].end;
2556 TrackViewList tracks = get_tracks_for_range_action ();
2558 framepos_t selection_cnt = end - start + 1;
2560 for (TrackSelection::iterator i = tracks.begin(); i != tracks.end(); ++i) {
2561 boost::shared_ptr<Region> current;
2562 boost::shared_ptr<Playlist> pl;
2563 framepos_t internal_start;
2566 if ((pl = (*i)->playlist()) == 0) {
2570 if ((current = pl->top_region_at (start)) == 0) {
2574 internal_start = start - current->position();
2575 RegionFactory::region_name (new_name, current->name(), true);
2579 plist.add (ARDOUR::Properties::start, current->start() + internal_start);
2580 plist.add (ARDOUR::Properties::length, selection_cnt);
2581 plist.add (ARDOUR::Properties::name, new_name);
2582 plist.add (ARDOUR::Properties::layer, 0);
2584 boost::shared_ptr<Region> region (RegionFactory::create (current, plist));
2589 Editor::create_region_from_selection (vector<boost::shared_ptr<Region> >& new_regions)
2591 if (selection->time.empty() || selection->tracks.empty()) {
2595 framepos_t start = selection->time[clicked_selection].start;
2596 framepos_t end = selection->time[clicked_selection].end;
2598 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
2599 sort_track_selection (ts);
2601 for (TrackSelection::iterator i = ts.begin(); i != ts.end(); ++i) {
2602 boost::shared_ptr<Region> current;
2603 boost::shared_ptr<Playlist> playlist;
2604 framepos_t internal_start;
2607 if ((playlist = (*i)->playlist()) == 0) {
2611 if ((current = playlist->top_region_at(start)) == 0) {
2615 internal_start = start - current->position();
2616 RegionFactory::region_name (new_name, current->name(), true);
2620 plist.add (ARDOUR::Properties::start, current->start() + internal_start);
2621 plist.add (ARDOUR::Properties::length, end - start + 1);
2622 plist.add (ARDOUR::Properties::name, new_name);
2624 new_regions.push_back (RegionFactory::create (current, plist));
2629 Editor::split_multichannel_region ()
2631 RegionSelection rs = get_regions_from_selection_and_entered ();
2637 vector< boost::shared_ptr<Region> > v;
2639 for (list<RegionView*>::iterator x = rs.begin(); x != rs.end(); ++x) {
2640 (*x)->region()->separate_by_channel (*_session, v);
2645 Editor::new_region_from_selection ()
2647 region_from_selection ();
2648 cancel_selection ();
2652 add_if_covered (RegionView* rv, const AudioRange* ar, RegionSelection* rs)
2654 switch (rv->region()->coverage (ar->start, ar->end - 1)) {
2655 case Evoral::OverlapNone:
2663 * - selected tracks, or if there are none...
2664 * - tracks containing selected regions, or if there are none...
2669 Editor::get_tracks_for_range_action () const
2673 if (selection->tracks.empty()) {
2675 /* use tracks with selected regions */
2677 RegionSelection rs = selection->regions;
2679 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
2680 TimeAxisView* tv = &(*i)->get_time_axis_view();
2682 if (!t.contains (tv)) {
2688 /* no regions and no tracks: use all tracks */
2694 t = selection->tracks;
2697 return t.filter_to_unique_playlists();
2701 Editor::separate_regions_between (const TimeSelection& ts)
2703 bool in_command = false;
2704 boost::shared_ptr<Playlist> playlist;
2705 RegionSelection new_selection;
2707 TrackViewList tmptracks = get_tracks_for_range_action ();
2708 sort_track_selection (tmptracks);
2710 for (TrackSelection::iterator i = tmptracks.begin(); i != tmptracks.end(); ++i) {
2712 RouteTimeAxisView* rtv;
2714 if ((rtv = dynamic_cast<RouteTimeAxisView*> ((*i))) != 0) {
2716 if (rtv->is_track()) {
2718 /* no edits to destructive tracks */
2720 if (rtv->track()->destructive()) {
2724 if ((playlist = rtv->playlist()) != 0) {
2726 playlist->clear_changes ();
2728 /* XXX need to consider musical time selections here at some point */
2730 double speed = rtv->track()->speed();
2733 for (list<AudioRange>::const_iterator t = ts.begin(); t != ts.end(); ++t) {
2735 sigc::connection c = rtv->view()->RegionViewAdded.connect (
2736 sigc::mem_fun(*this, &Editor::collect_new_region_view));
2738 latest_regionviews.clear ();
2740 playlist->partition ((framepos_t)((*t).start * speed),
2741 (framepos_t)((*t).end * speed), false);
2745 if (!latest_regionviews.empty()) {
2747 rtv->view()->foreach_regionview (sigc::bind (
2748 sigc::ptr_fun (add_if_covered),
2749 &(*t), &new_selection));
2752 begin_reversible_command (_("separate"));
2756 /* pick up changes to existing regions */
2758 vector<Command*> cmds;
2759 playlist->rdiff (cmds);
2760 _session->add_commands (cmds);
2762 /* pick up changes to the playlist itself (adds/removes)
2765 _session->add_command(new StatefulDiffCommand (playlist));
2774 selection->set (new_selection);
2775 set_mouse_mode (MouseObject);
2777 commit_reversible_command ();
2781 struct PlaylistState {
2782 boost::shared_ptr<Playlist> playlist;
2786 /** Take tracks from get_tracks_for_range_action and cut any regions
2787 * on those tracks so that the tracks are empty over the time
2791 Editor::separate_region_from_selection ()
2793 /* preferentially use *all* ranges in the time selection if we're in range mode
2794 to allow discontiguous operation, since get_edit_op_range() currently
2795 returns a single range.
2798 if (!selection->time.empty()) {
2800 separate_regions_between (selection->time);
2807 if (get_edit_op_range (start, end)) {
2809 AudioRange ar (start, end, 1);
2813 separate_regions_between (ts);
2819 Editor::separate_region_from_punch ()
2821 Location* loc = _session->locations()->auto_punch_location();
2823 separate_regions_using_location (*loc);
2828 Editor::separate_region_from_loop ()
2830 Location* loc = _session->locations()->auto_loop_location();
2832 separate_regions_using_location (*loc);
2837 Editor::separate_regions_using_location (Location& loc)
2839 if (loc.is_mark()) {
2843 AudioRange ar (loc.start(), loc.end(), 1);
2848 separate_regions_between (ts);
2851 /** Separate regions under the selected region */
2853 Editor::separate_under_selected_regions ()
2855 vector<PlaylistState> playlists;
2859 rs = get_regions_from_selection_and_entered();
2861 if (!_session || rs.empty()) {
2865 begin_reversible_command (_("separate region under"));
2867 list<boost::shared_ptr<Region> > regions_to_remove;
2869 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
2870 // we can't just remove the region(s) in this loop because
2871 // this removes them from the RegionSelection, and they thus
2872 // disappear from underneath the iterator, and the ++i above
2873 // SEGVs in a puzzling fashion.
2875 // so, first iterate over the regions to be removed from rs and
2876 // add them to the regions_to_remove list, and then
2877 // iterate over the list to actually remove them.
2879 regions_to_remove.push_back ((*i)->region());
2882 for (list<boost::shared_ptr<Region> >::iterator rl = regions_to_remove.begin(); rl != regions_to_remove.end(); ++rl) {
2884 boost::shared_ptr<Playlist> playlist = (*rl)->playlist();
2887 // is this check necessary?
2891 vector<PlaylistState>::iterator i;
2893 //only take state if this is a new playlist.
2894 for (i = playlists.begin(); i != playlists.end(); ++i) {
2895 if ((*i).playlist == playlist) {
2900 if (i == playlists.end()) {
2902 PlaylistState before;
2903 before.playlist = playlist;
2904 before.before = &playlist->get_state();
2906 playlist->freeze ();
2907 playlists.push_back(before);
2910 //Partition on the region bounds
2911 playlist->partition ((*rl)->first_frame() - 1, (*rl)->last_frame() + 1, true);
2913 //Re-add region that was just removed due to the partition operation
2914 playlist->add_region( (*rl), (*rl)->first_frame() );
2917 vector<PlaylistState>::iterator pl;
2919 for (pl = playlists.begin(); pl != playlists.end(); ++pl) {
2920 (*pl).playlist->thaw ();
2921 _session->add_command(new MementoCommand<Playlist>(*(*pl).playlist, (*pl).before, &(*pl).playlist->get_state()));
2924 commit_reversible_command ();
2928 Editor::crop_region_to_selection ()
2930 if (!selection->time.empty()) {
2932 crop_region_to (selection->time.start(), selection->time.end_frame());
2939 if (get_edit_op_range (start, end)) {
2940 crop_region_to (start, end);
2947 Editor::crop_region_to (framepos_t start, framepos_t end)
2949 vector<boost::shared_ptr<Playlist> > playlists;
2950 boost::shared_ptr<Playlist> playlist;
2953 if (selection->tracks.empty()) {
2954 ts = track_views.filter_to_unique_playlists();
2956 ts = selection->tracks.filter_to_unique_playlists ();
2959 sort_track_selection (ts);
2961 for (TrackSelection::iterator i = ts.begin(); i != ts.end(); ++i) {
2963 RouteTimeAxisView* rtv;
2965 if ((rtv = dynamic_cast<RouteTimeAxisView*> ((*i))) != 0) {
2967 boost::shared_ptr<Track> t = rtv->track();
2969 if (t != 0 && ! t->destructive()) {
2971 if ((playlist = rtv->playlist()) != 0) {
2972 playlists.push_back (playlist);
2978 if (playlists.empty()) {
2982 framepos_t the_start;
2986 begin_reversible_command (_("trim to selection"));
2988 for (vector<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
2990 boost::shared_ptr<Region> region;
2994 if ((region = (*i)->top_region_at(the_start)) == 0) {
2998 /* now adjust lengths to that we do the right thing
2999 if the selection extends beyond the region
3002 the_start = max (the_start, (framepos_t) region->position());
3003 if (max_framepos - the_start < region->length()) {
3004 the_end = the_start + region->length() - 1;
3006 the_end = max_framepos;
3008 the_end = min (end, the_end);
3009 cnt = the_end - the_start + 1;
3011 region->clear_changes ();
3012 region->trim_to (the_start, cnt);
3013 _session->add_command (new StatefulDiffCommand (region));
3016 commit_reversible_command ();
3020 Editor::region_fill_track ()
3022 RegionSelection rs = get_regions_from_selection_and_entered ();
3024 if (!_session || rs.empty()) {
3028 framepos_t const end = _session->current_end_frame ();
3030 begin_reversible_command (Operations::region_fill);
3032 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3034 boost::shared_ptr<Region> region ((*i)->region());
3036 boost::shared_ptr<Playlist> pl = region->playlist();
3038 if (end <= region->last_frame()) {
3042 double times = (double) (end - region->last_frame()) / (double) region->length();
3048 pl->clear_changes ();
3049 pl->add_region (RegionFactory::create (region, true), region->last_frame(), times);
3050 _session->add_command (new StatefulDiffCommand (pl));
3053 commit_reversible_command ();
3057 Editor::region_fill_selection ()
3059 if (clicked_routeview == 0 || !clicked_routeview->is_audio_track()) {
3063 if (selection->time.empty()) {
3067 boost::shared_ptr<Region> region = _regions->get_single_selection ();
3072 framepos_t start = selection->time[clicked_selection].start;
3073 framepos_t end = selection->time[clicked_selection].end;
3075 boost::shared_ptr<Playlist> playlist;
3077 if (selection->tracks.empty()) {
3081 framepos_t selection_length = end - start;
3082 float times = (float)selection_length / region->length();
3084 begin_reversible_command (Operations::fill_selection);
3086 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
3088 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
3090 if ((playlist = (*i)->playlist()) == 0) {
3094 playlist->clear_changes ();
3095 playlist->add_region (RegionFactory::create (region, true), start, times);
3096 _session->add_command (new StatefulDiffCommand (playlist));
3099 commit_reversible_command ();
3103 Editor::set_region_sync_position ()
3105 set_sync_point (get_preferred_edit_position (), get_regions_from_selection_and_edit_point ());
3109 Editor::set_sync_point (framepos_t where, const RegionSelection& rs)
3111 bool in_command = false;
3113 for (RegionSelection::const_iterator r = rs.begin(); r != rs.end(); ++r) {
3115 if (!(*r)->region()->covers (where)) {
3119 boost::shared_ptr<Region> region ((*r)->region());
3122 begin_reversible_command (_("set sync point"));
3126 region->clear_changes ();
3127 region->set_sync_position (where);
3128 _session->add_command(new StatefulDiffCommand (region));
3132 commit_reversible_command ();
3136 /** Remove the sync positions of the selection */
3138 Editor::remove_region_sync ()
3140 RegionSelection rs = get_regions_from_selection_and_entered ();
3146 begin_reversible_command (_("remove region sync"));
3148 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3150 (*i)->region()->clear_changes ();
3151 (*i)->region()->clear_sync_position ();
3152 _session->add_command(new StatefulDiffCommand ((*i)->region()));
3155 commit_reversible_command ();
3159 Editor::naturalize_region ()
3161 RegionSelection rs = get_regions_from_selection_and_entered ();
3167 if (rs.size() > 1) {
3168 begin_reversible_command (_("move regions to original position"));
3170 begin_reversible_command (_("move region to original position"));
3173 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3174 (*i)->region()->clear_changes ();
3175 (*i)->region()->move_to_natural_position ();
3176 _session->add_command (new StatefulDiffCommand ((*i)->region()));
3179 commit_reversible_command ();
3183 Editor::align_regions (RegionPoint what)
3185 RegionSelection const rs = get_regions_from_selection_and_edit_point ();
3191 begin_reversible_command (_("align selection"));
3193 framepos_t const position = get_preferred_edit_position ();
3195 for (RegionSelection::const_iterator i = rs.begin(); i != rs.end(); ++i) {
3196 align_region_internal ((*i)->region(), what, position);
3199 commit_reversible_command ();
3202 struct RegionSortByTime {
3203 bool operator() (const RegionView* a, const RegionView* b) {
3204 return a->region()->position() < b->region()->position();
3209 Editor::align_regions_relative (RegionPoint point)
3211 RegionSelection const rs = get_regions_from_selection_and_edit_point ();
3217 framepos_t const position = get_preferred_edit_position ();
3219 framepos_t distance = 0;
3223 list<RegionView*> sorted;
3224 rs.by_position (sorted);
3226 boost::shared_ptr<Region> r ((*sorted.begin())->region());
3231 if (position > r->position()) {
3232 distance = position - r->position();
3234 distance = r->position() - position;
3240 if (position > r->last_frame()) {
3241 distance = position - r->last_frame();
3242 pos = r->position() + distance;
3244 distance = r->last_frame() - position;
3245 pos = r->position() - distance;
3251 pos = r->adjust_to_sync (position);
3252 if (pos > r->position()) {
3253 distance = pos - r->position();
3255 distance = r->position() - pos;
3261 if (pos == r->position()) {
3265 begin_reversible_command (_("align selection (relative)"));
3267 /* move first one specially */
3269 r->clear_changes ();
3270 r->set_position (pos);
3271 _session->add_command(new StatefulDiffCommand (r));
3273 /* move rest by the same amount */
3277 for (list<RegionView*>::iterator i = sorted.begin(); i != sorted.end(); ++i) {
3279 boost::shared_ptr<Region> region ((*i)->region());
3281 region->clear_changes ();
3284 region->set_position (region->position() + distance);
3286 region->set_position (region->position() - distance);
3289 _session->add_command(new StatefulDiffCommand (region));
3293 commit_reversible_command ();
3297 Editor::align_region (boost::shared_ptr<Region> region, RegionPoint point, framepos_t position)
3299 begin_reversible_command (_("align region"));
3300 align_region_internal (region, point, position);
3301 commit_reversible_command ();
3305 Editor::align_region_internal (boost::shared_ptr<Region> region, RegionPoint point, framepos_t position)
3307 region->clear_changes ();
3311 region->set_position (region->adjust_to_sync (position));
3315 if (position > region->length()) {
3316 region->set_position (position - region->length());
3321 region->set_position (position);
3325 _session->add_command(new StatefulDiffCommand (region));
3329 Editor::trim_region_front ()
3335 Editor::trim_region_back ()
3337 trim_region (false);
3341 Editor::trim_region (bool front)
3343 framepos_t where = get_preferred_edit_position();
3344 RegionSelection rs = get_regions_from_selection_and_edit_point ();
3350 begin_reversible_command (front ? _("trim front") : _("trim back"));
3352 for (list<RegionView*>::const_iterator i = rs.by_layer().begin(); i != rs.by_layer().end(); ++i) {
3353 if (!(*i)->region()->locked()) {
3355 (*i)->region()->clear_changes ();
3358 (*i)->region()->trim_front (where);
3359 maybe_locate_with_edit_preroll ( where );
3361 (*i)->region()->trim_end (where);
3362 maybe_locate_with_edit_preroll ( where );
3365 _session->add_command (new StatefulDiffCommand ((*i)->region()));
3369 commit_reversible_command ();
3372 /** Trim the end of the selected regions to the position of the edit cursor */
3374 Editor::trim_region_to_loop ()
3376 Location* loc = _session->locations()->auto_loop_location();
3380 trim_region_to_location (*loc, _("trim to loop"));
3384 Editor::trim_region_to_punch ()
3386 Location* loc = _session->locations()->auto_punch_location();
3390 trim_region_to_location (*loc, _("trim to punch"));
3394 Editor::trim_region_to_location (const Location& loc, const char* str)
3396 RegionSelection rs = get_regions_from_selection_and_entered ();
3398 begin_reversible_command (str);
3400 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
3401 RegionView* rv = (*x);
3403 /* require region to span proposed trim */
3404 switch (rv->region()->coverage (loc.start(), loc.end())) {
3405 case Evoral::OverlapInternal:
3411 RouteTimeAxisView* tav = dynamic_cast<RouteTimeAxisView*> (&rv->get_time_axis_view());
3420 if (tav->track() != 0) {
3421 speed = tav->track()->speed();
3424 start = session_frame_to_track_frame (loc.start(), speed);
3425 end = session_frame_to_track_frame (loc.end(), speed);
3427 rv->region()->clear_changes ();
3428 rv->region()->trim_to (start, (end - start));
3429 _session->add_command(new StatefulDiffCommand (rv->region()));
3432 commit_reversible_command ();
3436 Editor::trim_region_to_previous_region_end ()
3438 return trim_to_region(false);
3442 Editor::trim_region_to_next_region_start ()
3444 return trim_to_region(true);
3448 Editor::trim_to_region(bool forward)
3450 RegionSelection rs = get_regions_from_selection_and_entered ();
3452 begin_reversible_command (_("trim to region"));
3454 boost::shared_ptr<Region> next_region;
3456 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
3458 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*x);
3464 AudioTimeAxisView* atav = dynamic_cast<AudioTimeAxisView*> (&arv->get_time_axis_view());
3472 if (atav->track() != 0) {
3473 speed = atav->track()->speed();
3477 boost::shared_ptr<Region> region = arv->region();
3478 boost::shared_ptr<Playlist> playlist (region->playlist());
3480 region->clear_changes ();
3484 next_region = playlist->find_next_region (region->first_frame(), Start, 1);
3490 region->trim_end((framepos_t) ( (next_region->first_frame() - 1) * speed));
3491 arv->region_changed (PropertyChange (ARDOUR::Properties::length));
3495 next_region = playlist->find_next_region (region->first_frame(), Start, 0);
3501 region->trim_front((framepos_t) ((next_region->last_frame() + 1) * speed));
3503 arv->region_changed (ARDOUR::bounds_change);
3506 _session->add_command(new StatefulDiffCommand (region));
3509 commit_reversible_command ();
3513 Editor::unfreeze_route ()
3515 if (clicked_routeview == 0 || !clicked_routeview->is_track()) {
3519 clicked_routeview->track()->unfreeze ();
3523 Editor::_freeze_thread (void* arg)
3525 return static_cast<Editor*>(arg)->freeze_thread ();
3529 Editor::freeze_thread ()
3531 /* create event pool because we may need to talk to the session */
3532 SessionEvent::create_per_thread_pool ("freeze events", 64);
3533 /* create per-thread buffers for process() tree to use */
3534 clicked_routeview->audio_track()->freeze_me (*current_interthread_info);
3535 current_interthread_info->done = true;
3540 Editor::freeze_route ()
3546 /* stop transport before we start. this is important */
3548 _session->request_transport_speed (0.0);
3550 /* wait for just a little while, because the above call is asynchronous */
3552 Glib::usleep (250000);
3554 if (clicked_routeview == 0 || !clicked_routeview->is_audio_track()) {
3558 if (!clicked_routeview->track()->bounceable (clicked_routeview->track()->main_outs(), true)) {
3560 _("This track/bus cannot be frozen because the signal adds or loses channels before reaching the outputs.\n"
3561 "This is typically caused by plugins that generate stereo output from mono input or vice versa.")
3563 d.set_title (_("Cannot freeze"));
3568 if (clicked_routeview->track()->has_external_redirects()) {
3569 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"
3570 "Freezing will only process the signal as far as the first send/insert/return."),
3571 clicked_routeview->track()->name()), true, MESSAGE_INFO, BUTTONS_NONE, true);
3573 d.add_button (_("Freeze anyway"), Gtk::RESPONSE_OK);
3574 d.add_button (_("Don't freeze"), Gtk::RESPONSE_CANCEL);
3575 d.set_title (_("Freeze Limits"));
3577 int response = d.run ();
3580 case Gtk::RESPONSE_CANCEL:
3587 InterThreadInfo itt;
3588 current_interthread_info = &itt;
3590 InterthreadProgressWindow ipw (current_interthread_info, _("Freeze"), _("Cancel Freeze"));
3592 pthread_create_and_store (X_("freezer"), &itt.thread, _freeze_thread, this);
3594 set_canvas_cursor (_cursors->wait);
3596 while (!itt.done && !itt.cancel) {
3597 gtk_main_iteration ();
3600 current_interthread_info = 0;
3601 set_canvas_cursor (current_canvas_cursor);
3605 Editor::bounce_range_selection (bool replace, bool enable_processing)
3607 if (selection->time.empty()) {
3611 TrackSelection views = selection->tracks;
3613 for (TrackViewList::iterator i = views.begin(); i != views.end(); ++i) {
3615 if (enable_processing) {
3617 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*i);
3619 if (rtv && rtv->track() && replace && enable_processing && !rtv->track()->bounceable (rtv->track()->main_outs(), false)) {
3621 _("You can't perform this operation because the processing of the signal "
3622 "will cause one or more of the tracks to end up with a region with more channels than this track has inputs.\n\n"
3623 "You can do this without processing, which is a different operation.")
3625 d.set_title (_("Cannot bounce"));
3632 framepos_t start = selection->time[clicked_selection].start;
3633 framepos_t end = selection->time[clicked_selection].end;
3634 framepos_t cnt = end - start + 1;
3636 begin_reversible_command (_("bounce range"));
3638 for (TrackViewList::iterator i = views.begin(); i != views.end(); ++i) {
3640 RouteTimeAxisView* rtv;
3642 if ((rtv = dynamic_cast<RouteTimeAxisView*> (*i)) == 0) {
3646 boost::shared_ptr<Playlist> playlist;
3648 if ((playlist = rtv->playlist()) == 0) {
3652 InterThreadInfo itt;
3654 playlist->clear_changes ();
3655 playlist->clear_owned_changes ();
3657 boost::shared_ptr<Region> r;
3659 if (enable_processing) {
3660 r = rtv->track()->bounce_range (start, start+cnt, itt, rtv->track()->main_outs(), false);
3662 r = rtv->track()->bounce_range (start, start+cnt, itt, boost::shared_ptr<Processor>(), false);
3670 list<AudioRange> ranges;
3671 ranges.push_back (AudioRange (start, start+cnt, 0));
3672 playlist->cut (ranges); // discard result
3673 playlist->add_region (r, start);
3676 vector<Command*> cmds;
3677 playlist->rdiff (cmds);
3678 _session->add_commands (cmds);
3680 _session->add_command (new StatefulDiffCommand (playlist));
3683 commit_reversible_command ();
3686 /** Delete selected regions, automation points or a time range */
3693 /** Cut selected regions, automation points or a time range */
3700 /** Copy selected regions, automation points or a time range */
3708 /** @return true if a Cut, Copy or Clear is possible */
3710 Editor::can_cut_copy () const
3712 switch (effective_mouse_mode()) {
3715 if (!selection->regions.empty() || !selection->points.empty()) {
3721 if (!selection->time.empty()) {
3734 /** Cut, copy or clear selected regions, automation points or a time range.
3735 * @param op Operation (Cut, Copy or Clear)
3738 Editor::cut_copy (CutCopyOp op)
3740 /* only cancel selection if cut/copy is successful.*/
3746 opname = _("delete");
3755 opname = _("clear");
3759 /* if we're deleting something, and the mouse is still pressed,
3760 the thing we started a drag for will be gone when we release
3761 the mouse button(s). avoid this. see part 2 at the end of
3765 if (op == Delete || op == Cut || op == Clear) {
3766 if (_drags->active ()) {
3771 if ( op != Clear ) //"Delete" doesn't change copy/paste buf
3772 cut_buffer->clear ();
3774 if (entered_marker) {
3776 /* cut/delete op while pointing at a marker */
3779 Location* loc = find_location_from_marker (entered_marker, ignored);
3781 if (_session && loc) {
3782 Glib::signal_idle().connect (sigc::bind (sigc::mem_fun(*this, &Editor::really_remove_marker), loc));
3789 if (internal_editing()) {
3791 switch (effective_mouse_mode()) {
3794 begin_reversible_command (opname + ' ' + X_("MIDI"));
3796 commit_reversible_command ();
3805 bool did_edit = false;
3807 switch (effective_mouse_mode()) {
3809 if (!selection->points.empty()) {
3810 begin_reversible_command (opname + _(" points"));
3812 cut_copy_points (op);
3813 if (op == Cut || op == Delete) {
3814 selection->clear_points ();
3821 if (!selection->regions.empty() || !selection->points.empty()) {
3825 if (selection->regions.empty()) {
3826 thing_name = _("points");
3827 } else if (selection->points.empty()) {
3828 thing_name = _("regions");
3830 thing_name = _("objects");
3833 begin_reversible_command (opname + ' ' + thing_name);
3836 if (!selection->regions.empty()) {
3837 cut_copy_regions (op, selection->regions);
3839 if (op == Cut || op == Delete) {
3840 selection->clear_regions ();
3844 if (!selection->points.empty()) {
3845 cut_copy_points (op);
3847 if (op == Cut || op == Delete) {
3848 selection->clear_points ();
3855 if (selection->time.empty()) {
3856 framepos_t start, end;
3857 /* no time selection, see if we can get an edit range
3860 if (get_edit_op_range (start, end)) {
3861 selection->set (start, end);
3864 if (!selection->time.empty()) {
3865 begin_reversible_command (opname + _(" range"));
3868 cut_copy_ranges (op);
3870 if (op == Cut || op == Delete) {
3871 selection->clear_time ();
3881 commit_reversible_command ();
3884 if (op == Delete || op == Cut || op == Clear) {
3889 struct AutomationRecord {
3890 AutomationRecord () : state (0) {}
3891 AutomationRecord (XMLNode* s) : state (s) {}
3893 XMLNode* state; ///< state before any operation
3894 boost::shared_ptr<Evoral::ControlList> copy; ///< copied events for the cut buffer
3897 /** Cut, copy or clear selected automation points.
3898 * @param op Operation (Cut, Copy or Clear)
3901 Editor::cut_copy_points (CutCopyOp op)
3903 if (selection->points.empty ()) {
3907 /* XXX: not ideal, as there may be more than one track involved in the point selection */
3908 _last_cut_copy_source_track = &selection->points.front()->line().trackview;
3910 /* Keep a record of the AutomationLists that we end up using in this operation */
3911 typedef std::map<boost::shared_ptr<AutomationList>, AutomationRecord> Lists;
3914 /* Go through all selected points, making an AutomationRecord for each distinct AutomationList */
3915 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
3916 boost::shared_ptr<AutomationList> al = (*i)->line().the_list();
3917 if (lists.find (al) == lists.end ()) {
3918 /* We haven't seen this list yet, so make a record for it. This includes
3919 taking a copy of its current state, in case this is needed for undo later.
3921 lists[al] = AutomationRecord (&al->get_state ());
3925 if (op == Cut || op == Copy) {
3926 /* This operation will involve putting things in the cut buffer, so create an empty
3927 ControlList for each of our source lists to put the cut buffer data in.
3929 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
3930 i->second.copy = i->first->create (i->first->parameter ());
3933 /* Add all selected points to the relevant copy ControlLists */
3934 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
3935 boost::shared_ptr<AutomationList> al = (*i)->line().the_list();
3936 AutomationList::const_iterator j = (*i)->model ();
3937 lists[al].copy->add ((*j)->when, (*j)->value);
3940 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
3941 /* Correct this copy list so that it starts at time 0 */
3942 double const start = i->second.copy->front()->when;
3943 for (AutomationList::iterator j = i->second.copy->begin(); j != i->second.copy->end(); ++j) {
3944 (*j)->when -= start;
3947 /* And add it to the cut buffer */
3948 cut_buffer->add (i->second.copy);
3952 if (op == Delete || op == Cut) {
3953 /* This operation needs to remove things from the main AutomationList, so do that now */
3955 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
3956 i->first->freeze ();
3959 /* Remove each selected point from its AutomationList */
3960 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
3961 boost::shared_ptr<AutomationList> al = (*i)->line().the_list();
3962 al->erase ((*i)->model ());
3965 /* Thaw the lists and add undo records for them */
3966 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
3967 boost::shared_ptr<AutomationList> al = i->first;
3969 _session->add_command (new MementoCommand<AutomationList> (*al.get(), i->second.state, &(al->get_state ())));
3974 /** Cut, copy or clear selected automation points.
3975 * @param op Operation (Cut, Copy or Clear)
3978 Editor::cut_copy_midi (CutCopyOp op)
3980 for (MidiRegionSelection::iterator i = selection->midi_regions.begin(); i != selection->midi_regions.end(); ++i) {
3981 MidiRegionView* mrv = *i;
3982 mrv->cut_copy_clear (op);
3988 struct lt_playlist {
3989 bool operator () (const PlaylistState& a, const PlaylistState& b) {
3990 return a.playlist < b.playlist;
3994 struct PlaylistMapping {
3996 boost::shared_ptr<Playlist> pl;
3998 PlaylistMapping (TimeAxisView* tvp) : tv (tvp) {}
4001 /** Remove `clicked_regionview' */
4003 Editor::remove_clicked_region ()
4005 if (clicked_routeview == 0 || clicked_regionview == 0) {
4009 boost::shared_ptr<Playlist> playlist = clicked_routeview->playlist();
4011 begin_reversible_command (_("remove region"));
4012 playlist->clear_changes ();
4013 playlist->clear_owned_changes ();
4014 playlist->remove_region (clicked_regionview->region());
4016 /* We might have removed regions, which alters other regions' layering_index,
4017 so we need to do a recursive diff here.
4019 vector<Command*> cmds;
4020 playlist->rdiff (cmds);
4021 _session->add_commands (cmds);
4023 _session->add_command(new StatefulDiffCommand (playlist));
4024 commit_reversible_command ();
4028 /** Remove the selected regions */
4030 Editor::remove_selected_regions ()
4032 RegionSelection rs = get_regions_from_selection_and_entered ();
4034 if (!_session || rs.empty()) {
4038 begin_reversible_command (_("remove region"));
4040 list<boost::shared_ptr<Region> > regions_to_remove;
4042 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
4043 // we can't just remove the region(s) in this loop because
4044 // this removes them from the RegionSelection, and they thus
4045 // disappear from underneath the iterator, and the ++i above
4046 // SEGVs in a puzzling fashion.
4048 // so, first iterate over the regions to be removed from rs and
4049 // add them to the regions_to_remove list, and then
4050 // iterate over the list to actually remove them.
4052 regions_to_remove.push_back ((*i)->region());
4055 vector<boost::shared_ptr<Playlist> > playlists;
4057 for (list<boost::shared_ptr<Region> >::iterator rl = regions_to_remove.begin(); rl != regions_to_remove.end(); ++rl) {
4059 boost::shared_ptr<Playlist> playlist = (*rl)->playlist();
4062 // is this check necessary?
4066 /* get_regions_from_selection_and_entered() guarantees that
4067 the playlists involved are unique, so there is no need
4071 playlists.push_back (playlist);
4073 playlist->clear_changes ();
4074 playlist->clear_owned_changes ();
4075 playlist->freeze ();
4076 playlist->remove_region (*rl);
4079 vector<boost::shared_ptr<Playlist> >::iterator pl;
4081 for (pl = playlists.begin(); pl != playlists.end(); ++pl) {
4084 /* We might have removed regions, which alters other regions' layering_index,
4085 so we need to do a recursive diff here.
4087 vector<Command*> cmds;
4088 (*pl)->rdiff (cmds);
4089 _session->add_commands (cmds);
4091 _session->add_command(new StatefulDiffCommand (*pl));
4094 commit_reversible_command ();
4097 /** Cut, copy or clear selected regions.
4098 * @param op Operation (Cut, Copy or Clear)
4101 Editor::cut_copy_regions (CutCopyOp op, RegionSelection& rs)
4103 /* we can't use a std::map here because the ordering is important, and we can't trivially sort
4104 a map when we want ordered access to both elements. i think.
4107 vector<PlaylistMapping> pmap;
4109 framepos_t first_position = max_framepos;
4111 typedef set<boost::shared_ptr<Playlist> > FreezeList;
4112 FreezeList freezelist;
4114 /* get ordering correct before we cut/copy */
4116 rs.sort_by_position_and_track ();
4118 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
4120 first_position = min ((framepos_t) (*x)->region()->position(), first_position);
4122 if (op == Cut || op == Clear || op == Delete) {
4123 boost::shared_ptr<Playlist> pl = (*x)->region()->playlist();
4126 FreezeList::iterator fl;
4128 // only take state if this is a new playlist.
4129 for (fl = freezelist.begin(); fl != freezelist.end(); ++fl) {
4135 if (fl == freezelist.end()) {
4136 pl->clear_changes();
4137 pl->clear_owned_changes ();
4139 freezelist.insert (pl);
4144 TimeAxisView* tv = &(*x)->get_time_axis_view();
4145 vector<PlaylistMapping>::iterator z;
4147 for (z = pmap.begin(); z != pmap.end(); ++z) {
4148 if ((*z).tv == tv) {
4153 if (z == pmap.end()) {
4154 pmap.push_back (PlaylistMapping (tv));
4158 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ) {
4160 boost::shared_ptr<Playlist> pl = (*x)->region()->playlist();
4163 /* region not yet associated with a playlist (e.g. unfinished
4170 TimeAxisView& tv = (*x)->get_time_axis_view();
4171 boost::shared_ptr<Playlist> npl;
4172 RegionSelection::iterator tmp;
4179 vector<PlaylistMapping>::iterator z;
4181 for (z = pmap.begin(); z != pmap.end(); ++z) {
4182 if ((*z).tv == &tv) {
4187 assert (z != pmap.end());
4190 npl = PlaylistFactory::create (pl->data_type(), *_session, "cutlist", true);
4198 boost::shared_ptr<Region> r = (*x)->region();
4199 boost::shared_ptr<Region> _xx;
4205 pl->remove_region (r);
4209 _xx = RegionFactory::create (r);
4210 npl->add_region (_xx, r->position() - first_position);
4211 pl->remove_region (r);
4215 /* copy region before adding, so we're not putting same object into two different playlists */
4216 npl->add_region (RegionFactory::create (r), r->position() - first_position);
4220 pl->remove_region (r);
4229 list<boost::shared_ptr<Playlist> > foo;
4231 /* the pmap is in the same order as the tracks in which selected regions occured */
4233 for (vector<PlaylistMapping>::iterator i = pmap.begin(); i != pmap.end(); ++i) {
4236 foo.push_back ((*i).pl);
4241 cut_buffer->set (foo);
4245 _last_cut_copy_source_track = 0;
4247 _last_cut_copy_source_track = pmap.front().tv;
4251 for (FreezeList::iterator pl = freezelist.begin(); pl != freezelist.end(); ++pl) {
4254 /* We might have removed regions, which alters other regions' layering_index,
4255 so we need to do a recursive diff here.
4257 vector<Command*> cmds;
4258 (*pl)->rdiff (cmds);
4259 _session->add_commands (cmds);
4261 _session->add_command (new StatefulDiffCommand (*pl));
4266 Editor::cut_copy_ranges (CutCopyOp op)
4268 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4270 /* Sort the track selection now, so that it if is used, the playlists
4271 selected by the calls below to cut_copy_clear are in the order that
4272 their tracks appear in the editor. This makes things like paste
4273 of ranges work properly.
4276 sort_track_selection (ts);
4279 if (!entered_track) {
4282 ts.push_back (entered_track);
4285 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4286 (*i)->cut_copy_clear (*selection, op);
4291 Editor::paste (float times, bool from_context)
4293 DEBUG_TRACE (DEBUG::CutNPaste, "paste to preferred edit pos\n");
4295 paste_internal (get_preferred_edit_position (false, from_context), times);
4299 Editor::mouse_paste ()
4304 if (!mouse_frame (where, ignored)) {
4309 paste_internal (where, 1);
4313 Editor::paste_internal (framepos_t position, float times)
4315 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("apparent paste position is %1\n", position));
4317 if (internal_editing()) {
4318 if (cut_buffer->midi_notes.empty()) {
4322 if (cut_buffer->empty()) {
4327 if (position == max_framepos) {
4328 position = get_preferred_edit_position();
4329 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("preferred edit position is %1\n", position));
4333 TrackViewList::iterator i;
4336 /* get everything in the correct order */
4338 if (_edit_point == Editing::EditAtMouse && entered_track) {
4339 /* With the mouse edit point, paste onto the track under the mouse */
4340 ts.push_back (entered_track);
4341 } else if (!selection->tracks.empty()) {
4342 /* Otherwise, if there are some selected tracks, paste to them */
4343 ts = selection->tracks.filter_to_unique_playlists ();
4344 sort_track_selection (ts);
4345 } else if (_last_cut_copy_source_track) {
4346 /* Otherwise paste to the track that the cut/copy came from;
4347 see discussion in mantis #3333.
4349 ts.push_back (_last_cut_copy_source_track);
4352 if (internal_editing ()) {
4354 /* undo/redo is handled by individual tracks/regions */
4356 for (nth = 0, i = ts.begin(); i != ts.end(); ++i, ++nth) {
4359 RegionSelection::iterator r;
4360 MidiNoteSelection::iterator cb;
4362 get_regions_at (rs, position, ts);
4364 for (cb = cut_buffer->midi_notes.begin(), r = rs.begin();
4365 cb != cut_buffer->midi_notes.end() && r != rs.end(); ++r) {
4366 MidiRegionView* mrv = dynamic_cast<MidiRegionView*> (*r);
4368 mrv->paste (position, times, **cb);
4376 /* we do redo (do you do voodoo?) */
4378 begin_reversible_command (Operations::paste);
4380 for (nth = 0, i = ts.begin(); i != ts.end(); ++i, ++nth) {
4381 (*i)->paste (position, times, *cut_buffer, nth);
4384 commit_reversible_command ();
4389 Editor::duplicate_some_regions (RegionSelection& regions, float times)
4391 boost::shared_ptr<Playlist> playlist;
4392 RegionSelection sel = regions; // clear (below) may clear the argument list if its the current region selection
4393 RegionSelection foo;
4395 framepos_t const start_frame = regions.start ();
4396 framepos_t const end_frame = regions.end_frame ();
4398 begin_reversible_command (Operations::duplicate_region);
4400 selection->clear_regions ();
4402 for (RegionSelection::iterator i = sel.begin(); i != sel.end(); ++i) {
4404 boost::shared_ptr<Region> r ((*i)->region());
4406 TimeAxisView& tv = (*i)->get_time_axis_view();
4407 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (&tv);
4408 latest_regionviews.clear ();
4409 sigc::connection c = rtv->view()->RegionViewAdded.connect (sigc::mem_fun(*this, &Editor::collect_new_region_view));
4411 playlist = (*i)->region()->playlist();
4412 playlist->clear_changes ();
4413 playlist->duplicate (r, end_frame + (r->first_frame() - start_frame), times);
4414 _session->add_command(new StatefulDiffCommand (playlist));
4418 foo.insert (foo.end(), latest_regionviews.begin(), latest_regionviews.end());
4421 commit_reversible_command ();
4424 selection->set (foo);
4429 Editor::duplicate_selection (float times)
4431 if (selection->time.empty() || selection->tracks.empty()) {
4435 boost::shared_ptr<Playlist> playlist;
4436 vector<boost::shared_ptr<Region> > new_regions;
4437 vector<boost::shared_ptr<Region> >::iterator ri;
4439 create_region_from_selection (new_regions);
4441 if (new_regions.empty()) {
4445 begin_reversible_command (_("duplicate selection"));
4447 ri = new_regions.begin();
4449 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4451 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4452 if ((playlist = (*i)->playlist()) == 0) {
4455 playlist->clear_changes ();
4456 playlist->duplicate (*ri, selection->time[clicked_selection].end, times);
4457 _session->add_command (new StatefulDiffCommand (playlist));
4460 if (ri == new_regions.end()) {
4465 commit_reversible_command ();
4468 /** Reset all selected points to the relevant default value */
4470 Editor::reset_point_selection ()
4472 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
4473 ARDOUR::AutomationList::iterator j = (*i)->model ();
4474 (*j)->value = (*i)->line().the_list()->default_value ();
4479 Editor::center_playhead ()
4481 float const page = _visible_canvas_width * samples_per_pixel;
4482 center_screen_internal (playhead_cursor->current_frame (), page);
4486 Editor::center_edit_point ()
4488 float const page = _visible_canvas_width * samples_per_pixel;
4489 center_screen_internal (get_preferred_edit_position(), page);
4492 /** Caller must begin and commit a reversible command */
4494 Editor::clear_playlist (boost::shared_ptr<Playlist> playlist)
4496 playlist->clear_changes ();
4498 _session->add_command (new StatefulDiffCommand (playlist));
4502 Editor::nudge_track (bool use_edit, bool forwards)
4504 boost::shared_ptr<Playlist> playlist;
4505 framepos_t distance;
4506 framepos_t next_distance;
4510 start = get_preferred_edit_position();
4515 if ((distance = get_nudge_distance (start, next_distance)) == 0) {
4519 if (selection->tracks.empty()) {
4523 begin_reversible_command (_("nudge track"));
4525 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4527 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4529 if ((playlist = (*i)->playlist()) == 0) {
4533 playlist->clear_changes ();
4534 playlist->clear_owned_changes ();
4536 playlist->nudge_after (start, distance, forwards);
4538 vector<Command*> cmds;
4540 playlist->rdiff (cmds);
4541 _session->add_commands (cmds);
4543 _session->add_command (new StatefulDiffCommand (playlist));
4546 commit_reversible_command ();
4550 Editor::remove_last_capture ()
4552 vector<string> choices;
4559 if (Config->get_verify_remove_last_capture()) {
4560 prompt = _("Do you really want to destroy the last capture?"
4561 "\n(This is destructive and cannot be undone)");
4563 choices.push_back (_("No, do nothing."));
4564 choices.push_back (_("Yes, destroy it."));
4566 Gtkmm2ext::Choice prompter (_("Destroy last capture"), prompt, choices);
4568 if (prompter.run () == 1) {
4569 _session->remove_last_capture ();
4570 _regions->redisplay ();
4574 _session->remove_last_capture();
4575 _regions->redisplay ();
4580 Editor::normalize_region ()
4586 RegionSelection rs = get_regions_from_selection_and_entered ();
4592 NormalizeDialog dialog (rs.size() > 1);
4594 if (dialog.run () == RESPONSE_CANCEL) {
4598 set_canvas_cursor (_cursors->wait);
4601 /* XXX: should really only count audio regions here */
4602 int const regions = rs.size ();
4604 /* Make a list of the selected audio regions' maximum amplitudes, and also
4605 obtain the maximum amplitude of them all.
4607 list<double> max_amps;
4609 for (RegionSelection::const_iterator i = rs.begin(); i != rs.end(); ++i) {
4610 AudioRegionView const * arv = dynamic_cast<AudioRegionView const *> (*i);
4612 dialog.descend (1.0 / regions);
4613 double const a = arv->audio_region()->maximum_amplitude (&dialog);
4616 /* the user cancelled the operation */
4617 set_canvas_cursor (current_canvas_cursor);
4621 max_amps.push_back (a);
4622 max_amp = max (max_amp, a);
4627 begin_reversible_command (_("normalize"));
4629 list<double>::const_iterator a = max_amps.begin ();
4631 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
4632 AudioRegionView* const arv = dynamic_cast<AudioRegionView*> (*r);
4637 arv->region()->clear_changes ();
4639 double const amp = dialog.normalize_individually() ? *a : max_amp;
4641 arv->audio_region()->normalize (amp, dialog.target ());
4642 _session->add_command (new StatefulDiffCommand (arv->region()));
4647 commit_reversible_command ();
4648 set_canvas_cursor (current_canvas_cursor);
4653 Editor::reset_region_scale_amplitude ()
4659 RegionSelection rs = get_regions_from_selection_and_entered ();
4665 begin_reversible_command ("reset gain");
4667 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
4668 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
4671 arv->region()->clear_changes ();
4672 arv->audio_region()->set_scale_amplitude (1.0f);
4673 _session->add_command (new StatefulDiffCommand (arv->region()));
4676 commit_reversible_command ();
4680 Editor::adjust_region_gain (bool up)
4682 RegionSelection rs = get_regions_from_selection_and_entered ();
4684 if (!_session || rs.empty()) {
4688 begin_reversible_command ("adjust region gain");
4690 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
4691 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
4696 arv->region()->clear_changes ();
4698 double dB = accurate_coefficient_to_dB (arv->audio_region()->scale_amplitude ());
4706 arv->audio_region()->set_scale_amplitude (dB_to_coefficient (dB));
4707 _session->add_command (new StatefulDiffCommand (arv->region()));
4710 commit_reversible_command ();
4715 Editor::reverse_region ()
4721 Reverse rev (*_session);
4722 apply_filter (rev, _("reverse regions"));
4726 Editor::strip_region_silence ()
4732 RegionSelection rs = get_regions_from_selection_and_entered ();
4738 std::list<RegionView*> audio_only;
4740 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
4741 AudioRegionView* const arv = dynamic_cast<AudioRegionView*> (*i);
4743 audio_only.push_back (arv);
4747 StripSilenceDialog d (_session, audio_only);
4748 int const r = d.run ();
4752 if (r == Gtk::RESPONSE_OK) {
4753 ARDOUR::AudioIntervalMap silences;
4754 d.silences (silences);
4755 StripSilence s (*_session, silences, d.fade_length());
4756 apply_filter (s, _("strip silence"), &d);
4761 Editor::apply_midi_note_edit_op_to_region (MidiOperator& op, MidiRegionView& mrv)
4763 Evoral::Sequence<Evoral::MusicalTime>::Notes selected;
4764 mrv.selection_as_notelist (selected, true);
4766 vector<Evoral::Sequence<Evoral::MusicalTime>::Notes> v;
4767 v.push_back (selected);
4769 framepos_t pos_frames = mrv.midi_region()->position() - mrv.midi_region()->start();
4770 double pos_beats = _session->tempo_map().framewalk_to_beats(0, pos_frames);
4772 return op (mrv.midi_region()->model(), pos_beats, v);
4776 Editor::apply_midi_note_edit_op (MidiOperator& op)
4780 RegionSelection rs = get_regions_from_selection_and_entered ();
4786 begin_reversible_command (op.name ());
4788 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
4789 RegionSelection::iterator tmp = r;
4792 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*r);
4795 cmd = apply_midi_note_edit_op_to_region (op, *mrv);
4798 _session->add_command (cmd);
4805 commit_reversible_command ();
4809 Editor::fork_region ()
4811 RegionSelection rs = get_regions_from_selection_and_entered ();
4817 begin_reversible_command (_("Fork Region(s)"));
4819 set_canvas_cursor (_cursors->wait);
4822 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
4823 RegionSelection::iterator tmp = r;
4826 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*>(*r);
4830 boost::shared_ptr<Playlist> playlist = mrv->region()->playlist();
4831 boost::shared_ptr<MidiSource> new_source = _session->create_midi_source_by_stealing_name (mrv->midi_view()->track());
4832 boost::shared_ptr<MidiRegion> newregion = mrv->midi_region()->clone (new_source);
4834 playlist->clear_changes ();
4835 playlist->replace_region (mrv->region(), newregion, mrv->region()->position());
4836 _session->add_command(new StatefulDiffCommand (playlist));
4838 error << string_compose (_("Could not unlink %1"), mrv->region()->name()) << endmsg;
4845 commit_reversible_command ();
4847 set_canvas_cursor (current_canvas_cursor);
4851 Editor::quantize_region ()
4853 int selected_midi_region_cnt = 0;
4859 RegionSelection rs = get_regions_from_selection_and_entered ();
4865 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
4866 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*r);
4868 selected_midi_region_cnt++;
4872 if (selected_midi_region_cnt == 0) {
4876 QuantizeDialog* qd = new QuantizeDialog (*this);
4879 const int r = qd->run ();
4882 if (r == Gtk::RESPONSE_OK) {
4883 Quantize quant (*_session, qd->snap_start(), qd->snap_end(),
4884 qd->start_grid_size(), qd->end_grid_size(),
4885 qd->strength(), qd->swing(), qd->threshold());
4887 apply_midi_note_edit_op (quant);
4892 Editor::insert_patch_change (bool from_context)
4894 RegionSelection rs = get_regions_from_selection_and_entered ();
4900 const framepos_t p = get_preferred_edit_position (false, from_context);
4902 /* XXX: bit of a hack; use the MIDNAM from the first selected region;
4903 there may be more than one, but the PatchChangeDialog can only offer
4904 one set of patch menus.
4906 MidiRegionView* first = dynamic_cast<MidiRegionView*> (rs.front ());
4908 Evoral::PatchChange<Evoral::MusicalTime> empty (0, 0, 0, 0);
4909 PatchChangeDialog d (0, _session, empty, first->instrument_info(), Gtk::Stock::ADD);
4911 if (d.run() == RESPONSE_CANCEL) {
4915 for (RegionSelection::iterator i = rs.begin (); i != rs.end(); ++i) {
4916 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*i);
4918 if (p >= mrv->region()->first_frame() && p <= mrv->region()->last_frame()) {
4919 mrv->add_patch_change (p - mrv->region()->position(), d.patch ());
4926 Editor::apply_filter (Filter& filter, string command, ProgressReporter* progress)
4928 RegionSelection rs = get_regions_from_selection_and_entered ();
4934 begin_reversible_command (command);
4936 set_canvas_cursor (_cursors->wait);
4940 int const N = rs.size ();
4942 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
4943 RegionSelection::iterator tmp = r;
4946 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
4948 boost::shared_ptr<Playlist> playlist = arv->region()->playlist();
4951 progress->descend (1.0 / N);
4954 if (arv->audio_region()->apply (filter, progress) == 0) {
4956 playlist->clear_changes ();
4957 playlist->clear_owned_changes ();
4959 if (filter.results.empty ()) {
4961 /* no regions returned; remove the old one */
4962 playlist->remove_region (arv->region ());
4966 std::vector<boost::shared_ptr<Region> >::iterator res = filter.results.begin ();
4968 /* first region replaces the old one */
4969 playlist->replace_region (arv->region(), *res, (*res)->position());
4973 while (res != filter.results.end()) {
4974 playlist->add_region (*res, (*res)->position());
4980 /* We might have removed regions, which alters other regions' layering_index,
4981 so we need to do a recursive diff here.
4983 vector<Command*> cmds;
4984 playlist->rdiff (cmds);
4985 _session->add_commands (cmds);
4987 _session->add_command(new StatefulDiffCommand (playlist));
4993 progress->ascend ();
5001 commit_reversible_command ();
5004 set_canvas_cursor (current_canvas_cursor);
5008 Editor::external_edit_region ()
5014 Editor::reset_region_gain_envelopes ()
5016 RegionSelection rs = get_regions_from_selection_and_entered ();
5018 if (!_session || rs.empty()) {
5022 _session->begin_reversible_command (_("reset region gain"));
5024 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5025 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
5027 boost::shared_ptr<AutomationList> alist (arv->audio_region()->envelope());
5028 XMLNode& before (alist->get_state());
5030 arv->audio_region()->set_default_envelope ();
5031 _session->add_command (new MementoCommand<AutomationList>(*arv->audio_region()->envelope().get(), &before, &alist->get_state()));
5035 _session->commit_reversible_command ();
5039 Editor::set_region_gain_visibility (RegionView* rv)
5041 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (rv);
5043 arv->update_envelope_visibility();
5048 Editor::set_gain_envelope_visibility ()
5054 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5055 AudioTimeAxisView* v = dynamic_cast<AudioTimeAxisView*>(*i);
5057 v->audio_view()->foreach_regionview (sigc::mem_fun (this, &Editor::set_region_gain_visibility));
5063 Editor::toggle_gain_envelope_active ()
5065 if (_ignore_region_action) {
5069 RegionSelection rs = get_regions_from_selection_and_entered ();
5071 if (!_session || rs.empty()) {
5075 _session->begin_reversible_command (_("region gain envelope active"));
5077 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5078 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
5080 arv->region()->clear_changes ();
5081 arv->audio_region()->set_envelope_active (!arv->audio_region()->envelope_active());
5082 _session->add_command (new StatefulDiffCommand (arv->region()));
5086 _session->commit_reversible_command ();
5090 Editor::toggle_region_lock ()
5092 if (_ignore_region_action) {
5096 RegionSelection rs = get_regions_from_selection_and_entered ();
5098 if (!_session || rs.empty()) {
5102 _session->begin_reversible_command (_("toggle region lock"));
5104 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5105 (*i)->region()->clear_changes ();
5106 (*i)->region()->set_locked (!(*i)->region()->locked());
5107 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5110 _session->commit_reversible_command ();
5114 Editor::toggle_region_video_lock ()
5116 if (_ignore_region_action) {
5120 RegionSelection rs = get_regions_from_selection_and_entered ();
5122 if (!_session || rs.empty()) {
5126 _session->begin_reversible_command (_("Toggle Video Lock"));
5128 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5129 (*i)->region()->clear_changes ();
5130 (*i)->region()->set_video_locked (!(*i)->region()->video_locked());
5131 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5134 _session->commit_reversible_command ();
5138 Editor::toggle_region_lock_style ()
5140 if (_ignore_region_action) {
5144 RegionSelection rs = get_regions_from_selection_and_entered ();
5146 if (!_session || rs.empty()) {
5150 _session->begin_reversible_command (_("region lock style"));
5152 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5153 (*i)->region()->clear_changes ();
5154 PositionLockStyle const ns = (*i)->region()->position_lock_style() == AudioTime ? MusicTime : AudioTime;
5155 (*i)->region()->set_position_lock_style (ns);
5156 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5159 _session->commit_reversible_command ();
5163 Editor::toggle_opaque_region ()
5165 if (_ignore_region_action) {
5169 RegionSelection rs = get_regions_from_selection_and_entered ();
5171 if (!_session || rs.empty()) {
5175 _session->begin_reversible_command (_("change region opacity"));
5177 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5178 (*i)->region()->clear_changes ();
5179 (*i)->region()->set_opaque (!(*i)->region()->opaque());
5180 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5183 _session->commit_reversible_command ();
5187 Editor::toggle_record_enable ()
5189 bool new_state = false;
5191 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5192 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5195 if (!rtav->is_track())
5199 new_state = !rtav->track()->record_enabled();
5203 rtav->track()->set_record_enabled (new_state, this);
5208 Editor::toggle_solo ()
5210 bool new_state = false;
5212 boost::shared_ptr<RouteList> rl (new RouteList);
5214 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5215 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5222 new_state = !rtav->route()->soloed ();
5226 rl->push_back (rtav->route());
5229 _session->set_solo (rl, new_state, Session::rt_cleanup, true);
5233 Editor::toggle_mute ()
5235 bool new_state = false;
5237 boost::shared_ptr<RouteList> rl (new RouteList);
5239 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5240 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5247 new_state = !rtav->route()->muted();
5251 rl->push_back (rtav->route());
5254 _session->set_mute (rl, new_state, Session::rt_cleanup, true);
5258 Editor::toggle_solo_isolate ()
5263 Editor::set_fade_length (bool in)
5265 RegionSelection rs = get_regions_from_selection_and_entered ();
5271 /* we need a region to measure the offset from the start */
5273 RegionView* rv = rs.front ();
5275 framepos_t pos = get_preferred_edit_position();
5279 if (pos > rv->region()->last_frame() || pos < rv->region()->first_frame()) {
5280 /* edit point is outside the relevant region */
5285 if (pos <= rv->region()->position()) {
5289 len = pos - rv->region()->position();
5290 cmd = _("set fade in length");
5292 if (pos >= rv->region()->last_frame()) {
5296 len = rv->region()->last_frame() - pos;
5297 cmd = _("set fade out length");
5300 begin_reversible_command (cmd);
5302 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5303 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5309 boost::shared_ptr<AutomationList> alist;
5311 alist = tmp->audio_region()->fade_in();
5313 alist = tmp->audio_region()->fade_out();
5316 XMLNode &before = alist->get_state();
5319 tmp->audio_region()->set_fade_in_length (len);
5320 tmp->audio_region()->set_fade_in_active (true);
5322 tmp->audio_region()->set_fade_out_length (len);
5323 tmp->audio_region()->set_fade_out_active (true);
5326 XMLNode &after = alist->get_state();
5327 _session->add_command(new MementoCommand<AutomationList>(*alist, &before, &after));
5330 commit_reversible_command ();
5334 Editor::set_fade_in_shape (FadeShape shape)
5336 RegionSelection rs = get_regions_from_selection_and_entered ();
5342 begin_reversible_command (_("set fade in shape"));
5344 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5345 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5351 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_in();
5352 XMLNode &before = alist->get_state();
5354 tmp->audio_region()->set_fade_in_shape (shape);
5356 XMLNode &after = alist->get_state();
5357 _session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
5360 commit_reversible_command ();
5365 Editor::set_fade_out_shape (FadeShape shape)
5367 RegionSelection rs = get_regions_from_selection_and_entered ();
5373 begin_reversible_command (_("set fade out shape"));
5375 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5376 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5382 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_out();
5383 XMLNode &before = alist->get_state();
5385 tmp->audio_region()->set_fade_out_shape (shape);
5387 XMLNode &after = alist->get_state();
5388 _session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
5391 commit_reversible_command ();
5395 Editor::set_fade_in_active (bool yn)
5397 RegionSelection rs = get_regions_from_selection_and_entered ();
5403 begin_reversible_command (_("set fade in active"));
5405 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5406 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5413 boost::shared_ptr<AudioRegion> ar (tmp->audio_region());
5415 ar->clear_changes ();
5416 ar->set_fade_in_active (yn);
5417 _session->add_command (new StatefulDiffCommand (ar));
5420 commit_reversible_command ();
5424 Editor::set_fade_out_active (bool yn)
5426 RegionSelection rs = get_regions_from_selection_and_entered ();
5432 begin_reversible_command (_("set fade out active"));
5434 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5435 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5441 boost::shared_ptr<AudioRegion> ar (tmp->audio_region());
5443 ar->clear_changes ();
5444 ar->set_fade_out_active (yn);
5445 _session->add_command(new StatefulDiffCommand (ar));
5448 commit_reversible_command ();
5452 Editor::toggle_region_fades (int dir)
5454 if (_ignore_region_action) {
5458 boost::shared_ptr<AudioRegion> ar;
5461 RegionSelection rs = get_regions_from_selection_and_entered ();
5467 RegionSelection::iterator i;
5468 for (i = rs.begin(); i != rs.end(); ++i) {
5469 if ((ar = boost::dynamic_pointer_cast<AudioRegion>((*i)->region())) != 0) {
5471 yn = ar->fade_out_active ();
5473 yn = ar->fade_in_active ();
5479 if (i == rs.end()) {
5483 /* XXX should this undo-able? */
5485 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5486 if ((ar = boost::dynamic_pointer_cast<AudioRegion>((*i)->region())) == 0) {
5489 if (dir == 1 || dir == 0) {
5490 ar->set_fade_in_active (!yn);
5493 if (dir == -1 || dir == 0) {
5494 ar->set_fade_out_active (!yn);
5500 /** Update region fade visibility after its configuration has been changed */
5502 Editor::update_region_fade_visibility ()
5504 bool _fade_visibility = _session->config.get_show_region_fades ();
5506 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5507 AudioTimeAxisView* v = dynamic_cast<AudioTimeAxisView*>(*i);
5509 if (_fade_visibility) {
5510 v->audio_view()->show_all_fades ();
5512 v->audio_view()->hide_all_fades ();
5519 Editor::set_edit_point ()
5524 if (!mouse_frame (where, ignored)) {
5530 if (selection->markers.empty()) {
5532 mouse_add_new_marker (where);
5537 Location* loc = find_location_from_marker (selection->markers.front(), ignored);
5540 loc->move_to (where);
5546 Editor::set_playhead_cursor ()
5548 if (entered_marker) {
5549 _session->request_locate (entered_marker->position(), _session->transport_rolling());
5554 if (!mouse_frame (where, ignored)) {
5561 _session->request_locate (where, _session->transport_rolling());
5565 if ( Config->get_always_play_range() )
5566 cancel_time_selection();
5570 Editor::split_region ()
5572 if ( !selection->time.empty()) {
5573 separate_regions_between (selection->time);
5577 RegionSelection rs = get_regions_from_selection_and_edit_point ();
5579 framepos_t where = get_preferred_edit_position ();
5585 split_regions_at (where, rs);
5588 struct EditorOrderRouteSorter {
5589 bool operator() (boost::shared_ptr<Route> a, boost::shared_ptr<Route> b) {
5590 return a->order_key () < b->order_key ();
5595 Editor::select_next_route()
5597 if (selection->tracks.empty()) {
5598 selection->set (track_views.front());
5602 TimeAxisView* current = selection->tracks.front();
5606 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5607 if (*i == current) {
5609 if (i != track_views.end()) {
5612 current = (*(track_views.begin()));
5613 //selection->set (*(track_views.begin()));
5618 rui = dynamic_cast<RouteUI *>(current);
5619 } while ( current->hidden() || (rui != NULL && !rui->route()->active()));
5621 selection->set(current);
5623 ensure_time_axis_view_is_visible (*current);
5627 Editor::select_prev_route()
5629 if (selection->tracks.empty()) {
5630 selection->set (track_views.front());
5634 TimeAxisView* current = selection->tracks.front();
5638 for (TrackViewList::reverse_iterator i = track_views.rbegin(); i != track_views.rend(); ++i) {
5639 if (*i == current) {
5641 if (i != track_views.rend()) {
5644 current = *(track_views.rbegin());
5649 rui = dynamic_cast<RouteUI *>(current);
5650 } while ( current->hidden() || (rui != NULL && !rui->route()->active()));
5652 selection->set (current);
5654 ensure_time_axis_view_is_visible (*current);
5658 Editor::set_loop_from_selection (bool play)
5660 if (_session == 0 || selection->time.empty()) {
5664 framepos_t start = selection->time[clicked_selection].start;
5665 framepos_t end = selection->time[clicked_selection].end;
5667 set_loop_range (start, end, _("set loop range from selection"));
5670 _session->request_play_loop (true);
5671 _session->request_locate (start, true);
5676 Editor::set_loop_from_edit_range (bool play)
5678 if (_session == 0) {
5685 if (!get_edit_op_range (start, end)) {
5689 set_loop_range (start, end, _("set loop range from edit range"));
5692 _session->request_play_loop (true);
5693 _session->request_locate (start, true);
5698 Editor::set_loop_from_region (bool play)
5700 framepos_t start = max_framepos;
5703 RegionSelection rs = get_regions_from_selection_and_entered ();
5709 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5710 if ((*i)->region()->position() < start) {
5711 start = (*i)->region()->position();
5713 if ((*i)->region()->last_frame() + 1 > end) {
5714 end = (*i)->region()->last_frame() + 1;
5718 set_loop_range (start, end, _("set loop range from region"));
5721 _session->request_play_loop (true);
5722 _session->request_locate (start, true);
5727 Editor::set_punch_from_selection ()
5729 if (_session == 0 || selection->time.empty()) {
5733 framepos_t start = selection->time[clicked_selection].start;
5734 framepos_t end = selection->time[clicked_selection].end;
5736 set_punch_range (start, end, _("set punch range from selection"));
5740 Editor::set_punch_from_edit_range ()
5742 if (_session == 0) {
5749 if (!get_edit_op_range (start, end)) {
5753 set_punch_range (start, end, _("set punch range from edit range"));
5757 Editor::set_punch_from_region ()
5759 framepos_t start = max_framepos;
5762 RegionSelection rs = get_regions_from_selection_and_entered ();
5768 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5769 if ((*i)->region()->position() < start) {
5770 start = (*i)->region()->position();
5772 if ((*i)->region()->last_frame() + 1 > end) {
5773 end = (*i)->region()->last_frame() + 1;
5777 set_punch_range (start, end, _("set punch range from region"));
5781 Editor::pitch_shift_region ()
5783 RegionSelection rs = get_regions_from_selection_and_entered ();
5785 RegionSelection audio_rs;
5786 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5787 if (dynamic_cast<AudioRegionView*> (*i)) {
5788 audio_rs.push_back (*i);
5792 if (audio_rs.empty()) {
5796 pitch_shift (audio_rs, 1.2);
5800 Editor::transpose_region ()
5802 RegionSelection rs = get_regions_from_selection_and_entered ();
5804 list<MidiRegionView*> midi_region_views;
5805 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5806 MidiRegionView* mrv = dynamic_cast<MidiRegionView*> (*i);
5808 midi_region_views.push_back (mrv);
5813 int const r = d.run ();
5814 if (r != RESPONSE_ACCEPT) {
5818 for (list<MidiRegionView*>::iterator i = midi_region_views.begin(); i != midi_region_views.end(); ++i) {
5819 (*i)->midi_region()->transpose (d.semitones ());
5824 Editor::set_tempo_from_region ()
5826 RegionSelection rs = get_regions_from_selection_and_entered ();
5828 if (!_session || rs.empty()) {
5832 RegionView* rv = rs.front();
5834 define_one_bar (rv->region()->position(), rv->region()->last_frame() + 1);
5838 Editor::use_range_as_bar ()
5840 framepos_t start, end;
5841 if (get_edit_op_range (start, end)) {
5842 define_one_bar (start, end);
5847 Editor::define_one_bar (framepos_t start, framepos_t end)
5849 framepos_t length = end - start;
5851 const Meter& m (_session->tempo_map().meter_at (start));
5853 /* length = 1 bar */
5855 /* now we want frames per beat.
5856 we have frames per bar, and beats per bar, so ...
5859 /* XXXX METER MATH */
5861 double frames_per_beat = length / m.divisions_per_bar();
5863 /* beats per minute = */
5865 double beats_per_minute = (_session->frame_rate() * 60.0) / frames_per_beat;
5867 /* now decide whether to:
5869 (a) set global tempo
5870 (b) add a new tempo marker
5874 const TempoSection& t (_session->tempo_map().tempo_section_at (start));
5876 bool do_global = false;
5878 if ((_session->tempo_map().n_tempos() == 1) && (_session->tempo_map().n_meters() == 1)) {
5880 /* only 1 tempo & 1 meter: ask if the user wants to set the tempo
5881 at the start, or create a new marker
5884 vector<string> options;
5885 options.push_back (_("Cancel"));
5886 options.push_back (_("Add new marker"));
5887 options.push_back (_("Set global tempo"));
5890 _("Define one bar"),
5891 _("Do you want to set the global tempo or add a new tempo marker?"),
5895 c.set_default_response (2);
5911 /* more than 1 tempo and/or meter section already, go ahead do the "usual":
5912 if the marker is at the region starter, change it, otherwise add
5917 begin_reversible_command (_("set tempo from region"));
5918 XMLNode& before (_session->tempo_map().get_state());
5921 _session->tempo_map().change_initial_tempo (beats_per_minute, t.note_type());
5922 } else if (t.frame() == start) {
5923 _session->tempo_map().change_existing_tempo_at (start, beats_per_minute, t.note_type());
5925 Timecode::BBT_Time bbt;
5926 _session->tempo_map().bbt_time (start, bbt);
5927 _session->tempo_map().add_tempo (Tempo (beats_per_minute, t.note_type()), bbt);
5930 XMLNode& after (_session->tempo_map().get_state());
5932 _session->add_command (new MementoCommand<TempoMap>(_session->tempo_map(), &before, &after));
5933 commit_reversible_command ();
5937 Editor::split_region_at_transients ()
5939 AnalysisFeatureList positions;
5941 RegionSelection rs = get_regions_from_selection_and_entered ();
5943 if (!_session || rs.empty()) {
5947 _session->begin_reversible_command (_("split regions"));
5949 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ) {
5951 RegionSelection::iterator tmp;
5956 boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion> ((*i)->region());
5958 if (ar && (ar->get_transients (positions) == 0)) {
5959 split_region_at_points ((*i)->region(), positions, true);
5966 _session->commit_reversible_command ();
5971 Editor::split_region_at_points (boost::shared_ptr<Region> r, AnalysisFeatureList& positions, bool can_ferret, bool select_new)
5973 bool use_rhythmic_rodent = false;
5975 boost::shared_ptr<Playlist> pl = r->playlist();
5977 list<boost::shared_ptr<Region> > new_regions;
5983 if (positions.empty()) {
5988 if (positions.size() > 20 && can_ferret) {
5989 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);
5990 MessageDialog msg (msgstr,
5993 Gtk::BUTTONS_OK_CANCEL);
5996 msg.add_button (_("Call for the Ferret!"), RESPONSE_APPLY);
5997 msg.set_secondary_text (_("Press OK to continue with this split operation\nor ask the Ferret dialog to tune the analysis"));
5999 msg.set_secondary_text (_("Press OK to continue with this split operation"));
6002 msg.set_title (_("Excessive split?"));
6005 int response = msg.run();
6011 case RESPONSE_APPLY:
6012 use_rhythmic_rodent = true;
6019 if (use_rhythmic_rodent) {
6020 show_rhythm_ferret ();
6024 AnalysisFeatureList::const_iterator x;
6026 pl->clear_changes ();
6027 pl->clear_owned_changes ();
6029 x = positions.begin();
6031 if (x == positions.end()) {
6036 pl->remove_region (r);
6040 while (x != positions.end()) {
6042 /* deal with positons that are out of scope of present region bounds */
6043 if (*x <= 0 || *x > r->length()) {
6048 /* file start = original start + how far we from the initial position ?
6051 framepos_t file_start = r->start() + pos;
6053 /* length = next position - current position
6056 framepos_t len = (*x) - pos;
6058 /* XXX we do we really want to allow even single-sample regions?
6059 shouldn't we have some kind of lower limit on region size?
6068 if (RegionFactory::region_name (new_name, r->name())) {
6072 /* do NOT announce new regions 1 by one, just wait till they are all done */
6076 plist.add (ARDOUR::Properties::start, file_start);
6077 plist.add (ARDOUR::Properties::length, len);
6078 plist.add (ARDOUR::Properties::name, new_name);
6079 plist.add (ARDOUR::Properties::layer, 0);
6081 boost::shared_ptr<Region> nr = RegionFactory::create (r->sources(), plist, false);
6082 /* because we set annouce to false, manually add the new region to the
6085 RegionFactory::map_add (nr);
6087 pl->add_region (nr, r->position() + pos);
6090 new_regions.push_front(nr);
6099 RegionFactory::region_name (new_name, r->name());
6101 /* Add the final region */
6104 plist.add (ARDOUR::Properties::start, r->start() + pos);
6105 plist.add (ARDOUR::Properties::length, r->last_frame() - (r->position() + pos) + 1);
6106 plist.add (ARDOUR::Properties::name, new_name);
6107 plist.add (ARDOUR::Properties::layer, 0);
6109 boost::shared_ptr<Region> nr = RegionFactory::create (r->sources(), plist, false);
6110 /* because we set annouce to false, manually add the new region to the
6113 RegionFactory::map_add (nr);
6114 pl->add_region (nr, r->position() + pos);
6117 new_regions.push_front(nr);
6122 /* We might have removed regions, which alters other regions' layering_index,
6123 so we need to do a recursive diff here.
6125 vector<Command*> cmds;
6127 _session->add_commands (cmds);
6129 _session->add_command (new StatefulDiffCommand (pl));
6133 for (list<boost::shared_ptr<Region> >::iterator i = new_regions.begin(); i != new_regions.end(); ++i){
6134 set_selected_regionview_from_region_list ((*i), Selection::Add);
6140 Editor::place_transient()
6146 RegionSelection rs = get_regions_from_selection_and_edit_point ();
6152 framepos_t where = get_preferred_edit_position();
6154 _session->begin_reversible_command (_("place transient"));
6156 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6157 framepos_t position = (*r)->region()->position();
6158 (*r)->region()->add_transient(where - position);
6161 _session->commit_reversible_command ();
6165 Editor::remove_transient(ArdourCanvas::Item* item)
6171 ArdourCanvas::Line* _line = reinterpret_cast<ArdourCanvas::Line*> (item);
6174 AudioRegionView* _arv = reinterpret_cast<AudioRegionView*> (item->get_data ("regionview"));
6175 _arv->remove_transient (*(float*) _line->get_data ("position"));
6179 Editor::snap_regions_to_grid ()
6181 list <boost::shared_ptr<Playlist > > used_playlists;
6183 RegionSelection rs = get_regions_from_selection_and_entered ();
6185 if (!_session || rs.empty()) {
6189 _session->begin_reversible_command (_("snap regions to grid"));
6191 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6193 boost::shared_ptr<Playlist> pl = (*r)->region()->playlist();
6195 if (!pl->frozen()) {
6196 /* we haven't seen this playlist before */
6198 /* remember used playlists so we can thaw them later */
6199 used_playlists.push_back(pl);
6203 framepos_t start_frame = (*r)->region()->first_frame ();
6204 snap_to (start_frame);
6205 (*r)->region()->set_position (start_frame);
6208 while (used_playlists.size() > 0) {
6209 list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
6211 used_playlists.pop_front();
6214 _session->commit_reversible_command ();
6218 Editor::close_region_gaps ()
6220 list <boost::shared_ptr<Playlist > > used_playlists;
6222 RegionSelection rs = get_regions_from_selection_and_entered ();
6224 if (!_session || rs.empty()) {
6228 Dialog dialog (_("Close Region Gaps"));
6231 table.set_spacings (12);
6232 table.set_border_width (12);
6233 Label* l = manage (left_aligned_label (_("Crossfade length")));
6234 table.attach (*l, 0, 1, 0, 1);
6236 SpinButton spin_crossfade (1, 0);
6237 spin_crossfade.set_range (0, 15);
6238 spin_crossfade.set_increments (1, 1);
6239 spin_crossfade.set_value (5);
6240 table.attach (spin_crossfade, 1, 2, 0, 1);
6242 table.attach (*manage (new Label (_("ms"))), 2, 3, 0, 1);
6244 l = manage (left_aligned_label (_("Pull-back length")));
6245 table.attach (*l, 0, 1, 1, 2);
6247 SpinButton spin_pullback (1, 0);
6248 spin_pullback.set_range (0, 100);
6249 spin_pullback.set_increments (1, 1);
6250 spin_pullback.set_value(30);
6251 table.attach (spin_pullback, 1, 2, 1, 2);
6253 table.attach (*manage (new Label (_("ms"))), 2, 3, 1, 2);
6255 dialog.get_vbox()->pack_start (table);
6256 dialog.add_button (Stock::CANCEL, RESPONSE_CANCEL);
6257 dialog.add_button (_("Ok"), RESPONSE_ACCEPT);
6260 if (dialog.run () == RESPONSE_CANCEL) {
6264 framepos_t crossfade_len = spin_crossfade.get_value();
6265 framepos_t pull_back_frames = spin_pullback.get_value();
6267 crossfade_len = lrintf (crossfade_len * _session->frame_rate()/1000);
6268 pull_back_frames = lrintf (pull_back_frames * _session->frame_rate()/1000);
6270 /* Iterate over the region list and make adjacent regions overlap by crossfade_len_ms */
6272 _session->begin_reversible_command (_("close region gaps"));
6275 boost::shared_ptr<Region> last_region;
6277 rs.sort_by_position_and_track();
6279 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6281 boost::shared_ptr<Playlist> pl = (*r)->region()->playlist();
6283 if (!pl->frozen()) {
6284 /* we haven't seen this playlist before */
6286 /* remember used playlists so we can thaw them later */
6287 used_playlists.push_back(pl);
6291 framepos_t position = (*r)->region()->position();
6293 if (idx == 0 || position < last_region->position()){
6294 last_region = (*r)->region();
6299 (*r)->region()->trim_front( (position - pull_back_frames));
6300 last_region->trim_end( (position - pull_back_frames + crossfade_len));
6302 last_region = (*r)->region();
6307 while (used_playlists.size() > 0) {
6308 list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
6310 used_playlists.pop_front();
6313 _session->commit_reversible_command ();
6317 Editor::tab_to_transient (bool forward)
6319 AnalysisFeatureList positions;
6321 RegionSelection rs = get_regions_from_selection_and_entered ();
6327 framepos_t pos = _session->audible_frame ();
6329 if (!selection->tracks.empty()) {
6331 /* don't waste time searching for transients in duplicate playlists.
6334 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
6336 for (TrackViewList::iterator t = ts.begin(); t != ts.end(); ++t) {
6338 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*t);
6341 boost::shared_ptr<Track> tr = rtv->track();
6343 boost::shared_ptr<Playlist> pl = tr->playlist ();
6345 framepos_t result = pl->find_next_transient (pos, forward ? 1 : -1);
6348 positions.push_back (result);
6361 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6362 (*r)->region()->get_transients (positions);
6366 TransientDetector::cleanup_transients (positions, _session->frame_rate(), 3.0);
6369 AnalysisFeatureList::iterator x;
6371 for (x = positions.begin(); x != positions.end(); ++x) {
6377 if (x != positions.end ()) {
6378 _session->request_locate (*x);
6382 AnalysisFeatureList::reverse_iterator x;
6384 for (x = positions.rbegin(); x != positions.rend(); ++x) {
6390 if (x != positions.rend ()) {
6391 _session->request_locate (*x);
6397 Editor::playhead_forward_to_grid ()
6403 framepos_t pos = playhead_cursor->current_frame ();
6404 if (pos < max_framepos - 1) {
6406 snap_to_internal (pos, 1, false);
6407 _session->request_locate (pos);
6413 Editor::playhead_backward_to_grid ()
6419 framepos_t pos = playhead_cursor->current_frame ();
6422 snap_to_internal (pos, -1, false);
6423 _session->request_locate (pos);
6428 Editor::set_track_height (Height h)
6430 TrackSelection& ts (selection->tracks);
6432 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
6433 (*x)->set_height_enum (h);
6438 Editor::toggle_tracks_active ()
6440 TrackSelection& ts (selection->tracks);
6442 bool target = false;
6448 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
6449 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*x);
6453 target = !rtv->_route->active();
6456 rtv->_route->set_active (target, this);
6462 Editor::remove_tracks ()
6464 TrackSelection& ts (selection->tracks);
6470 vector<string> choices;
6474 const char* trackstr;
6476 vector<boost::shared_ptr<Route> > routes;
6477 bool special_bus = false;
6479 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
6480 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*x);
6484 if (rtv->is_track()) {
6489 routes.push_back (rtv->_route);
6491 if (rtv->route()->is_master() || rtv->route()->is_monitor()) {
6496 if (special_bus && !Config->get_allow_special_bus_removal()) {
6497 MessageDialog msg (_("That would be bad news ...."),
6501 msg.set_secondary_text (string_compose (_(
6502 "Removing the master or monitor bus is such a bad idea\n\
6503 that %1 is not going to allow it.\n\
6505 If you really want to do this sort of thing\n\
6506 edit your ardour.rc file to set the\n\
6507 \"allow-special-bus-removal\" option to be \"yes\""), PROGRAM_NAME));
6514 if (ntracks + nbusses == 0) {
6519 trackstr = _("tracks");
6521 trackstr = _("track");
6525 busstr = _("busses");
6532 prompt = string_compose (_("Do you really want to remove %1 %2 and %3 %4?\n"
6533 "(You may also lose the playlists associated with the %2)\n\n"
6534 "This action cannot be undone, and the session file will be overwritten!"),
6535 ntracks, trackstr, nbusses, busstr);
6537 prompt = string_compose (_("Do you really want to remove %1 %2?\n"
6538 "(You may also lose the playlists associated with the %2)\n\n"
6539 "This action cannot be undone, and the session file will be overwritten!"),
6542 } else if (nbusses) {
6543 prompt = string_compose (_("Do you really want to remove %1 %2?\n\n"
6544 "This action cannot be undon, and the session file will be overwritten"),
6548 choices.push_back (_("No, do nothing."));
6549 if (ntracks + nbusses > 1) {
6550 choices.push_back (_("Yes, remove them."));
6552 choices.push_back (_("Yes, remove it."));
6557 title = string_compose (_("Remove %1"), trackstr);
6559 title = string_compose (_("Remove %1"), busstr);
6562 Choice prompter (title, prompt, choices);
6564 if (prompter.run () != 1) {
6568 for (vector<boost::shared_ptr<Route> >::iterator x = routes.begin(); x != routes.end(); ++x) {
6569 _session->remove_route (*x);
6574 Editor::do_insert_time ()
6576 if (selection->tracks.empty()) {
6580 InsertTimeDialog d (*this);
6581 int response = d.run ();
6583 if (response != RESPONSE_OK) {
6587 if (d.distance() == 0) {
6591 InsertTimeOption opt = d.intersected_region_action ();
6594 get_preferred_edit_position(),
6600 d.move_glued_markers(),
6601 d.move_locked_markers(),
6607 Editor::insert_time (
6608 framepos_t pos, framecnt_t frames, InsertTimeOption opt,
6609 bool all_playlists, bool ignore_music_glue, bool markers_too, bool glued_markers_too, bool locked_markers_too, bool tempo_too
6612 bool commit = false;
6614 if (Config->get_edit_mode() == Lock) {
6618 begin_reversible_command (_("insert time"));
6620 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
6622 for (TrackViewList::iterator x = ts.begin(); x != ts.end(); ++x) {
6626 /* don't operate on any playlist more than once, which could
6627 * happen if "all playlists" is enabled, but there is more
6628 * than 1 track using playlists "from" a given track.
6631 set<boost::shared_ptr<Playlist> > pl;
6633 if (all_playlists) {
6634 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*x);
6636 vector<boost::shared_ptr<Playlist> > all = _session->playlists->playlists_for_track (rtav->track ());
6637 for (vector<boost::shared_ptr<Playlist> >::iterator p = all.begin(); p != all.end(); ++p) {
6642 if ((*x)->playlist ()) {
6643 pl.insert ((*x)->playlist ());
6647 for (set<boost::shared_ptr<Playlist> >::iterator i = pl.begin(); i != pl.end(); ++i) {
6649 (*i)->clear_changes ();
6650 (*i)->clear_owned_changes ();
6652 if (opt == SplitIntersected) {
6656 (*i)->shift (pos, frames, (opt == MoveIntersected), ignore_music_glue);
6658 vector<Command*> cmds;
6660 _session->add_commands (cmds);
6662 _session->add_command (new StatefulDiffCommand (*i));
6667 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*x);
6669 rtav->route ()->shift (pos, frames);
6677 XMLNode& before (_session->locations()->get_state());
6678 Locations::LocationList copy (_session->locations()->list());
6680 for (Locations::LocationList::iterator i = copy.begin(); i != copy.end(); ++i) {
6682 Locations::LocationList::const_iterator tmp;
6684 bool const was_locked = (*i)->locked ();
6685 if (locked_markers_too) {
6689 if ((*i)->position_lock_style() == AudioTime || glued_markers_too) {
6691 if ((*i)->start() >= pos) {
6692 (*i)->set_start ((*i)->start() + frames);
6693 if (!(*i)->is_mark()) {
6694 (*i)->set_end ((*i)->end() + frames);
6707 XMLNode& after (_session->locations()->get_state());
6708 _session->add_command (new MementoCommand<Locations>(*_session->locations(), &before, &after));
6713 _session->tempo_map().insert_time (pos, frames);
6717 commit_reversible_command ();
6722 Editor::fit_selected_tracks ()
6724 if (!selection->tracks.empty()) {
6725 fit_tracks (selection->tracks);
6729 /* no selected tracks - use tracks with selected regions */
6731 if (!selection->regions.empty()) {
6732 for (RegionSelection::iterator r = selection->regions.begin(); r != selection->regions.end(); ++r) {
6733 tvl.push_back (&(*r)->get_time_axis_view ());
6739 } else if (internal_editing()) {
6740 /* no selected tracks, or regions, but in internal edit mode, so follow the mouse and use
6743 if (entered_track) {
6744 tvl.push_back (entered_track);
6752 Editor::fit_tracks (TrackViewList & tracks)
6754 if (tracks.empty()) {
6758 uint32_t child_heights = 0;
6759 int visible_tracks = 0;
6761 for (TrackSelection::iterator t = tracks.begin(); t != tracks.end(); ++t) {
6763 if (!(*t)->marked_for_display()) {
6767 child_heights += (*t)->effective_height() - (*t)->current_height();
6771 /* compute the per-track height from:
6773 total canvas visible height -
6774 height that will be taken by visible children of selected
6775 tracks - height of the ruler/hscroll area
6777 uint32_t h = (uint32_t) floor ((_visible_canvas_height - (child_heights + _trackview_group->canvas_origin().y)) / visible_tracks);
6778 double first_y_pos = DBL_MAX;
6780 if (h < TimeAxisView::preset_height (HeightSmall)) {
6781 MessageDialog msg (*this, _("There are too many tracks to fit in the current window"));
6782 /* too small to be displayed */
6786 undo_visual_stack.push_back (current_visual_state (true));
6787 no_save_visual = true;
6789 /* build a list of all tracks, including children */
6792 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
6794 TimeAxisView::Children c = (*i)->get_child_list ();
6795 for (TimeAxisView::Children::iterator j = c.begin(); j != c.end(); ++j) {
6796 all.push_back (j->get());
6800 /* operate on all tracks, hide unselected ones that are in the middle of selected ones */
6802 bool within_selected = false;
6804 for (TrackViewList::iterator t = all.begin(); t != all.end(); ++t) {
6806 TrackViewList::iterator next;
6811 if ((*t)->marked_for_display ()) {
6812 if (tracks.contains (*t)) {
6813 (*t)->set_height (h);
6814 first_y_pos = std::min ((*t)->y_position (), first_y_pos);
6815 within_selected = true;
6816 } else if (within_selected) {
6817 hide_track_in_display (*t);
6823 set the controls_layout height now, because waiting for its size
6824 request signal handler will cause the vertical adjustment setting to fail
6827 controls_layout.property_height () = _full_canvas_height;
6828 vertical_adjustment.set_value (first_y_pos);
6830 redo_visual_stack.push_back (current_visual_state (true));
6834 Editor::save_visual_state (uint32_t n)
6836 while (visual_states.size() <= n) {
6837 visual_states.push_back (0);
6840 if (visual_states[n] != 0) {
6841 delete visual_states[n];
6844 visual_states[n] = current_visual_state (true);
6849 Editor::goto_visual_state (uint32_t n)
6851 if (visual_states.size() <= n) {
6855 if (visual_states[n] == 0) {
6859 use_visual_state (*visual_states[n]);
6863 Editor::start_visual_state_op (uint32_t n)
6865 save_visual_state (n);
6867 PopUp* pup = new PopUp (WIN_POS_MOUSE, 1000, true);
6869 snprintf (buf, sizeof (buf), _("Saved view %u"), n+1);
6870 pup->set_text (buf);
6875 Editor::cancel_visual_state_op (uint32_t n)
6877 goto_visual_state (n);
6881 Editor::toggle_region_mute ()
6883 if (_ignore_region_action) {
6887 RegionSelection rs = get_regions_from_selection_and_entered ();
6893 if (rs.size() > 1) {
6894 begin_reversible_command (_("mute regions"));
6896 begin_reversible_command (_("mute region"));
6899 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
6901 (*i)->region()->playlist()->clear_changes ();
6902 (*i)->region()->set_muted (!(*i)->region()->muted ());
6903 _session->add_command (new StatefulDiffCommand ((*i)->region()->playlist()));
6907 commit_reversible_command ();
6911 Editor::combine_regions ()
6913 /* foreach track with selected regions, take all selected regions
6914 and join them into a new region containing the subregions (as a
6918 typedef set<RouteTimeAxisView*> RTVS;
6921 if (selection->regions.empty()) {
6925 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
6926 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(&(*i)->get_time_axis_view());
6929 tracks.insert (rtv);
6933 begin_reversible_command (_("combine regions"));
6935 vector<RegionView*> new_selection;
6937 for (RTVS::iterator i = tracks.begin(); i != tracks.end(); ++i) {
6940 if ((rv = (*i)->combine_regions ()) != 0) {
6941 new_selection.push_back (rv);
6945 selection->clear_regions ();
6946 for (vector<RegionView*>::iterator i = new_selection.begin(); i != new_selection.end(); ++i) {
6947 selection->add (*i);
6950 commit_reversible_command ();
6954 Editor::uncombine_regions ()
6956 typedef set<RouteTimeAxisView*> RTVS;
6959 if (selection->regions.empty()) {
6963 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
6964 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(&(*i)->get_time_axis_view());
6967 tracks.insert (rtv);
6971 begin_reversible_command (_("uncombine regions"));
6973 for (RTVS::iterator i = tracks.begin(); i != tracks.end(); ++i) {
6974 (*i)->uncombine_regions ();
6977 commit_reversible_command ();
6981 Editor::toggle_midi_input_active (bool flip_others)
6984 boost::shared_ptr<RouteList> rl (new RouteList);
6986 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
6987 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
6993 boost::shared_ptr<MidiTrack> mt = rtav->midi_track();
6996 rl->push_back (rtav->route());
6997 onoff = !mt->input_active();
7001 _session->set_exclusive_input_active (rl, onoff, flip_others);
7008 lock_dialog = new Gtk::Dialog (string_compose (_("%1: Locked"), PROGRAM_NAME), true);
7010 Gtk::Image* padlock = manage (new Gtk::Image (ARDOUR_UI_UTILS::get_icon ("padlock_closed")));
7011 lock_dialog->get_vbox()->pack_start (*padlock);
7013 ArdourButton* b = manage (new ArdourButton);
7014 b->set_name ("lock button");
7015 b->set_markup (string_compose ("<span size=\"large\" weight=\"bold\">%1</span>", _("Click to unlock")));
7016 b->signal_clicked.connect (sigc::mem_fun (*this, &Editor::unlock));
7017 lock_dialog->get_vbox()->pack_start (*b);
7019 lock_dialog->get_vbox()->show_all ();
7020 lock_dialog->set_size_request (200, 200);
7024 /* The global menu bar continues to be accessible to applications
7025 with modal dialogs, which means that we need to desensitize
7026 all items in the menu bar. Since those items are really just
7027 proxies for actions, that means disabling all actions.
7029 ActionManager::disable_all_actions ();
7031 lock_dialog->present ();
7037 lock_dialog->hide ();
7040 ActionManager::pop_action_state ();
7043 if (ARDOUR_UI::config()->get_lock_gui_after_seconds()) {
7044 start_lock_event_timing ();