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 DisplaySuspender ds;
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);
1422 Editor::tav_zoom_smooth (bool coarser, bool force_all)
1424 DisplaySuspender ds;
1428 if (selection->tracks.empty() || force_all) {
1431 ts = &selection->tracks;
1434 for (TrackViewList::iterator i = ts->begin(); i != ts->end(); ++i) {
1435 TimeAxisView *tv = (static_cast<TimeAxisView*>(*i));
1436 uint32_t h = tv->current_height ();
1441 if (h >= TimeAxisView::preset_height (HeightSmall)) {
1446 tv->set_height (h + 5);
1452 Editor::clamp_samples_per_pixel (framecnt_t& fpp) const
1454 bool clamped = false;
1464 sr = _session->frame_rate ();
1469 const framecnt_t three_days = 3 * 24 * 60 * 60 * sr;
1470 const framecnt_t lots_of_pixels = 4000;
1472 /* if the zoom level is greater than what you'd get trying to display 3
1473 * days of audio on a really big screen, scale it down.
1476 if (fpp * lots_of_pixels > three_days) {
1477 fpp = three_days / _track_canvas->width();
1485 Editor::temporal_zoom_step (bool coarser)
1487 ENSURE_GUI_THREAD (*this, &Editor::temporal_zoom_step, coarser)
1489 framecnt_t nspp = samples_per_pixel;
1497 temporal_zoom (nspp);
1501 Editor::temporal_zoom (framecnt_t fpp)
1507 framepos_t current_page = current_page_samples();
1508 framepos_t current_leftmost = leftmost_frame;
1509 framepos_t current_rightmost;
1510 framepos_t current_center;
1511 framepos_t new_page_size;
1512 framepos_t half_page_size;
1513 framepos_t leftmost_after_zoom = 0;
1515 bool in_track_canvas;
1519 clamp_samples_per_pixel (fpp);
1520 if (fpp == samples_per_pixel) {
1524 // Imposing an arbitrary limit to zoom out as too much zoom out produces
1525 // segfaults for lack of memory. If somebody decides this is not high enough I
1526 // believe it can be raisen to higher values but some limit must be in place.
1528 // This constant represents 1 day @ 48kHz on a 1600 pixel wide display
1529 // all of which is used for the editor track displays. The whole day
1530 // would be 4147200000 samples, so 2592000 samples per pixel.
1532 nfpp = min (fpp, (framecnt_t) 2592000);
1533 nfpp = max ((framecnt_t) 1, fpp);
1535 new_page_size = (framepos_t) floor (_visible_canvas_width * nfpp);
1536 half_page_size = new_page_size / 2;
1538 switch (zoom_focus) {
1540 leftmost_after_zoom = current_leftmost;
1543 case ZoomFocusRight:
1544 current_rightmost = leftmost_frame + current_page;
1545 if (current_rightmost < new_page_size) {
1546 leftmost_after_zoom = 0;
1548 leftmost_after_zoom = current_rightmost - new_page_size;
1552 case ZoomFocusCenter:
1553 current_center = current_leftmost + (current_page/2);
1554 if (current_center < half_page_size) {
1555 leftmost_after_zoom = 0;
1557 leftmost_after_zoom = current_center - half_page_size;
1561 case ZoomFocusPlayhead:
1562 /* centre playhead */
1563 l = playhead_cursor->current_frame () - (new_page_size * 0.5);
1566 leftmost_after_zoom = 0;
1567 } else if (l > max_framepos) {
1568 leftmost_after_zoom = max_framepos - new_page_size;
1570 leftmost_after_zoom = (framepos_t) l;
1574 case ZoomFocusMouse:
1575 /* try to keep the mouse over the same point in the display */
1577 if (!mouse_frame (where, in_track_canvas)) {
1578 /* use playhead instead */
1579 where = playhead_cursor->current_frame ();
1581 if (where < half_page_size) {
1582 leftmost_after_zoom = 0;
1584 leftmost_after_zoom = where - half_page_size;
1589 l = - ((new_page_size * ((where - current_leftmost)/(double)current_page)) - where);
1592 leftmost_after_zoom = 0;
1593 } else if (l > max_framepos) {
1594 leftmost_after_zoom = max_framepos - new_page_size;
1596 leftmost_after_zoom = (framepos_t) l;
1603 /* try to keep the edit point in the same place */
1604 where = get_preferred_edit_position ();
1608 double l = - ((new_page_size * ((where - current_leftmost)/(double)current_page)) - where);
1611 leftmost_after_zoom = 0;
1612 } else if (l > max_framepos) {
1613 leftmost_after_zoom = max_framepos - new_page_size;
1615 leftmost_after_zoom = (framepos_t) l;
1619 /* edit point not defined */
1626 // leftmost_after_zoom = min (leftmost_after_zoom, _session->current_end_frame());
1628 reposition_and_zoom (leftmost_after_zoom, nfpp);
1632 Editor::temporal_zoom_region (bool both_axes)
1634 framepos_t start = max_framepos;
1636 set<TimeAxisView*> tracks;
1638 RegionSelection rs = get_regions_from_selection_and_entered ();
1644 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
1646 if ((*i)->region()->position() < start) {
1647 start = (*i)->region()->position();
1650 if ((*i)->region()->last_frame() + 1 > end) {
1651 end = (*i)->region()->last_frame() + 1;
1654 tracks.insert (&((*i)->get_time_axis_view()));
1657 /* now comes an "interesting" hack ... make sure we leave a little space
1658 at each end of the editor so that the zoom doesn't fit the region
1659 precisely to the screen.
1662 GdkScreen* screen = gdk_screen_get_default ();
1663 gint pixwidth = gdk_screen_get_width (screen);
1664 gint mmwidth = gdk_screen_get_width_mm (screen);
1665 double pix_per_mm = (double) pixwidth/ (double) mmwidth;
1666 double one_centimeter_in_pixels = pix_per_mm * 10.0;
1668 if ((start == 0 && end == 0) || end < start) {
1672 framepos_t range = end - start;
1673 double new_fpp = (double) range / (double) _visible_canvas_width;
1674 framepos_t extra_samples = (framepos_t) floor (one_centimeter_in_pixels * new_fpp);
1676 if (start > extra_samples) {
1677 start -= extra_samples;
1682 if (max_framepos - extra_samples > end) {
1683 end += extra_samples;
1688 /* if we're zooming on both axes we need to save track heights etc.
1691 undo_visual_stack.push_back (current_visual_state (both_axes));
1693 PBD::Unwinder<bool> nsv (no_save_visual, true);
1695 temporal_zoom_by_frame (start, end);
1698 uint32_t per_track_height = (uint32_t) floor ((_visible_canvas_height - 10.0) / tracks.size());
1700 /* set visible track heights appropriately */
1702 for (set<TimeAxisView*>::iterator t = tracks.begin(); t != tracks.end(); ++t) {
1703 (*t)->set_height (per_track_height);
1706 /* hide irrelevant tracks */
1708 DisplaySuspender ds;
1710 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1711 if (find (tracks.begin(), tracks.end(), (*i)) == tracks.end()) {
1712 hide_track_in_display (*i);
1716 vertical_adjustment.set_value (0.0);
1719 redo_visual_stack.push_back (current_visual_state (both_axes));
1723 Editor::zoom_to_region (bool both_axes)
1725 temporal_zoom_region (both_axes);
1729 Editor::temporal_zoom_selection ()
1731 if (!selection) return;
1733 if (selection->time.empty()) {
1737 framepos_t start = selection->time[clicked_selection].start;
1738 framepos_t end = selection->time[clicked_selection].end;
1740 temporal_zoom_by_frame (start, end);
1744 Editor::temporal_zoom_session ()
1746 ENSURE_GUI_THREAD (*this, &Editor::temporal_zoom_session)
1749 framecnt_t const l = _session->current_end_frame() - _session->current_start_frame();
1750 double s = _session->current_start_frame() - l * 0.01;
1754 framecnt_t const e = _session->current_end_frame() + l * 0.01;
1755 temporal_zoom_by_frame (framecnt_t (s), e);
1760 Editor::temporal_zoom_by_frame (framepos_t start, framepos_t end)
1762 if (!_session) return;
1764 if ((start == 0 && end == 0) || end < start) {
1768 framepos_t range = end - start;
1770 double const new_fpp = (double) range / (double) _visible_canvas_width;
1772 framepos_t new_page = (framepos_t) floor (_visible_canvas_width * new_fpp);
1773 framepos_t middle = (framepos_t) floor ((double) start + ((double) range / 2.0f));
1774 framepos_t new_leftmost = (framepos_t) floor ((double) middle - ((double) new_page / 2.0f));
1776 if (new_leftmost > middle) {
1780 if (new_leftmost < 0) {
1784 reposition_and_zoom (new_leftmost, new_fpp);
1788 Editor::temporal_zoom_to_frame (bool coarser, framepos_t frame)
1794 framecnt_t range_before = frame - leftmost_frame;
1798 if (samples_per_pixel <= 1) {
1801 new_spp = samples_per_pixel + (samples_per_pixel/2);
1803 range_before += range_before/2;
1805 if (samples_per_pixel >= 1) {
1806 new_spp = samples_per_pixel - (samples_per_pixel/2);
1808 /* could bail out here since we cannot zoom any finer,
1809 but leave that to the clamp_samples_per_pixel() and
1812 new_spp = samples_per_pixel;
1815 range_before -= range_before/2;
1818 clamp_samples_per_pixel (new_spp);
1820 if (new_spp == samples_per_pixel) {
1824 /* zoom focus is automatically taken as @param frame when this
1828 framepos_t new_leftmost = frame - (framepos_t)range_before;
1830 if (new_leftmost > frame) {
1834 if (new_leftmost < 0) {
1838 reposition_and_zoom (new_leftmost, new_spp);
1843 Editor::choose_new_marker_name(string &name) {
1845 if (!Config->get_name_new_markers()) {
1846 /* don't prompt user for a new name */
1850 ArdourPrompter dialog (true);
1852 dialog.set_prompt (_("New Name:"));
1854 dialog.set_title (_("New Location Marker"));
1856 dialog.set_name ("MarkNameWindow");
1857 dialog.set_size_request (250, -1);
1858 dialog.set_position (Gtk::WIN_POS_MOUSE);
1860 dialog.add_button (Stock::OK, RESPONSE_ACCEPT);
1861 dialog.set_initial_text (name);
1865 switch (dialog.run ()) {
1866 case RESPONSE_ACCEPT:
1872 dialog.get_result(name);
1879 Editor::add_location_from_selection ()
1883 if (selection->time.empty()) {
1887 if (_session == 0 || clicked_axisview == 0) {
1891 framepos_t start = selection->time[clicked_selection].start;
1892 framepos_t end = selection->time[clicked_selection].end;
1894 _session->locations()->next_available_name(rangename,"selection");
1895 Location *location = new Location (*_session, start, end, rangename, Location::IsRangeMarker);
1897 _session->begin_reversible_command (_("add marker"));
1898 XMLNode &before = _session->locations()->get_state();
1899 _session->locations()->add (location, true);
1900 XMLNode &after = _session->locations()->get_state();
1901 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
1902 _session->commit_reversible_command ();
1906 Editor::add_location_mark (framepos_t where)
1910 select_new_marker = true;
1912 _session->locations()->next_available_name(markername,"mark");
1913 if (!choose_new_marker_name(markername)) {
1916 Location *location = new Location (*_session, where, where, markername, Location::IsMark);
1917 _session->begin_reversible_command (_("add marker"));
1918 XMLNode &before = _session->locations()->get_state();
1919 _session->locations()->add (location, true);
1920 XMLNode &after = _session->locations()->get_state();
1921 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
1922 _session->commit_reversible_command ();
1926 Editor::add_location_from_playhead_cursor ()
1928 add_location_mark (_session->audible_frame());
1931 /** Add a range marker around each selected region */
1933 Editor::add_locations_from_region ()
1935 RegionSelection rs = get_regions_from_selection_and_entered ();
1941 _session->begin_reversible_command (selection->regions.size () > 1 ? _("add markers") : _("add marker"));
1942 XMLNode &before = _session->locations()->get_state();
1944 for (RegionSelection::iterator i = rs.begin (); i != rs.end (); ++i) {
1946 boost::shared_ptr<Region> region = (*i)->region ();
1948 Location *location = new Location (*_session, region->position(), region->last_frame(), region->name(), Location::IsRangeMarker);
1950 _session->locations()->add (location, true);
1953 XMLNode &after = _session->locations()->get_state();
1954 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
1955 _session->commit_reversible_command ();
1958 /** Add a single range marker around all selected regions */
1960 Editor::add_location_from_region ()
1962 RegionSelection rs = get_regions_from_selection_and_entered ();
1968 _session->begin_reversible_command (_("add marker"));
1969 XMLNode &before = _session->locations()->get_state();
1973 if (rs.size() > 1) {
1974 _session->locations()->next_available_name(markername, "regions");
1976 RegionView* rv = *(rs.begin());
1977 boost::shared_ptr<Region> region = rv->region();
1978 markername = region->name();
1981 if (!choose_new_marker_name(markername)) {
1985 // single range spanning all selected
1986 Location *location = new Location (*_session, selection->regions.start(), selection->regions.end_frame(), markername, Location::IsRangeMarker);
1987 _session->locations()->add (location, true);
1989 XMLNode &after = _session->locations()->get_state();
1990 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
1991 _session->commit_reversible_command ();
1997 Editor::jump_forward_to_mark ()
2003 framepos_t pos = _session->locations()->first_mark_after (playhead_cursor->current_frame());
2009 _session->request_locate (pos, _session->transport_rolling());
2013 Editor::jump_backward_to_mark ()
2019 framepos_t pos = _session->locations()->first_mark_before (playhead_cursor->current_frame());
2025 _session->request_locate (pos, _session->transport_rolling());
2031 framepos_t const pos = _session->audible_frame ();
2034 _session->locations()->next_available_name (markername, "mark");
2036 if (!choose_new_marker_name (markername)) {
2040 _session->locations()->add (new Location (*_session, pos, 0, markername, Location::IsMark), true);
2044 Editor::clear_markers ()
2047 _session->begin_reversible_command (_("clear markers"));
2048 XMLNode &before = _session->locations()->get_state();
2049 _session->locations()->clear_markers ();
2050 XMLNode &after = _session->locations()->get_state();
2051 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2052 _session->commit_reversible_command ();
2057 Editor::clear_ranges ()
2060 _session->begin_reversible_command (_("clear ranges"));
2061 XMLNode &before = _session->locations()->get_state();
2063 Location * looploc = _session->locations()->auto_loop_location();
2064 Location * punchloc = _session->locations()->auto_punch_location();
2065 Location * sessionloc = _session->locations()->session_range_location();
2067 _session->locations()->clear_ranges ();
2069 if (looploc) _session->locations()->add (looploc);
2070 if (punchloc) _session->locations()->add (punchloc);
2071 if (sessionloc) _session->locations()->add (sessionloc);
2073 XMLNode &after = _session->locations()->get_state();
2074 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2075 _session->commit_reversible_command ();
2080 Editor::clear_locations ()
2082 _session->begin_reversible_command (_("clear locations"));
2083 XMLNode &before = _session->locations()->get_state();
2084 _session->locations()->clear ();
2085 XMLNode &after = _session->locations()->get_state();
2086 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2087 _session->commit_reversible_command ();
2088 _session->locations()->clear ();
2092 Editor::unhide_markers ()
2094 for (LocationMarkerMap::iterator i = location_markers.begin(); i != location_markers.end(); ++i) {
2095 Location *l = (*i).first;
2096 if (l->is_hidden() && l->is_mark()) {
2097 l->set_hidden(false, this);
2103 Editor::unhide_ranges ()
2105 for (LocationMarkerMap::iterator i = location_markers.begin(); i != location_markers.end(); ++i) {
2106 Location *l = (*i).first;
2107 if (l->is_hidden() && l->is_range_marker()) {
2108 l->set_hidden(false, this);
2113 /* INSERT/REPLACE */
2116 Editor::insert_region_list_selection (float times)
2118 RouteTimeAxisView *tv = 0;
2119 boost::shared_ptr<Playlist> playlist;
2121 if (clicked_routeview != 0) {
2122 tv = clicked_routeview;
2123 } else if (!selection->tracks.empty()) {
2124 if ((tv = dynamic_cast<RouteTimeAxisView*>(selection->tracks.front())) == 0) {
2127 } else if (entered_track != 0) {
2128 if ((tv = dynamic_cast<RouteTimeAxisView*>(entered_track)) == 0) {
2135 if ((playlist = tv->playlist()) == 0) {
2139 boost::shared_ptr<Region> region = _regions->get_single_selection ();
2144 begin_reversible_command (_("insert region"));
2145 playlist->clear_changes ();
2146 playlist->add_region ((RegionFactory::create (region, true)), get_preferred_edit_position(), times);
2147 if (Config->get_edit_mode() == Ripple)
2148 playlist->ripple (get_preferred_edit_position(), region->length() * times, boost::shared_ptr<Region>());
2150 _session->add_command(new StatefulDiffCommand (playlist));
2151 commit_reversible_command ();
2154 /* BUILT-IN EFFECTS */
2157 Editor::reverse_selection ()
2162 /* GAIN ENVELOPE EDITING */
2165 Editor::edit_envelope ()
2172 Editor::transition_to_rolling (bool fwd)
2178 if (_session->config.get_external_sync()) {
2179 switch (Config->get_sync_source()) {
2183 /* transport controlled by the master */
2188 if (_session->is_auditioning()) {
2189 _session->cancel_audition ();
2193 _session->request_transport_speed (fwd ? 1.0f : -1.0f);
2197 Editor::play_from_start ()
2199 _session->request_locate (_session->current_start_frame(), true);
2203 Editor::play_from_edit_point ()
2205 _session->request_locate (get_preferred_edit_position(), true);
2209 Editor::play_from_edit_point_and_return ()
2211 framepos_t start_frame;
2212 framepos_t return_frame;
2214 start_frame = get_preferred_edit_position (true);
2216 if (_session->transport_rolling()) {
2217 _session->request_locate (start_frame, false);
2221 /* don't reset the return frame if its already set */
2223 if ((return_frame = _session->requested_return_frame()) < 0) {
2224 return_frame = _session->audible_frame();
2227 if (start_frame >= 0) {
2228 _session->request_roll_at_and_return (start_frame, return_frame);
2233 Editor::play_selection ()
2235 if (selection->time.empty()) {
2239 _session->request_play_range (&selection->time, true);
2243 Editor::get_preroll ()
2245 return 1.0 /*Config->get_edit_preroll_seconds()*/ * _session->frame_rate();
2250 Editor::maybe_locate_with_edit_preroll ( framepos_t location )
2252 if ( _session->transport_rolling() || !Config->get_always_play_range() )
2255 location -= get_preroll();
2257 //don't try to locate before the beginning of time
2261 //if follow_playhead is on, keep the playhead on the screen
2262 if ( _follow_playhead )
2263 if ( location < leftmost_frame )
2264 location = leftmost_frame;
2266 _session->request_locate( location );
2270 Editor::play_with_preroll ()
2272 if (selection->time.empty()) {
2275 framepos_t preroll = get_preroll();
2277 framepos_t start = 0;
2278 if (selection->time[clicked_selection].start > preroll)
2279 start = selection->time[clicked_selection].start - preroll;
2281 framepos_t end = selection->time[clicked_selection].end + preroll;
2283 AudioRange ar (start, end, 0);
2284 list<AudioRange> lar;
2287 _session->request_play_range (&lar, true);
2292 Editor::play_location (Location& location)
2294 if (location.start() <= location.end()) {
2298 _session->request_bounded_roll (location.start(), location.end());
2302 Editor::loop_location (Location& location)
2304 if (location.start() <= location.end()) {
2310 if ((tll = transport_loop_location()) != 0) {
2311 tll->set (location.start(), location.end());
2313 // enable looping, reposition and start rolling
2314 _session->request_play_loop (true);
2315 _session->request_locate (tll->start(), true);
2320 Editor::do_layer_operation (LayerOperation op)
2322 if (selection->regions.empty ()) {
2326 bool const multiple = selection->regions.size() > 1;
2330 begin_reversible_command (_("raise regions"));
2332 begin_reversible_command (_("raise region"));
2338 begin_reversible_command (_("raise regions to top"));
2340 begin_reversible_command (_("raise region to top"));
2346 begin_reversible_command (_("lower regions"));
2348 begin_reversible_command (_("lower region"));
2354 begin_reversible_command (_("lower regions to bottom"));
2356 begin_reversible_command (_("lower region"));
2361 set<boost::shared_ptr<Playlist> > playlists = selection->regions.playlists ();
2362 for (set<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
2363 (*i)->clear_owned_changes ();
2366 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
2367 boost::shared_ptr<Region> r = (*i)->region ();
2379 r->lower_to_bottom ();
2383 for (set<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
2384 vector<Command*> cmds;
2386 _session->add_commands (cmds);
2389 commit_reversible_command ();
2393 Editor::raise_region ()
2395 do_layer_operation (Raise);
2399 Editor::raise_region_to_top ()
2401 do_layer_operation (RaiseToTop);
2405 Editor::lower_region ()
2407 do_layer_operation (Lower);
2411 Editor::lower_region_to_bottom ()
2413 do_layer_operation (LowerToBottom);
2416 /** Show the region editor for the selected regions */
2418 Editor::show_region_properties ()
2420 selection->foreach_regionview (&RegionView::show_region_editor);
2423 /** Show the midi list editor for the selected MIDI regions */
2425 Editor::show_midi_list_editor ()
2427 selection->foreach_midi_regionview (&MidiRegionView::show_list_editor);
2431 Editor::rename_region ()
2433 RegionSelection rs = get_regions_from_selection_and_entered ();
2439 ArdourDialog d (*this, _("Rename Region"), true, false);
2441 Label label (_("New name:"));
2444 hbox.set_spacing (6);
2445 hbox.pack_start (label, false, false);
2446 hbox.pack_start (entry, true, true);
2448 d.get_vbox()->set_border_width (12);
2449 d.get_vbox()->pack_start (hbox, false, false);
2451 d.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
2452 d.add_button(Gtk::Stock::OK, Gtk::RESPONSE_OK);
2454 d.set_size_request (300, -1);
2456 entry.set_text (rs.front()->region()->name());
2457 entry.select_region (0, -1);
2459 entry.signal_activate().connect (sigc::bind (sigc::mem_fun (d, &Dialog::response), RESPONSE_OK));
2465 int const ret = d.run();
2469 if (ret != RESPONSE_OK) {
2473 std::string str = entry.get_text();
2474 strip_whitespace_edges (str);
2476 rs.front()->region()->set_name (str);
2477 _regions->redisplay ();
2482 Editor::audition_playlist_region_via_route (boost::shared_ptr<Region> region, Route& route)
2484 if (_session->is_auditioning()) {
2485 _session->cancel_audition ();
2488 // note: some potential for creativity here, because region doesn't
2489 // have to belong to the playlist that Route is handling
2491 // bool was_soloed = route.soloed();
2493 route.set_solo (true, this);
2495 _session->request_bounded_roll (region->position(), region->position() + region->length());
2497 /* XXX how to unset the solo state ? */
2500 /** Start an audition of the first selected region */
2502 Editor::play_edit_range ()
2504 framepos_t start, end;
2506 if (get_edit_op_range (start, end)) {
2507 _session->request_bounded_roll (start, end);
2512 Editor::play_selected_region ()
2514 framepos_t start = max_framepos;
2517 RegionSelection rs = get_regions_from_selection_and_entered ();
2523 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
2524 if ((*i)->region()->position() < start) {
2525 start = (*i)->region()->position();
2527 if ((*i)->region()->last_frame() + 1 > end) {
2528 end = (*i)->region()->last_frame() + 1;
2532 _session->request_bounded_roll (start, end);
2536 Editor::audition_playlist_region_standalone (boost::shared_ptr<Region> region)
2538 _session->audition_region (region);
2542 Editor::region_from_selection ()
2544 if (clicked_axisview == 0) {
2548 if (selection->time.empty()) {
2552 framepos_t start = selection->time[clicked_selection].start;
2553 framepos_t end = selection->time[clicked_selection].end;
2555 TrackViewList tracks = get_tracks_for_range_action ();
2557 framepos_t selection_cnt = end - start + 1;
2559 for (TrackSelection::iterator i = tracks.begin(); i != tracks.end(); ++i) {
2560 boost::shared_ptr<Region> current;
2561 boost::shared_ptr<Playlist> pl;
2562 framepos_t internal_start;
2565 if ((pl = (*i)->playlist()) == 0) {
2569 if ((current = pl->top_region_at (start)) == 0) {
2573 internal_start = start - current->position();
2574 RegionFactory::region_name (new_name, current->name(), true);
2578 plist.add (ARDOUR::Properties::start, current->start() + internal_start);
2579 plist.add (ARDOUR::Properties::length, selection_cnt);
2580 plist.add (ARDOUR::Properties::name, new_name);
2581 plist.add (ARDOUR::Properties::layer, 0);
2583 boost::shared_ptr<Region> region (RegionFactory::create (current, plist));
2588 Editor::create_region_from_selection (vector<boost::shared_ptr<Region> >& new_regions)
2590 if (selection->time.empty() || selection->tracks.empty()) {
2594 framepos_t start = selection->time[clicked_selection].start;
2595 framepos_t end = selection->time[clicked_selection].end;
2597 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
2598 sort_track_selection (ts);
2600 for (TrackSelection::iterator i = ts.begin(); i != ts.end(); ++i) {
2601 boost::shared_ptr<Region> current;
2602 boost::shared_ptr<Playlist> playlist;
2603 framepos_t internal_start;
2606 if ((playlist = (*i)->playlist()) == 0) {
2610 if ((current = playlist->top_region_at(start)) == 0) {
2614 internal_start = start - current->position();
2615 RegionFactory::region_name (new_name, current->name(), true);
2619 plist.add (ARDOUR::Properties::start, current->start() + internal_start);
2620 plist.add (ARDOUR::Properties::length, end - start + 1);
2621 plist.add (ARDOUR::Properties::name, new_name);
2623 new_regions.push_back (RegionFactory::create (current, plist));
2628 Editor::split_multichannel_region ()
2630 RegionSelection rs = get_regions_from_selection_and_entered ();
2636 vector< boost::shared_ptr<Region> > v;
2638 for (list<RegionView*>::iterator x = rs.begin(); x != rs.end(); ++x) {
2639 (*x)->region()->separate_by_channel (*_session, v);
2644 Editor::new_region_from_selection ()
2646 region_from_selection ();
2647 cancel_selection ();
2651 add_if_covered (RegionView* rv, const AudioRange* ar, RegionSelection* rs)
2653 switch (rv->region()->coverage (ar->start, ar->end - 1)) {
2654 case Evoral::OverlapNone:
2662 * - selected tracks, or if there are none...
2663 * - tracks containing selected regions, or if there are none...
2668 Editor::get_tracks_for_range_action () const
2672 if (selection->tracks.empty()) {
2674 /* use tracks with selected regions */
2676 RegionSelection rs = selection->regions;
2678 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
2679 TimeAxisView* tv = &(*i)->get_time_axis_view();
2681 if (!t.contains (tv)) {
2687 /* no regions and no tracks: use all tracks */
2693 t = selection->tracks;
2696 return t.filter_to_unique_playlists();
2700 Editor::separate_regions_between (const TimeSelection& ts)
2702 bool in_command = false;
2703 boost::shared_ptr<Playlist> playlist;
2704 RegionSelection new_selection;
2706 TrackViewList tmptracks = get_tracks_for_range_action ();
2707 sort_track_selection (tmptracks);
2709 for (TrackSelection::iterator i = tmptracks.begin(); i != tmptracks.end(); ++i) {
2711 RouteTimeAxisView* rtv;
2713 if ((rtv = dynamic_cast<RouteTimeAxisView*> ((*i))) != 0) {
2715 if (rtv->is_track()) {
2717 /* no edits to destructive tracks */
2719 if (rtv->track()->destructive()) {
2723 if ((playlist = rtv->playlist()) != 0) {
2725 playlist->clear_changes ();
2727 /* XXX need to consider musical time selections here at some point */
2729 double speed = rtv->track()->speed();
2732 for (list<AudioRange>::const_iterator t = ts.begin(); t != ts.end(); ++t) {
2734 sigc::connection c = rtv->view()->RegionViewAdded.connect (
2735 sigc::mem_fun(*this, &Editor::collect_new_region_view));
2737 latest_regionviews.clear ();
2739 playlist->partition ((framepos_t)((*t).start * speed),
2740 (framepos_t)((*t).end * speed), false);
2744 if (!latest_regionviews.empty()) {
2746 rtv->view()->foreach_regionview (sigc::bind (
2747 sigc::ptr_fun (add_if_covered),
2748 &(*t), &new_selection));
2751 begin_reversible_command (_("separate"));
2755 /* pick up changes to existing regions */
2757 vector<Command*> cmds;
2758 playlist->rdiff (cmds);
2759 _session->add_commands (cmds);
2761 /* pick up changes to the playlist itself (adds/removes)
2764 _session->add_command(new StatefulDiffCommand (playlist));
2773 selection->set (new_selection);
2774 set_mouse_mode (MouseObject);
2776 commit_reversible_command ();
2780 struct PlaylistState {
2781 boost::shared_ptr<Playlist> playlist;
2785 /** Take tracks from get_tracks_for_range_action and cut any regions
2786 * on those tracks so that the tracks are empty over the time
2790 Editor::separate_region_from_selection ()
2792 /* preferentially use *all* ranges in the time selection if we're in range mode
2793 to allow discontiguous operation, since get_edit_op_range() currently
2794 returns a single range.
2797 if (!selection->time.empty()) {
2799 separate_regions_between (selection->time);
2806 if (get_edit_op_range (start, end)) {
2808 AudioRange ar (start, end, 1);
2812 separate_regions_between (ts);
2818 Editor::separate_region_from_punch ()
2820 Location* loc = _session->locations()->auto_punch_location();
2822 separate_regions_using_location (*loc);
2827 Editor::separate_region_from_loop ()
2829 Location* loc = _session->locations()->auto_loop_location();
2831 separate_regions_using_location (*loc);
2836 Editor::separate_regions_using_location (Location& loc)
2838 if (loc.is_mark()) {
2842 AudioRange ar (loc.start(), loc.end(), 1);
2847 separate_regions_between (ts);
2850 /** Separate regions under the selected region */
2852 Editor::separate_under_selected_regions ()
2854 vector<PlaylistState> playlists;
2858 rs = get_regions_from_selection_and_entered();
2860 if (!_session || rs.empty()) {
2864 begin_reversible_command (_("separate region under"));
2866 list<boost::shared_ptr<Region> > regions_to_remove;
2868 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
2869 // we can't just remove the region(s) in this loop because
2870 // this removes them from the RegionSelection, and they thus
2871 // disappear from underneath the iterator, and the ++i above
2872 // SEGVs in a puzzling fashion.
2874 // so, first iterate over the regions to be removed from rs and
2875 // add them to the regions_to_remove list, and then
2876 // iterate over the list to actually remove them.
2878 regions_to_remove.push_back ((*i)->region());
2881 for (list<boost::shared_ptr<Region> >::iterator rl = regions_to_remove.begin(); rl != regions_to_remove.end(); ++rl) {
2883 boost::shared_ptr<Playlist> playlist = (*rl)->playlist();
2886 // is this check necessary?
2890 vector<PlaylistState>::iterator i;
2892 //only take state if this is a new playlist.
2893 for (i = playlists.begin(); i != playlists.end(); ++i) {
2894 if ((*i).playlist == playlist) {
2899 if (i == playlists.end()) {
2901 PlaylistState before;
2902 before.playlist = playlist;
2903 before.before = &playlist->get_state();
2905 playlist->freeze ();
2906 playlists.push_back(before);
2909 //Partition on the region bounds
2910 playlist->partition ((*rl)->first_frame() - 1, (*rl)->last_frame() + 1, true);
2912 //Re-add region that was just removed due to the partition operation
2913 playlist->add_region( (*rl), (*rl)->first_frame() );
2916 vector<PlaylistState>::iterator pl;
2918 for (pl = playlists.begin(); pl != playlists.end(); ++pl) {
2919 (*pl).playlist->thaw ();
2920 _session->add_command(new MementoCommand<Playlist>(*(*pl).playlist, (*pl).before, &(*pl).playlist->get_state()));
2923 commit_reversible_command ();
2927 Editor::crop_region_to_selection ()
2929 if (!selection->time.empty()) {
2931 crop_region_to (selection->time.start(), selection->time.end_frame());
2938 if (get_edit_op_range (start, end)) {
2939 crop_region_to (start, end);
2946 Editor::crop_region_to (framepos_t start, framepos_t end)
2948 vector<boost::shared_ptr<Playlist> > playlists;
2949 boost::shared_ptr<Playlist> playlist;
2952 if (selection->tracks.empty()) {
2953 ts = track_views.filter_to_unique_playlists();
2955 ts = selection->tracks.filter_to_unique_playlists ();
2958 sort_track_selection (ts);
2960 for (TrackSelection::iterator i = ts.begin(); i != ts.end(); ++i) {
2962 RouteTimeAxisView* rtv;
2964 if ((rtv = dynamic_cast<RouteTimeAxisView*> ((*i))) != 0) {
2966 boost::shared_ptr<Track> t = rtv->track();
2968 if (t != 0 && ! t->destructive()) {
2970 if ((playlist = rtv->playlist()) != 0) {
2971 playlists.push_back (playlist);
2977 if (playlists.empty()) {
2981 framepos_t the_start;
2985 begin_reversible_command (_("trim to selection"));
2987 for (vector<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
2989 boost::shared_ptr<Region> region;
2993 if ((region = (*i)->top_region_at(the_start)) == 0) {
2997 /* now adjust lengths to that we do the right thing
2998 if the selection extends beyond the region
3001 the_start = max (the_start, (framepos_t) region->position());
3002 if (max_framepos - the_start < region->length()) {
3003 the_end = the_start + region->length() - 1;
3005 the_end = max_framepos;
3007 the_end = min (end, the_end);
3008 cnt = the_end - the_start + 1;
3010 region->clear_changes ();
3011 region->trim_to (the_start, cnt);
3012 _session->add_command (new StatefulDiffCommand (region));
3015 commit_reversible_command ();
3019 Editor::region_fill_track ()
3021 RegionSelection rs = get_regions_from_selection_and_entered ();
3023 if (!_session || rs.empty()) {
3027 framepos_t const end = _session->current_end_frame ();
3029 begin_reversible_command (Operations::region_fill);
3031 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3033 boost::shared_ptr<Region> region ((*i)->region());
3035 boost::shared_ptr<Playlist> pl = region->playlist();
3037 if (end <= region->last_frame()) {
3041 double times = (double) (end - region->last_frame()) / (double) region->length();
3047 pl->clear_changes ();
3048 pl->add_region (RegionFactory::create (region, true), region->last_frame(), times);
3049 _session->add_command (new StatefulDiffCommand (pl));
3052 commit_reversible_command ();
3056 Editor::region_fill_selection ()
3058 if (clicked_routeview == 0 || !clicked_routeview->is_audio_track()) {
3062 if (selection->time.empty()) {
3066 boost::shared_ptr<Region> region = _regions->get_single_selection ();
3071 framepos_t start = selection->time[clicked_selection].start;
3072 framepos_t end = selection->time[clicked_selection].end;
3074 boost::shared_ptr<Playlist> playlist;
3076 if (selection->tracks.empty()) {
3080 framepos_t selection_length = end - start;
3081 float times = (float)selection_length / region->length();
3083 begin_reversible_command (Operations::fill_selection);
3085 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
3087 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
3089 if ((playlist = (*i)->playlist()) == 0) {
3093 playlist->clear_changes ();
3094 playlist->add_region (RegionFactory::create (region, true), start, times);
3095 _session->add_command (new StatefulDiffCommand (playlist));
3098 commit_reversible_command ();
3102 Editor::set_region_sync_position ()
3104 set_sync_point (get_preferred_edit_position (), get_regions_from_selection_and_edit_point ());
3108 Editor::set_sync_point (framepos_t where, const RegionSelection& rs)
3110 bool in_command = false;
3112 for (RegionSelection::const_iterator r = rs.begin(); r != rs.end(); ++r) {
3114 if (!(*r)->region()->covers (where)) {
3118 boost::shared_ptr<Region> region ((*r)->region());
3121 begin_reversible_command (_("set sync point"));
3125 region->clear_changes ();
3126 region->set_sync_position (where);
3127 _session->add_command(new StatefulDiffCommand (region));
3131 commit_reversible_command ();
3135 /** Remove the sync positions of the selection */
3137 Editor::remove_region_sync ()
3139 RegionSelection rs = get_regions_from_selection_and_entered ();
3145 begin_reversible_command (_("remove region sync"));
3147 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3149 (*i)->region()->clear_changes ();
3150 (*i)->region()->clear_sync_position ();
3151 _session->add_command(new StatefulDiffCommand ((*i)->region()));
3154 commit_reversible_command ();
3158 Editor::naturalize_region ()
3160 RegionSelection rs = get_regions_from_selection_and_entered ();
3166 if (rs.size() > 1) {
3167 begin_reversible_command (_("move regions to original position"));
3169 begin_reversible_command (_("move region to original position"));
3172 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3173 (*i)->region()->clear_changes ();
3174 (*i)->region()->move_to_natural_position ();
3175 _session->add_command (new StatefulDiffCommand ((*i)->region()));
3178 commit_reversible_command ();
3182 Editor::align_regions (RegionPoint what)
3184 RegionSelection const rs = get_regions_from_selection_and_edit_point ();
3190 begin_reversible_command (_("align selection"));
3192 framepos_t const position = get_preferred_edit_position ();
3194 for (RegionSelection::const_iterator i = rs.begin(); i != rs.end(); ++i) {
3195 align_region_internal ((*i)->region(), what, position);
3198 commit_reversible_command ();
3201 struct RegionSortByTime {
3202 bool operator() (const RegionView* a, const RegionView* b) {
3203 return a->region()->position() < b->region()->position();
3208 Editor::align_regions_relative (RegionPoint point)
3210 RegionSelection const rs = get_regions_from_selection_and_edit_point ();
3216 framepos_t const position = get_preferred_edit_position ();
3218 framepos_t distance = 0;
3222 list<RegionView*> sorted;
3223 rs.by_position (sorted);
3225 boost::shared_ptr<Region> r ((*sorted.begin())->region());
3230 if (position > r->position()) {
3231 distance = position - r->position();
3233 distance = r->position() - position;
3239 if (position > r->last_frame()) {
3240 distance = position - r->last_frame();
3241 pos = r->position() + distance;
3243 distance = r->last_frame() - position;
3244 pos = r->position() - distance;
3250 pos = r->adjust_to_sync (position);
3251 if (pos > r->position()) {
3252 distance = pos - r->position();
3254 distance = r->position() - pos;
3260 if (pos == r->position()) {
3264 begin_reversible_command (_("align selection (relative)"));
3266 /* move first one specially */
3268 r->clear_changes ();
3269 r->set_position (pos);
3270 _session->add_command(new StatefulDiffCommand (r));
3272 /* move rest by the same amount */
3276 for (list<RegionView*>::iterator i = sorted.begin(); i != sorted.end(); ++i) {
3278 boost::shared_ptr<Region> region ((*i)->region());
3280 region->clear_changes ();
3283 region->set_position (region->position() + distance);
3285 region->set_position (region->position() - distance);
3288 _session->add_command(new StatefulDiffCommand (region));
3292 commit_reversible_command ();
3296 Editor::align_region (boost::shared_ptr<Region> region, RegionPoint point, framepos_t position)
3298 begin_reversible_command (_("align region"));
3299 align_region_internal (region, point, position);
3300 commit_reversible_command ();
3304 Editor::align_region_internal (boost::shared_ptr<Region> region, RegionPoint point, framepos_t position)
3306 region->clear_changes ();
3310 region->set_position (region->adjust_to_sync (position));
3314 if (position > region->length()) {
3315 region->set_position (position - region->length());
3320 region->set_position (position);
3324 _session->add_command(new StatefulDiffCommand (region));
3328 Editor::trim_region_front ()
3334 Editor::trim_region_back ()
3336 trim_region (false);
3340 Editor::trim_region (bool front)
3342 framepos_t where = get_preferred_edit_position();
3343 RegionSelection rs = get_regions_from_selection_and_edit_point ();
3349 begin_reversible_command (front ? _("trim front") : _("trim back"));
3351 for (list<RegionView*>::const_iterator i = rs.by_layer().begin(); i != rs.by_layer().end(); ++i) {
3352 if (!(*i)->region()->locked()) {
3354 (*i)->region()->clear_changes ();
3357 (*i)->region()->trim_front (where);
3358 maybe_locate_with_edit_preroll ( where );
3360 (*i)->region()->trim_end (where);
3361 maybe_locate_with_edit_preroll ( where );
3364 _session->add_command (new StatefulDiffCommand ((*i)->region()));
3368 commit_reversible_command ();
3371 /** Trim the end of the selected regions to the position of the edit cursor */
3373 Editor::trim_region_to_loop ()
3375 Location* loc = _session->locations()->auto_loop_location();
3379 trim_region_to_location (*loc, _("trim to loop"));
3383 Editor::trim_region_to_punch ()
3385 Location* loc = _session->locations()->auto_punch_location();
3389 trim_region_to_location (*loc, _("trim to punch"));
3393 Editor::trim_region_to_location (const Location& loc, const char* str)
3395 RegionSelection rs = get_regions_from_selection_and_entered ();
3397 begin_reversible_command (str);
3399 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
3400 RegionView* rv = (*x);
3402 /* require region to span proposed trim */
3403 switch (rv->region()->coverage (loc.start(), loc.end())) {
3404 case Evoral::OverlapInternal:
3410 RouteTimeAxisView* tav = dynamic_cast<RouteTimeAxisView*> (&rv->get_time_axis_view());
3419 if (tav->track() != 0) {
3420 speed = tav->track()->speed();
3423 start = session_frame_to_track_frame (loc.start(), speed);
3424 end = session_frame_to_track_frame (loc.end(), speed);
3426 rv->region()->clear_changes ();
3427 rv->region()->trim_to (start, (end - start));
3428 _session->add_command(new StatefulDiffCommand (rv->region()));
3431 commit_reversible_command ();
3435 Editor::trim_region_to_previous_region_end ()
3437 return trim_to_region(false);
3441 Editor::trim_region_to_next_region_start ()
3443 return trim_to_region(true);
3447 Editor::trim_to_region(bool forward)
3449 RegionSelection rs = get_regions_from_selection_and_entered ();
3451 begin_reversible_command (_("trim to region"));
3453 boost::shared_ptr<Region> next_region;
3455 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
3457 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*x);
3463 AudioTimeAxisView* atav = dynamic_cast<AudioTimeAxisView*> (&arv->get_time_axis_view());
3471 if (atav->track() != 0) {
3472 speed = atav->track()->speed();
3476 boost::shared_ptr<Region> region = arv->region();
3477 boost::shared_ptr<Playlist> playlist (region->playlist());
3479 region->clear_changes ();
3483 next_region = playlist->find_next_region (region->first_frame(), Start, 1);
3489 region->trim_end((framepos_t) ( (next_region->first_frame() - 1) * speed));
3490 arv->region_changed (PropertyChange (ARDOUR::Properties::length));
3494 next_region = playlist->find_next_region (region->first_frame(), Start, 0);
3500 region->trim_front((framepos_t) ((next_region->last_frame() + 1) * speed));
3502 arv->region_changed (ARDOUR::bounds_change);
3505 _session->add_command(new StatefulDiffCommand (region));
3508 commit_reversible_command ();
3512 Editor::unfreeze_route ()
3514 if (clicked_routeview == 0 || !clicked_routeview->is_track()) {
3518 clicked_routeview->track()->unfreeze ();
3522 Editor::_freeze_thread (void* arg)
3524 return static_cast<Editor*>(arg)->freeze_thread ();
3528 Editor::freeze_thread ()
3530 /* create event pool because we may need to talk to the session */
3531 SessionEvent::create_per_thread_pool ("freeze events", 64);
3532 /* create per-thread buffers for process() tree to use */
3533 clicked_routeview->audio_track()->freeze_me (*current_interthread_info);
3534 current_interthread_info->done = true;
3539 Editor::freeze_route ()
3545 /* stop transport before we start. this is important */
3547 _session->request_transport_speed (0.0);
3549 /* wait for just a little while, because the above call is asynchronous */
3551 Glib::usleep (250000);
3553 if (clicked_routeview == 0 || !clicked_routeview->is_audio_track()) {
3557 if (!clicked_routeview->track()->bounceable (clicked_routeview->track()->main_outs(), true)) {
3559 _("This track/bus cannot be frozen because the signal adds or loses channels before reaching the outputs.\n"
3560 "This is typically caused by plugins that generate stereo output from mono input or vice versa.")
3562 d.set_title (_("Cannot freeze"));
3567 if (clicked_routeview->track()->has_external_redirects()) {
3568 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"
3569 "Freezing will only process the signal as far as the first send/insert/return."),
3570 clicked_routeview->track()->name()), true, MESSAGE_INFO, BUTTONS_NONE, true);
3572 d.add_button (_("Freeze anyway"), Gtk::RESPONSE_OK);
3573 d.add_button (_("Don't freeze"), Gtk::RESPONSE_CANCEL);
3574 d.set_title (_("Freeze Limits"));
3576 int response = d.run ();
3579 case Gtk::RESPONSE_CANCEL:
3586 InterThreadInfo itt;
3587 current_interthread_info = &itt;
3589 InterthreadProgressWindow ipw (current_interthread_info, _("Freeze"), _("Cancel Freeze"));
3591 pthread_create_and_store (X_("freezer"), &itt.thread, _freeze_thread, this);
3593 set_canvas_cursor (_cursors->wait);
3595 while (!itt.done && !itt.cancel) {
3596 gtk_main_iteration ();
3599 current_interthread_info = 0;
3600 set_canvas_cursor (current_canvas_cursor);
3604 Editor::bounce_range_selection (bool replace, bool enable_processing)
3606 if (selection->time.empty()) {
3610 TrackSelection views = selection->tracks;
3612 for (TrackViewList::iterator i = views.begin(); i != views.end(); ++i) {
3614 if (enable_processing) {
3616 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*i);
3618 if (rtv && rtv->track() && replace && enable_processing && !rtv->track()->bounceable (rtv->track()->main_outs(), false)) {
3620 _("You can't perform this operation because the processing of the signal "
3621 "will cause one or more of the tracks to end up with a region with more channels than this track has inputs.\n\n"
3622 "You can do this without processing, which is a different operation.")
3624 d.set_title (_("Cannot bounce"));
3631 framepos_t start = selection->time[clicked_selection].start;
3632 framepos_t end = selection->time[clicked_selection].end;
3633 framepos_t cnt = end - start + 1;
3635 begin_reversible_command (_("bounce range"));
3637 for (TrackViewList::iterator i = views.begin(); i != views.end(); ++i) {
3639 RouteTimeAxisView* rtv;
3641 if ((rtv = dynamic_cast<RouteTimeAxisView*> (*i)) == 0) {
3645 boost::shared_ptr<Playlist> playlist;
3647 if ((playlist = rtv->playlist()) == 0) {
3651 InterThreadInfo itt;
3653 playlist->clear_changes ();
3654 playlist->clear_owned_changes ();
3656 boost::shared_ptr<Region> r;
3658 if (enable_processing) {
3659 r = rtv->track()->bounce_range (start, start+cnt, itt, rtv->track()->main_outs(), false);
3661 r = rtv->track()->bounce_range (start, start+cnt, itt, boost::shared_ptr<Processor>(), false);
3669 list<AudioRange> ranges;
3670 ranges.push_back (AudioRange (start, start+cnt, 0));
3671 playlist->cut (ranges); // discard result
3672 playlist->add_region (r, start);
3675 vector<Command*> cmds;
3676 playlist->rdiff (cmds);
3677 _session->add_commands (cmds);
3679 _session->add_command (new StatefulDiffCommand (playlist));
3682 commit_reversible_command ();
3685 /** Delete selected regions, automation points or a time range */
3692 /** Cut selected regions, automation points or a time range */
3699 /** Copy selected regions, automation points or a time range */
3707 /** @return true if a Cut, Copy or Clear is possible */
3709 Editor::can_cut_copy () const
3711 switch (effective_mouse_mode()) {
3714 if (!selection->regions.empty() || !selection->points.empty()) {
3720 if (!selection->time.empty()) {
3733 /** Cut, copy or clear selected regions, automation points or a time range.
3734 * @param op Operation (Delete, Cut, Copy or Clear)
3737 Editor::cut_copy (CutCopyOp op)
3739 /* only cancel selection if cut/copy is successful.*/
3745 opname = _("delete");
3754 opname = _("clear");
3758 /* if we're deleting something, and the mouse is still pressed,
3759 the thing we started a drag for will be gone when we release
3760 the mouse button(s). avoid this. see part 2 at the end of
3764 if (op == Delete || op == Cut || op == Clear) {
3765 if (_drags->active ()) {
3770 if ( op != Delete ) //"Delete" doesn't change copy/paste buf
3771 cut_buffer->clear ();
3773 if (entered_marker) {
3775 /* cut/delete op while pointing at a marker */
3778 Location* loc = find_location_from_marker (entered_marker, ignored);
3780 if (_session && loc) {
3781 Glib::signal_idle().connect (sigc::bind (sigc::mem_fun(*this, &Editor::really_remove_marker), loc));
3788 if (internal_editing()) {
3790 switch (effective_mouse_mode()) {
3793 begin_reversible_command (opname + ' ' + X_("MIDI"));
3795 commit_reversible_command ();
3804 bool did_edit = false;
3806 switch (effective_mouse_mode()) {
3808 if (!selection->points.empty()) {
3809 begin_reversible_command (opname + _(" points"));
3811 cut_copy_points (op);
3812 if (op == Cut || op == Delete) {
3813 selection->clear_points ();
3820 if (!selection->regions.empty() || !selection->points.empty()) {
3824 if (selection->regions.empty()) {
3825 thing_name = _("points");
3826 } else if (selection->points.empty()) {
3827 thing_name = _("regions");
3829 thing_name = _("objects");
3832 begin_reversible_command (opname + ' ' + thing_name);
3835 if (!selection->regions.empty()) {
3836 cut_copy_regions (op, selection->regions);
3838 if (op == Cut || op == Delete) {
3839 selection->clear_regions ();
3843 if (!selection->points.empty()) {
3844 cut_copy_points (op);
3846 if (op == Cut || op == Delete) {
3847 selection->clear_points ();
3854 if (selection->time.empty()) {
3855 framepos_t start, end;
3856 /* no time selection, see if we can get an edit range
3859 if (get_edit_op_range (start, end)) {
3860 selection->set (start, end);
3863 if (!selection->time.empty()) {
3864 begin_reversible_command (opname + _(" range"));
3867 cut_copy_ranges (op);
3869 if (op == Cut || op == Delete) {
3870 selection->clear_time ();
3880 commit_reversible_command ();
3883 if (op == Delete || op == Cut || op == Clear) {
3888 struct AutomationRecord {
3889 AutomationRecord () : state (0) {}
3890 AutomationRecord (XMLNode* s) : state (s) {}
3892 XMLNode* state; ///< state before any operation
3893 boost::shared_ptr<Evoral::ControlList> copy; ///< copied events for the cut buffer
3896 /** Cut, copy or clear selected automation points.
3897 * @param op Operation (Cut, Copy or Clear)
3900 Editor::cut_copy_points (CutCopyOp op)
3902 if (selection->points.empty ()) {
3906 /* XXX: not ideal, as there may be more than one track involved in the point selection */
3907 _last_cut_copy_source_track = &selection->points.front()->line().trackview;
3909 /* Keep a record of the AutomationLists that we end up using in this operation */
3910 typedef std::map<boost::shared_ptr<AutomationList>, AutomationRecord> Lists;
3913 /* Go through all selected points, making an AutomationRecord for each distinct AutomationList */
3914 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
3915 boost::shared_ptr<AutomationList> al = (*i)->line().the_list();
3916 if (lists.find (al) == lists.end ()) {
3917 /* We haven't seen this list yet, so make a record for it. This includes
3918 taking a copy of its current state, in case this is needed for undo later.
3920 lists[al] = AutomationRecord (&al->get_state ());
3924 if (op == Cut || op == Copy) {
3925 /* This operation will involve putting things in the cut buffer, so create an empty
3926 ControlList for each of our source lists to put the cut buffer data in.
3928 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
3929 i->second.copy = i->first->create (i->first->parameter ());
3932 /* Add all selected points to the relevant copy ControlLists */
3933 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
3934 boost::shared_ptr<AutomationList> al = (*i)->line().the_list();
3935 AutomationList::const_iterator j = (*i)->model ();
3936 lists[al].copy->add ((*j)->when, (*j)->value);
3939 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
3940 /* Correct this copy list so that it starts at time 0 */
3941 double const start = i->second.copy->front()->when;
3942 for (AutomationList::iterator j = i->second.copy->begin(); j != i->second.copy->end(); ++j) {
3943 (*j)->when -= start;
3946 /* And add it to the cut buffer */
3947 cut_buffer->add (i->second.copy);
3951 if (op == Delete || op == Cut) {
3952 /* This operation needs to remove things from the main AutomationList, so do that now */
3954 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
3955 i->first->freeze ();
3958 /* Remove each selected point from its AutomationList */
3959 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
3960 boost::shared_ptr<AutomationList> al = (*i)->line().the_list();
3961 al->erase ((*i)->model ());
3964 /* Thaw the lists and add undo records for them */
3965 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
3966 boost::shared_ptr<AutomationList> al = i->first;
3968 _session->add_command (new MementoCommand<AutomationList> (*al.get(), i->second.state, &(al->get_state ())));
3973 /** Cut, copy or clear selected automation points.
3974 * @param op Operation (Cut, Copy or Clear)
3977 Editor::cut_copy_midi (CutCopyOp op)
3979 for (MidiRegionSelection::iterator i = selection->midi_regions.begin(); i != selection->midi_regions.end(); ++i) {
3980 MidiRegionView* mrv = *i;
3981 mrv->cut_copy_clear (op);
3987 struct lt_playlist {
3988 bool operator () (const PlaylistState& a, const PlaylistState& b) {
3989 return a.playlist < b.playlist;
3993 struct PlaylistMapping {
3995 boost::shared_ptr<Playlist> pl;
3997 PlaylistMapping (TimeAxisView* tvp) : tv (tvp) {}
4000 /** Remove `clicked_regionview' */
4002 Editor::remove_clicked_region ()
4004 if (clicked_routeview == 0 || clicked_regionview == 0) {
4008 boost::shared_ptr<Playlist> playlist = clicked_routeview->playlist();
4010 playlist->clear_changes ();
4011 playlist->clear_owned_changes ();
4012 playlist->remove_region (clicked_regionview->region());
4013 if (Config->get_edit_mode() == Ripple)
4014 playlist->ripple (clicked_regionview->region()->position(), -clicked_regionview->region()->length(), boost::shared_ptr<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);
4077 if (Config->get_edit_mode() == Ripple)
4078 playlist->ripple ((*rl)->position(), -(*rl)->length(), boost::shared_ptr<Region>());
4082 vector<boost::shared_ptr<Playlist> >::iterator pl;
4084 for (pl = playlists.begin(); pl != playlists.end(); ++pl) {
4087 /* We might have removed regions, which alters other regions' layering_index,
4088 so we need to do a recursive diff here.
4090 vector<Command*> cmds;
4091 (*pl)->rdiff (cmds);
4092 _session->add_commands (cmds);
4094 _session->add_command(new StatefulDiffCommand (*pl));
4097 commit_reversible_command ();
4100 /** Cut, copy or clear selected regions.
4101 * @param op Operation (Cut, Copy or Clear)
4104 Editor::cut_copy_regions (CutCopyOp op, RegionSelection& rs)
4106 /* we can't use a std::map here because the ordering is important, and we can't trivially sort
4107 a map when we want ordered access to both elements. i think.
4110 vector<PlaylistMapping> pmap;
4112 framepos_t first_position = max_framepos;
4114 typedef set<boost::shared_ptr<Playlist> > FreezeList;
4115 FreezeList freezelist;
4117 /* get ordering correct before we cut/copy */
4119 rs.sort_by_position_and_track ();
4121 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
4123 first_position = min ((framepos_t) (*x)->region()->position(), first_position);
4125 if (op == Cut || op == Clear || op == Delete) {
4126 boost::shared_ptr<Playlist> pl = (*x)->region()->playlist();
4129 FreezeList::iterator fl;
4131 // only take state if this is a new playlist.
4132 for (fl = freezelist.begin(); fl != freezelist.end(); ++fl) {
4138 if (fl == freezelist.end()) {
4139 pl->clear_changes();
4140 pl->clear_owned_changes ();
4142 freezelist.insert (pl);
4147 TimeAxisView* tv = &(*x)->get_time_axis_view();
4148 vector<PlaylistMapping>::iterator z;
4150 for (z = pmap.begin(); z != pmap.end(); ++z) {
4151 if ((*z).tv == tv) {
4156 if (z == pmap.end()) {
4157 pmap.push_back (PlaylistMapping (tv));
4161 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ) {
4163 boost::shared_ptr<Playlist> pl = (*x)->region()->playlist();
4166 /* region not yet associated with a playlist (e.g. unfinished
4173 TimeAxisView& tv = (*x)->get_time_axis_view();
4174 boost::shared_ptr<Playlist> npl;
4175 RegionSelection::iterator tmp;
4182 vector<PlaylistMapping>::iterator z;
4184 for (z = pmap.begin(); z != pmap.end(); ++z) {
4185 if ((*z).tv == &tv) {
4190 assert (z != pmap.end());
4193 npl = PlaylistFactory::create (pl->data_type(), *_session, "cutlist", true);
4201 boost::shared_ptr<Region> r = (*x)->region();
4202 boost::shared_ptr<Region> _xx;
4208 pl->remove_region (r);
4209 if (Config->get_edit_mode() == Ripple)
4210 pl->ripple (r->position(), -r->length(), boost::shared_ptr<Region>());
4214 _xx = RegionFactory::create (r);
4215 npl->add_region (_xx, r->position() - first_position);
4216 pl->remove_region (r);
4217 if (Config->get_edit_mode() == Ripple)
4218 pl->ripple (r->position(), -r->length(), boost::shared_ptr<Region>());
4222 /* copy region before adding, so we're not putting same object into two different playlists */
4223 npl->add_region (RegionFactory::create (r), r->position() - first_position);
4227 pl->remove_region (r);
4228 if (Config->get_edit_mode() == Ripple)
4229 pl->ripple (r->position(), -r->length(), boost::shared_ptr<Region>());
4238 list<boost::shared_ptr<Playlist> > foo;
4240 /* the pmap is in the same order as the tracks in which selected regions occured */
4242 for (vector<PlaylistMapping>::iterator i = pmap.begin(); i != pmap.end(); ++i) {
4245 foo.push_back ((*i).pl);
4250 cut_buffer->set (foo);
4254 _last_cut_copy_source_track = 0;
4256 _last_cut_copy_source_track = pmap.front().tv;
4260 for (FreezeList::iterator pl = freezelist.begin(); pl != freezelist.end(); ++pl) {
4263 /* We might have removed regions, which alters other regions' layering_index,
4264 so we need to do a recursive diff here.
4266 vector<Command*> cmds;
4267 (*pl)->rdiff (cmds);
4268 _session->add_commands (cmds);
4270 _session->add_command (new StatefulDiffCommand (*pl));
4275 Editor::cut_copy_ranges (CutCopyOp op)
4277 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4279 /* Sort the track selection now, so that it if is used, the playlists
4280 selected by the calls below to cut_copy_clear are in the order that
4281 their tracks appear in the editor. This makes things like paste
4282 of ranges work properly.
4285 sort_track_selection (ts);
4288 if (!entered_track) {
4291 ts.push_back (entered_track);
4294 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4295 (*i)->cut_copy_clear (*selection, op);
4300 Editor::paste (float times, bool from_context)
4302 DEBUG_TRACE (DEBUG::CutNPaste, "paste to preferred edit pos\n");
4304 paste_internal (get_preferred_edit_position (false, from_context), times);
4308 Editor::mouse_paste ()
4313 if (!mouse_frame (where, ignored)) {
4318 paste_internal (where, 1);
4322 Editor::paste_internal (framepos_t position, float times)
4324 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("apparent paste position is %1\n", position));
4326 if (internal_editing()) {
4327 if (cut_buffer->midi_notes.empty()) {
4331 if (cut_buffer->empty()) {
4336 if (position == max_framepos) {
4337 position = get_preferred_edit_position();
4338 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("preferred edit position is %1\n", position));
4342 TrackViewList::iterator i;
4345 /* get everything in the correct order */
4347 if (_edit_point == Editing::EditAtMouse && entered_track) {
4348 /* With the mouse edit point, paste onto the track under the mouse */
4349 ts.push_back (entered_track);
4350 } else if (!selection->tracks.empty()) {
4351 /* Otherwise, if there are some selected tracks, paste to them */
4352 ts = selection->tracks.filter_to_unique_playlists ();
4353 sort_track_selection (ts);
4354 } else if (_last_cut_copy_source_track) {
4355 /* Otherwise paste to the track that the cut/copy came from;
4356 see discussion in mantis #3333.
4358 ts.push_back (_last_cut_copy_source_track);
4361 if (internal_editing ()) {
4363 /* undo/redo is handled by individual tracks/regions */
4365 for (nth = 0, i = ts.begin(); i != ts.end(); ++i, ++nth) {
4368 RegionSelection::iterator r;
4369 MidiNoteSelection::iterator cb;
4371 get_regions_at (rs, position, ts);
4373 for (cb = cut_buffer->midi_notes.begin(), r = rs.begin();
4374 cb != cut_buffer->midi_notes.end() && r != rs.end(); ++r) {
4375 MidiRegionView* mrv = dynamic_cast<MidiRegionView*> (*r);
4377 mrv->paste (position, times, **cb);
4385 /* we do redo (do you do voodoo?) */
4387 begin_reversible_command (Operations::paste);
4389 for (nth = 0, i = ts.begin(); i != ts.end(); ++i, ++nth) {
4390 (*i)->paste (position, times, *cut_buffer, nth);
4393 commit_reversible_command ();
4398 Editor::duplicate_some_regions (RegionSelection& regions, float times)
4400 boost::shared_ptr<Playlist> playlist;
4401 RegionSelection sel = regions; // clear (below) may clear the argument list if its the current region selection
4402 RegionSelection foo;
4404 framepos_t const start_frame = regions.start ();
4405 framepos_t const end_frame = regions.end_frame ();
4407 begin_reversible_command (Operations::duplicate_region);
4409 selection->clear_regions ();
4411 for (RegionSelection::iterator i = sel.begin(); i != sel.end(); ++i) {
4413 boost::shared_ptr<Region> r ((*i)->region());
4415 TimeAxisView& tv = (*i)->get_time_axis_view();
4416 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (&tv);
4417 latest_regionviews.clear ();
4418 sigc::connection c = rtv->view()->RegionViewAdded.connect (sigc::mem_fun(*this, &Editor::collect_new_region_view));
4420 playlist = (*i)->region()->playlist();
4421 playlist->clear_changes ();
4422 playlist->duplicate (r, end_frame + (r->first_frame() - start_frame), times);
4423 _session->add_command(new StatefulDiffCommand (playlist));
4427 foo.insert (foo.end(), latest_regionviews.begin(), latest_regionviews.end());
4430 commit_reversible_command ();
4433 selection->set (foo);
4438 Editor::duplicate_selection (float times)
4440 if (selection->time.empty() || selection->tracks.empty()) {
4444 boost::shared_ptr<Playlist> playlist;
4445 vector<boost::shared_ptr<Region> > new_regions;
4446 vector<boost::shared_ptr<Region> >::iterator ri;
4448 create_region_from_selection (new_regions);
4450 if (new_regions.empty()) {
4454 begin_reversible_command (_("duplicate selection"));
4456 ri = new_regions.begin();
4458 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4460 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4461 if ((playlist = (*i)->playlist()) == 0) {
4464 playlist->clear_changes ();
4465 playlist->duplicate (*ri, selection->time[clicked_selection].end, times);
4466 _session->add_command (new StatefulDiffCommand (playlist));
4469 if (ri == new_regions.end()) {
4474 commit_reversible_command ();
4477 /** Reset all selected points to the relevant default value */
4479 Editor::reset_point_selection ()
4481 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
4482 ARDOUR::AutomationList::iterator j = (*i)->model ();
4483 (*j)->value = (*i)->line().the_list()->default_value ();
4488 Editor::center_playhead ()
4490 float const page = _visible_canvas_width * samples_per_pixel;
4491 center_screen_internal (playhead_cursor->current_frame (), page);
4495 Editor::center_edit_point ()
4497 float const page = _visible_canvas_width * samples_per_pixel;
4498 center_screen_internal (get_preferred_edit_position(), page);
4501 /** Caller must begin and commit a reversible command */
4503 Editor::clear_playlist (boost::shared_ptr<Playlist> playlist)
4505 playlist->clear_changes ();
4507 _session->add_command (new StatefulDiffCommand (playlist));
4511 Editor::nudge_track (bool use_edit, bool forwards)
4513 boost::shared_ptr<Playlist> playlist;
4514 framepos_t distance;
4515 framepos_t next_distance;
4519 start = get_preferred_edit_position();
4524 if ((distance = get_nudge_distance (start, next_distance)) == 0) {
4528 if (selection->tracks.empty()) {
4532 begin_reversible_command (_("nudge track"));
4534 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4536 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4538 if ((playlist = (*i)->playlist()) == 0) {
4542 playlist->clear_changes ();
4543 playlist->clear_owned_changes ();
4545 playlist->nudge_after (start, distance, forwards);
4547 vector<Command*> cmds;
4549 playlist->rdiff (cmds);
4550 _session->add_commands (cmds);
4552 _session->add_command (new StatefulDiffCommand (playlist));
4555 commit_reversible_command ();
4559 Editor::remove_last_capture ()
4561 vector<string> choices;
4568 if (Config->get_verify_remove_last_capture()) {
4569 prompt = _("Do you really want to destroy the last capture?"
4570 "\n(This is destructive and cannot be undone)");
4572 choices.push_back (_("No, do nothing."));
4573 choices.push_back (_("Yes, destroy it."));
4575 Gtkmm2ext::Choice prompter (_("Destroy last capture"), prompt, choices);
4577 if (prompter.run () == 1) {
4578 _session->remove_last_capture ();
4579 _regions->redisplay ();
4583 _session->remove_last_capture();
4584 _regions->redisplay ();
4589 Editor::normalize_region ()
4595 RegionSelection rs = get_regions_from_selection_and_entered ();
4601 NormalizeDialog dialog (rs.size() > 1);
4603 if (dialog.run () == RESPONSE_CANCEL) {
4607 set_canvas_cursor (_cursors->wait);
4610 /* XXX: should really only count audio regions here */
4611 int const regions = rs.size ();
4613 /* Make a list of the selected audio regions' maximum amplitudes, and also
4614 obtain the maximum amplitude of them all.
4616 list<double> max_amps;
4618 for (RegionSelection::const_iterator i = rs.begin(); i != rs.end(); ++i) {
4619 AudioRegionView const * arv = dynamic_cast<AudioRegionView const *> (*i);
4621 dialog.descend (1.0 / regions);
4622 double const a = arv->audio_region()->maximum_amplitude (&dialog);
4625 /* the user cancelled the operation */
4626 set_canvas_cursor (current_canvas_cursor);
4630 max_amps.push_back (a);
4631 max_amp = max (max_amp, a);
4636 begin_reversible_command (_("normalize"));
4638 list<double>::const_iterator a = max_amps.begin ();
4640 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
4641 AudioRegionView* const arv = dynamic_cast<AudioRegionView*> (*r);
4646 arv->region()->clear_changes ();
4648 double const amp = dialog.normalize_individually() ? *a : max_amp;
4650 arv->audio_region()->normalize (amp, dialog.target ());
4651 _session->add_command (new StatefulDiffCommand (arv->region()));
4656 commit_reversible_command ();
4657 set_canvas_cursor (current_canvas_cursor);
4662 Editor::reset_region_scale_amplitude ()
4668 RegionSelection rs = get_regions_from_selection_and_entered ();
4674 begin_reversible_command ("reset gain");
4676 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
4677 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
4680 arv->region()->clear_changes ();
4681 arv->audio_region()->set_scale_amplitude (1.0f);
4682 _session->add_command (new StatefulDiffCommand (arv->region()));
4685 commit_reversible_command ();
4689 Editor::adjust_region_gain (bool up)
4691 RegionSelection rs = get_regions_from_selection_and_entered ();
4693 if (!_session || rs.empty()) {
4697 begin_reversible_command ("adjust region gain");
4699 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
4700 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
4705 arv->region()->clear_changes ();
4707 double dB = accurate_coefficient_to_dB (arv->audio_region()->scale_amplitude ());
4715 arv->audio_region()->set_scale_amplitude (dB_to_coefficient (dB));
4716 _session->add_command (new StatefulDiffCommand (arv->region()));
4719 commit_reversible_command ();
4724 Editor::reverse_region ()
4730 Reverse rev (*_session);
4731 apply_filter (rev, _("reverse regions"));
4735 Editor::strip_region_silence ()
4741 RegionSelection rs = get_regions_from_selection_and_entered ();
4747 std::list<RegionView*> audio_only;
4749 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
4750 AudioRegionView* const arv = dynamic_cast<AudioRegionView*> (*i);
4752 audio_only.push_back (arv);
4756 StripSilenceDialog d (_session, audio_only);
4757 int const r = d.run ();
4761 if (r == Gtk::RESPONSE_OK) {
4762 ARDOUR::AudioIntervalMap silences;
4763 d.silences (silences);
4764 StripSilence s (*_session, silences, d.fade_length());
4765 apply_filter (s, _("strip silence"), &d);
4770 Editor::apply_midi_note_edit_op_to_region (MidiOperator& op, MidiRegionView& mrv)
4772 Evoral::Sequence<Evoral::MusicalTime>::Notes selected;
4773 mrv.selection_as_notelist (selected, true);
4775 vector<Evoral::Sequence<Evoral::MusicalTime>::Notes> v;
4776 v.push_back (selected);
4778 framepos_t pos_frames = mrv.midi_region()->position() - mrv.midi_region()->start();
4779 double pos_beats = _session->tempo_map().framewalk_to_beats(0, pos_frames);
4781 return op (mrv.midi_region()->model(), pos_beats, v);
4785 Editor::apply_midi_note_edit_op (MidiOperator& op)
4789 RegionSelection rs = get_regions_from_selection_and_entered ();
4795 begin_reversible_command (op.name ());
4797 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
4798 RegionSelection::iterator tmp = r;
4801 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*r);
4804 cmd = apply_midi_note_edit_op_to_region (op, *mrv);
4807 _session->add_command (cmd);
4814 commit_reversible_command ();
4818 Editor::fork_region ()
4820 RegionSelection rs = get_regions_from_selection_and_entered ();
4826 begin_reversible_command (_("Fork Region(s)"));
4828 set_canvas_cursor (_cursors->wait);
4831 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
4832 RegionSelection::iterator tmp = r;
4835 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*>(*r);
4839 boost::shared_ptr<Playlist> playlist = mrv->region()->playlist();
4840 boost::shared_ptr<MidiSource> new_source = _session->create_midi_source_by_stealing_name (mrv->midi_view()->track());
4841 boost::shared_ptr<MidiRegion> newregion = mrv->midi_region()->clone (new_source);
4843 playlist->clear_changes ();
4844 playlist->replace_region (mrv->region(), newregion, mrv->region()->position());
4845 _session->add_command(new StatefulDiffCommand (playlist));
4847 error << string_compose (_("Could not unlink %1"), mrv->region()->name()) << endmsg;
4854 commit_reversible_command ();
4856 set_canvas_cursor (current_canvas_cursor);
4860 Editor::quantize_region ()
4862 int selected_midi_region_cnt = 0;
4868 RegionSelection rs = get_regions_from_selection_and_entered ();
4874 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
4875 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*r);
4877 selected_midi_region_cnt++;
4881 if (selected_midi_region_cnt == 0) {
4885 QuantizeDialog* qd = new QuantizeDialog (*this);
4888 const int r = qd->run ();
4891 if (r == Gtk::RESPONSE_OK) {
4892 Quantize quant (*_session, qd->snap_start(), qd->snap_end(),
4893 qd->start_grid_size(), qd->end_grid_size(),
4894 qd->strength(), qd->swing(), qd->threshold());
4896 apply_midi_note_edit_op (quant);
4901 Editor::insert_patch_change (bool from_context)
4903 RegionSelection rs = get_regions_from_selection_and_entered ();
4909 const framepos_t p = get_preferred_edit_position (false, from_context);
4911 /* XXX: bit of a hack; use the MIDNAM from the first selected region;
4912 there may be more than one, but the PatchChangeDialog can only offer
4913 one set of patch menus.
4915 MidiRegionView* first = dynamic_cast<MidiRegionView*> (rs.front ());
4917 Evoral::PatchChange<Evoral::MusicalTime> empty (0, 0, 0, 0);
4918 PatchChangeDialog d (0, _session, empty, first->instrument_info(), Gtk::Stock::ADD);
4920 if (d.run() == RESPONSE_CANCEL) {
4924 for (RegionSelection::iterator i = rs.begin (); i != rs.end(); ++i) {
4925 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*i);
4927 if (p >= mrv->region()->first_frame() && p <= mrv->region()->last_frame()) {
4928 mrv->add_patch_change (p - mrv->region()->position(), d.patch ());
4935 Editor::apply_filter (Filter& filter, string command, ProgressReporter* progress)
4937 RegionSelection rs = get_regions_from_selection_and_entered ();
4943 begin_reversible_command (command);
4945 set_canvas_cursor (_cursors->wait);
4949 int const N = rs.size ();
4951 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
4952 RegionSelection::iterator tmp = r;
4955 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
4957 boost::shared_ptr<Playlist> playlist = arv->region()->playlist();
4960 progress->descend (1.0 / N);
4963 if (arv->audio_region()->apply (filter, progress) == 0) {
4965 playlist->clear_changes ();
4966 playlist->clear_owned_changes ();
4968 if (filter.results.empty ()) {
4970 /* no regions returned; remove the old one */
4971 playlist->remove_region (arv->region ());
4975 std::vector<boost::shared_ptr<Region> >::iterator res = filter.results.begin ();
4977 /* first region replaces the old one */
4978 playlist->replace_region (arv->region(), *res, (*res)->position());
4982 while (res != filter.results.end()) {
4983 playlist->add_region (*res, (*res)->position());
4989 /* We might have removed regions, which alters other regions' layering_index,
4990 so we need to do a recursive diff here.
4992 vector<Command*> cmds;
4993 playlist->rdiff (cmds);
4994 _session->add_commands (cmds);
4996 _session->add_command(new StatefulDiffCommand (playlist));
5002 progress->ascend ();
5010 commit_reversible_command ();
5013 set_canvas_cursor (current_canvas_cursor);
5017 Editor::external_edit_region ()
5023 Editor::reset_region_gain_envelopes ()
5025 RegionSelection rs = get_regions_from_selection_and_entered ();
5027 if (!_session || rs.empty()) {
5031 _session->begin_reversible_command (_("reset region gain"));
5033 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5034 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
5036 boost::shared_ptr<AutomationList> alist (arv->audio_region()->envelope());
5037 XMLNode& before (alist->get_state());
5039 arv->audio_region()->set_default_envelope ();
5040 _session->add_command (new MementoCommand<AutomationList>(*arv->audio_region()->envelope().get(), &before, &alist->get_state()));
5044 _session->commit_reversible_command ();
5048 Editor::set_region_gain_visibility (RegionView* rv)
5050 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (rv);
5052 arv->update_envelope_visibility();
5057 Editor::set_gain_envelope_visibility ()
5063 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5064 AudioTimeAxisView* v = dynamic_cast<AudioTimeAxisView*>(*i);
5066 v->audio_view()->foreach_regionview (sigc::mem_fun (this, &Editor::set_region_gain_visibility));
5072 Editor::toggle_gain_envelope_active ()
5074 if (_ignore_region_action) {
5078 RegionSelection rs = get_regions_from_selection_and_entered ();
5080 if (!_session || rs.empty()) {
5084 _session->begin_reversible_command (_("region gain envelope active"));
5086 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5087 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
5089 arv->region()->clear_changes ();
5090 arv->audio_region()->set_envelope_active (!arv->audio_region()->envelope_active());
5091 _session->add_command (new StatefulDiffCommand (arv->region()));
5095 _session->commit_reversible_command ();
5099 Editor::toggle_region_lock ()
5101 if (_ignore_region_action) {
5105 RegionSelection rs = get_regions_from_selection_and_entered ();
5107 if (!_session || rs.empty()) {
5111 _session->begin_reversible_command (_("toggle region lock"));
5113 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5114 (*i)->region()->clear_changes ();
5115 (*i)->region()->set_locked (!(*i)->region()->locked());
5116 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5119 _session->commit_reversible_command ();
5123 Editor::toggle_region_video_lock ()
5125 if (_ignore_region_action) {
5129 RegionSelection rs = get_regions_from_selection_and_entered ();
5131 if (!_session || rs.empty()) {
5135 _session->begin_reversible_command (_("Toggle Video Lock"));
5137 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5138 (*i)->region()->clear_changes ();
5139 (*i)->region()->set_video_locked (!(*i)->region()->video_locked());
5140 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5143 _session->commit_reversible_command ();
5147 Editor::toggle_region_lock_style ()
5149 if (_ignore_region_action) {
5153 RegionSelection rs = get_regions_from_selection_and_entered ();
5155 if (!_session || rs.empty()) {
5159 _session->begin_reversible_command (_("region lock style"));
5161 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5162 (*i)->region()->clear_changes ();
5163 PositionLockStyle const ns = (*i)->region()->position_lock_style() == AudioTime ? MusicTime : AudioTime;
5164 (*i)->region()->set_position_lock_style (ns);
5165 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5168 _session->commit_reversible_command ();
5172 Editor::toggle_opaque_region ()
5174 if (_ignore_region_action) {
5178 RegionSelection rs = get_regions_from_selection_and_entered ();
5180 if (!_session || rs.empty()) {
5184 _session->begin_reversible_command (_("change region opacity"));
5186 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5187 (*i)->region()->clear_changes ();
5188 (*i)->region()->set_opaque (!(*i)->region()->opaque());
5189 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5192 _session->commit_reversible_command ();
5196 Editor::toggle_record_enable ()
5198 bool new_state = false;
5200 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5201 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5204 if (!rtav->is_track())
5208 new_state = !rtav->track()->record_enabled();
5212 rtav->track()->set_record_enabled (new_state, this);
5217 Editor::toggle_solo ()
5219 bool new_state = false;
5221 boost::shared_ptr<RouteList> rl (new RouteList);
5223 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5224 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5231 new_state = !rtav->route()->soloed ();
5235 rl->push_back (rtav->route());
5238 _session->set_solo (rl, new_state, Session::rt_cleanup, true);
5242 Editor::toggle_mute ()
5244 bool new_state = false;
5246 boost::shared_ptr<RouteList> rl (new RouteList);
5248 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5249 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5256 new_state = !rtav->route()->muted();
5260 rl->push_back (rtav->route());
5263 _session->set_mute (rl, new_state, Session::rt_cleanup, true);
5267 Editor::toggle_solo_isolate ()
5272 Editor::set_fade_length (bool in)
5274 RegionSelection rs = get_regions_from_selection_and_entered ();
5280 /* we need a region to measure the offset from the start */
5282 RegionView* rv = rs.front ();
5284 framepos_t pos = get_preferred_edit_position();
5288 if (pos > rv->region()->last_frame() || pos < rv->region()->first_frame()) {
5289 /* edit point is outside the relevant region */
5294 if (pos <= rv->region()->position()) {
5298 len = pos - rv->region()->position();
5299 cmd = _("set fade in length");
5301 if (pos >= rv->region()->last_frame()) {
5305 len = rv->region()->last_frame() - pos;
5306 cmd = _("set fade out length");
5309 begin_reversible_command (cmd);
5311 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5312 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5318 boost::shared_ptr<AutomationList> alist;
5320 alist = tmp->audio_region()->fade_in();
5322 alist = tmp->audio_region()->fade_out();
5325 XMLNode &before = alist->get_state();
5328 tmp->audio_region()->set_fade_in_length (len);
5329 tmp->audio_region()->set_fade_in_active (true);
5331 tmp->audio_region()->set_fade_out_length (len);
5332 tmp->audio_region()->set_fade_out_active (true);
5335 XMLNode &after = alist->get_state();
5336 _session->add_command(new MementoCommand<AutomationList>(*alist, &before, &after));
5339 commit_reversible_command ();
5343 Editor::set_fade_in_shape (FadeShape shape)
5345 RegionSelection rs = get_regions_from_selection_and_entered ();
5351 begin_reversible_command (_("set fade in shape"));
5353 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5354 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5360 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_in();
5361 XMLNode &before = alist->get_state();
5363 tmp->audio_region()->set_fade_in_shape (shape);
5365 XMLNode &after = alist->get_state();
5366 _session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
5369 commit_reversible_command ();
5374 Editor::set_fade_out_shape (FadeShape shape)
5376 RegionSelection rs = get_regions_from_selection_and_entered ();
5382 begin_reversible_command (_("set fade out shape"));
5384 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5385 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5391 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_out();
5392 XMLNode &before = alist->get_state();
5394 tmp->audio_region()->set_fade_out_shape (shape);
5396 XMLNode &after = alist->get_state();
5397 _session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
5400 commit_reversible_command ();
5404 Editor::set_fade_in_active (bool yn)
5406 RegionSelection rs = get_regions_from_selection_and_entered ();
5412 begin_reversible_command (_("set fade in active"));
5414 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5415 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5422 boost::shared_ptr<AudioRegion> ar (tmp->audio_region());
5424 ar->clear_changes ();
5425 ar->set_fade_in_active (yn);
5426 _session->add_command (new StatefulDiffCommand (ar));
5429 commit_reversible_command ();
5433 Editor::set_fade_out_active (bool yn)
5435 RegionSelection rs = get_regions_from_selection_and_entered ();
5441 begin_reversible_command (_("set fade out active"));
5443 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5444 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5450 boost::shared_ptr<AudioRegion> ar (tmp->audio_region());
5452 ar->clear_changes ();
5453 ar->set_fade_out_active (yn);
5454 _session->add_command(new StatefulDiffCommand (ar));
5457 commit_reversible_command ();
5461 Editor::toggle_region_fades (int dir)
5463 if (_ignore_region_action) {
5467 boost::shared_ptr<AudioRegion> ar;
5470 RegionSelection rs = get_regions_from_selection_and_entered ();
5476 RegionSelection::iterator i;
5477 for (i = rs.begin(); i != rs.end(); ++i) {
5478 if ((ar = boost::dynamic_pointer_cast<AudioRegion>((*i)->region())) != 0) {
5480 yn = ar->fade_out_active ();
5482 yn = ar->fade_in_active ();
5488 if (i == rs.end()) {
5492 /* XXX should this undo-able? */
5494 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5495 if ((ar = boost::dynamic_pointer_cast<AudioRegion>((*i)->region())) == 0) {
5498 if (dir == 1 || dir == 0) {
5499 ar->set_fade_in_active (!yn);
5502 if (dir == -1 || dir == 0) {
5503 ar->set_fade_out_active (!yn);
5509 /** Update region fade visibility after its configuration has been changed */
5511 Editor::update_region_fade_visibility ()
5513 bool _fade_visibility = _session->config.get_show_region_fades ();
5515 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5516 AudioTimeAxisView* v = dynamic_cast<AudioTimeAxisView*>(*i);
5518 if (_fade_visibility) {
5519 v->audio_view()->show_all_fades ();
5521 v->audio_view()->hide_all_fades ();
5528 Editor::set_edit_point ()
5533 if (!mouse_frame (where, ignored)) {
5539 if (selection->markers.empty()) {
5541 mouse_add_new_marker (where);
5546 Location* loc = find_location_from_marker (selection->markers.front(), ignored);
5549 loc->move_to (where);
5555 Editor::set_playhead_cursor ()
5557 if (entered_marker) {
5558 _session->request_locate (entered_marker->position(), _session->transport_rolling());
5563 if (!mouse_frame (where, ignored)) {
5570 _session->request_locate (where, _session->transport_rolling());
5574 if ( Config->get_always_play_range() )
5575 cancel_time_selection();
5579 Editor::split_region ()
5581 if ( !selection->time.empty()) {
5582 separate_regions_between (selection->time);
5586 RegionSelection rs = get_regions_from_selection_and_edit_point ();
5588 framepos_t where = get_preferred_edit_position ();
5594 split_regions_at (where, rs);
5597 struct EditorOrderRouteSorter {
5598 bool operator() (boost::shared_ptr<Route> a, boost::shared_ptr<Route> b) {
5599 return a->order_key () < b->order_key ();
5604 Editor::select_next_route()
5606 if (selection->tracks.empty()) {
5607 selection->set (track_views.front());
5611 TimeAxisView* current = selection->tracks.front();
5615 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5616 if (*i == current) {
5618 if (i != track_views.end()) {
5621 current = (*(track_views.begin()));
5622 //selection->set (*(track_views.begin()));
5627 rui = dynamic_cast<RouteUI *>(current);
5628 } while ( current->hidden() || (rui != NULL && !rui->route()->active()));
5630 selection->set(current);
5632 ensure_time_axis_view_is_visible (*current);
5636 Editor::select_prev_route()
5638 if (selection->tracks.empty()) {
5639 selection->set (track_views.front());
5643 TimeAxisView* current = selection->tracks.front();
5647 for (TrackViewList::reverse_iterator i = track_views.rbegin(); i != track_views.rend(); ++i) {
5648 if (*i == current) {
5650 if (i != track_views.rend()) {
5653 current = *(track_views.rbegin());
5658 rui = dynamic_cast<RouteUI *>(current);
5659 } while ( current->hidden() || (rui != NULL && !rui->route()->active()));
5661 selection->set (current);
5663 ensure_time_axis_view_is_visible (*current);
5667 Editor::set_loop_from_selection (bool play)
5669 if (_session == 0 || selection->time.empty()) {
5673 framepos_t start = selection->time[clicked_selection].start;
5674 framepos_t end = selection->time[clicked_selection].end;
5676 set_loop_range (start, end, _("set loop range from selection"));
5679 _session->request_play_loop (true);
5680 _session->request_locate (start, true);
5685 Editor::set_loop_from_edit_range (bool play)
5687 if (_session == 0) {
5694 if (!get_edit_op_range (start, end)) {
5698 set_loop_range (start, end, _("set loop range from edit range"));
5701 _session->request_play_loop (true);
5702 _session->request_locate (start, true);
5707 Editor::set_loop_from_region (bool play)
5709 framepos_t start = max_framepos;
5712 RegionSelection rs = get_regions_from_selection_and_entered ();
5718 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5719 if ((*i)->region()->position() < start) {
5720 start = (*i)->region()->position();
5722 if ((*i)->region()->last_frame() + 1 > end) {
5723 end = (*i)->region()->last_frame() + 1;
5727 set_loop_range (start, end, _("set loop range from region"));
5730 _session->request_play_loop (true);
5731 _session->request_locate (start, true);
5736 Editor::set_punch_from_selection ()
5738 if (_session == 0 || selection->time.empty()) {
5742 framepos_t start = selection->time[clicked_selection].start;
5743 framepos_t end = selection->time[clicked_selection].end;
5745 set_punch_range (start, end, _("set punch range from selection"));
5749 Editor::set_punch_from_edit_range ()
5751 if (_session == 0) {
5758 if (!get_edit_op_range (start, end)) {
5762 set_punch_range (start, end, _("set punch range from edit range"));
5766 Editor::set_punch_from_region ()
5768 framepos_t start = max_framepos;
5771 RegionSelection rs = get_regions_from_selection_and_entered ();
5777 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5778 if ((*i)->region()->position() < start) {
5779 start = (*i)->region()->position();
5781 if ((*i)->region()->last_frame() + 1 > end) {
5782 end = (*i)->region()->last_frame() + 1;
5786 set_punch_range (start, end, _("set punch range from region"));
5790 Editor::pitch_shift_region ()
5792 RegionSelection rs = get_regions_from_selection_and_entered ();
5794 RegionSelection audio_rs;
5795 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5796 if (dynamic_cast<AudioRegionView*> (*i)) {
5797 audio_rs.push_back (*i);
5801 if (audio_rs.empty()) {
5805 pitch_shift (audio_rs, 1.2);
5809 Editor::transpose_region ()
5811 RegionSelection rs = get_regions_from_selection_and_entered ();
5813 list<MidiRegionView*> midi_region_views;
5814 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5815 MidiRegionView* mrv = dynamic_cast<MidiRegionView*> (*i);
5817 midi_region_views.push_back (mrv);
5822 int const r = d.run ();
5823 if (r != RESPONSE_ACCEPT) {
5827 for (list<MidiRegionView*>::iterator i = midi_region_views.begin(); i != midi_region_views.end(); ++i) {
5828 (*i)->midi_region()->transpose (d.semitones ());
5833 Editor::set_tempo_from_region ()
5835 RegionSelection rs = get_regions_from_selection_and_entered ();
5837 if (!_session || rs.empty()) {
5841 RegionView* rv = rs.front();
5843 define_one_bar (rv->region()->position(), rv->region()->last_frame() + 1);
5847 Editor::use_range_as_bar ()
5849 framepos_t start, end;
5850 if (get_edit_op_range (start, end)) {
5851 define_one_bar (start, end);
5856 Editor::define_one_bar (framepos_t start, framepos_t end)
5858 framepos_t length = end - start;
5860 const Meter& m (_session->tempo_map().meter_at (start));
5862 /* length = 1 bar */
5864 /* now we want frames per beat.
5865 we have frames per bar, and beats per bar, so ...
5868 /* XXXX METER MATH */
5870 double frames_per_beat = length / m.divisions_per_bar();
5872 /* beats per minute = */
5874 double beats_per_minute = (_session->frame_rate() * 60.0) / frames_per_beat;
5876 /* now decide whether to:
5878 (a) set global tempo
5879 (b) add a new tempo marker
5883 const TempoSection& t (_session->tempo_map().tempo_section_at (start));
5885 bool do_global = false;
5887 if ((_session->tempo_map().n_tempos() == 1) && (_session->tempo_map().n_meters() == 1)) {
5889 /* only 1 tempo & 1 meter: ask if the user wants to set the tempo
5890 at the start, or create a new marker
5893 vector<string> options;
5894 options.push_back (_("Cancel"));
5895 options.push_back (_("Add new marker"));
5896 options.push_back (_("Set global tempo"));
5899 _("Define one bar"),
5900 _("Do you want to set the global tempo or add a new tempo marker?"),
5904 c.set_default_response (2);
5920 /* more than 1 tempo and/or meter section already, go ahead do the "usual":
5921 if the marker is at the region starter, change it, otherwise add
5926 begin_reversible_command (_("set tempo from region"));
5927 XMLNode& before (_session->tempo_map().get_state());
5930 _session->tempo_map().change_initial_tempo (beats_per_minute, t.note_type());
5931 } else if (t.frame() == start) {
5932 _session->tempo_map().change_existing_tempo_at (start, beats_per_minute, t.note_type());
5934 Timecode::BBT_Time bbt;
5935 _session->tempo_map().bbt_time (start, bbt);
5936 _session->tempo_map().add_tempo (Tempo (beats_per_minute, t.note_type()), bbt);
5939 XMLNode& after (_session->tempo_map().get_state());
5941 _session->add_command (new MementoCommand<TempoMap>(_session->tempo_map(), &before, &after));
5942 commit_reversible_command ();
5946 Editor::split_region_at_transients ()
5948 AnalysisFeatureList positions;
5950 RegionSelection rs = get_regions_from_selection_and_entered ();
5952 if (!_session || rs.empty()) {
5956 _session->begin_reversible_command (_("split regions"));
5958 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ) {
5960 RegionSelection::iterator tmp;
5965 boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion> ((*i)->region());
5967 if (ar && (ar->get_transients (positions) == 0)) {
5968 split_region_at_points ((*i)->region(), positions, true);
5975 _session->commit_reversible_command ();
5980 Editor::split_region_at_points (boost::shared_ptr<Region> r, AnalysisFeatureList& positions, bool can_ferret, bool select_new)
5982 bool use_rhythmic_rodent = false;
5984 boost::shared_ptr<Playlist> pl = r->playlist();
5986 list<boost::shared_ptr<Region> > new_regions;
5992 if (positions.empty()) {
5997 if (positions.size() > 20 && can_ferret) {
5998 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);
5999 MessageDialog msg (msgstr,
6002 Gtk::BUTTONS_OK_CANCEL);
6005 msg.add_button (_("Call for the Ferret!"), RESPONSE_APPLY);
6006 msg.set_secondary_text (_("Press OK to continue with this split operation\nor ask the Ferret dialog to tune the analysis"));
6008 msg.set_secondary_text (_("Press OK to continue with this split operation"));
6011 msg.set_title (_("Excessive split?"));
6014 int response = msg.run();
6020 case RESPONSE_APPLY:
6021 use_rhythmic_rodent = true;
6028 if (use_rhythmic_rodent) {
6029 show_rhythm_ferret ();
6033 AnalysisFeatureList::const_iterator x;
6035 pl->clear_changes ();
6036 pl->clear_owned_changes ();
6038 x = positions.begin();
6040 if (x == positions.end()) {
6045 pl->remove_region (r);
6049 while (x != positions.end()) {
6051 /* deal with positons that are out of scope of present region bounds */
6052 if (*x <= 0 || *x > r->length()) {
6057 /* file start = original start + how far we from the initial position ?
6060 framepos_t file_start = r->start() + pos;
6062 /* length = next position - current position
6065 framepos_t len = (*x) - pos;
6067 /* XXX we do we really want to allow even single-sample regions?
6068 shouldn't we have some kind of lower limit on region size?
6077 if (RegionFactory::region_name (new_name, r->name())) {
6081 /* do NOT announce new regions 1 by one, just wait till they are all done */
6085 plist.add (ARDOUR::Properties::start, file_start);
6086 plist.add (ARDOUR::Properties::length, len);
6087 plist.add (ARDOUR::Properties::name, new_name);
6088 plist.add (ARDOUR::Properties::layer, 0);
6090 boost::shared_ptr<Region> nr = RegionFactory::create (r->sources(), plist, false);
6091 /* because we set annouce to false, manually add the new region to the
6094 RegionFactory::map_add (nr);
6096 pl->add_region (nr, r->position() + pos);
6099 new_regions.push_front(nr);
6108 RegionFactory::region_name (new_name, r->name());
6110 /* Add the final region */
6113 plist.add (ARDOUR::Properties::start, r->start() + pos);
6114 plist.add (ARDOUR::Properties::length, r->last_frame() - (r->position() + pos) + 1);
6115 plist.add (ARDOUR::Properties::name, new_name);
6116 plist.add (ARDOUR::Properties::layer, 0);
6118 boost::shared_ptr<Region> nr = RegionFactory::create (r->sources(), plist, false);
6119 /* because we set annouce to false, manually add the new region to the
6122 RegionFactory::map_add (nr);
6123 pl->add_region (nr, r->position() + pos);
6126 new_regions.push_front(nr);
6131 /* We might have removed regions, which alters other regions' layering_index,
6132 so we need to do a recursive diff here.
6134 vector<Command*> cmds;
6136 _session->add_commands (cmds);
6138 _session->add_command (new StatefulDiffCommand (pl));
6142 for (list<boost::shared_ptr<Region> >::iterator i = new_regions.begin(); i != new_regions.end(); ++i){
6143 set_selected_regionview_from_region_list ((*i), Selection::Add);
6149 Editor::place_transient()
6155 RegionSelection rs = get_regions_from_selection_and_edit_point ();
6161 framepos_t where = get_preferred_edit_position();
6163 _session->begin_reversible_command (_("place transient"));
6165 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6166 framepos_t position = (*r)->region()->position();
6167 (*r)->region()->add_transient(where - position);
6170 _session->commit_reversible_command ();
6174 Editor::remove_transient(ArdourCanvas::Item* item)
6180 ArdourCanvas::Line* _line = reinterpret_cast<ArdourCanvas::Line*> (item);
6183 AudioRegionView* _arv = reinterpret_cast<AudioRegionView*> (item->get_data ("regionview"));
6184 _arv->remove_transient (*(float*) _line->get_data ("position"));
6188 Editor::snap_regions_to_grid ()
6190 list <boost::shared_ptr<Playlist > > used_playlists;
6192 RegionSelection rs = get_regions_from_selection_and_entered ();
6194 if (!_session || rs.empty()) {
6198 _session->begin_reversible_command (_("snap regions to grid"));
6200 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6202 boost::shared_ptr<Playlist> pl = (*r)->region()->playlist();
6204 if (!pl->frozen()) {
6205 /* we haven't seen this playlist before */
6207 /* remember used playlists so we can thaw them later */
6208 used_playlists.push_back(pl);
6212 framepos_t start_frame = (*r)->region()->first_frame ();
6213 snap_to (start_frame);
6214 (*r)->region()->set_position (start_frame);
6217 while (used_playlists.size() > 0) {
6218 list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
6220 used_playlists.pop_front();
6223 _session->commit_reversible_command ();
6227 Editor::close_region_gaps ()
6229 list <boost::shared_ptr<Playlist > > used_playlists;
6231 RegionSelection rs = get_regions_from_selection_and_entered ();
6233 if (!_session || rs.empty()) {
6237 Dialog dialog (_("Close Region Gaps"));
6240 table.set_spacings (12);
6241 table.set_border_width (12);
6242 Label* l = manage (left_aligned_label (_("Crossfade length")));
6243 table.attach (*l, 0, 1, 0, 1);
6245 SpinButton spin_crossfade (1, 0);
6246 spin_crossfade.set_range (0, 15);
6247 spin_crossfade.set_increments (1, 1);
6248 spin_crossfade.set_value (5);
6249 table.attach (spin_crossfade, 1, 2, 0, 1);
6251 table.attach (*manage (new Label (_("ms"))), 2, 3, 0, 1);
6253 l = manage (left_aligned_label (_("Pull-back length")));
6254 table.attach (*l, 0, 1, 1, 2);
6256 SpinButton spin_pullback (1, 0);
6257 spin_pullback.set_range (0, 100);
6258 spin_pullback.set_increments (1, 1);
6259 spin_pullback.set_value(30);
6260 table.attach (spin_pullback, 1, 2, 1, 2);
6262 table.attach (*manage (new Label (_("ms"))), 2, 3, 1, 2);
6264 dialog.get_vbox()->pack_start (table);
6265 dialog.add_button (Stock::CANCEL, RESPONSE_CANCEL);
6266 dialog.add_button (_("Ok"), RESPONSE_ACCEPT);
6269 if (dialog.run () == RESPONSE_CANCEL) {
6273 framepos_t crossfade_len = spin_crossfade.get_value();
6274 framepos_t pull_back_frames = spin_pullback.get_value();
6276 crossfade_len = lrintf (crossfade_len * _session->frame_rate()/1000);
6277 pull_back_frames = lrintf (pull_back_frames * _session->frame_rate()/1000);
6279 /* Iterate over the region list and make adjacent regions overlap by crossfade_len_ms */
6281 _session->begin_reversible_command (_("close region gaps"));
6284 boost::shared_ptr<Region> last_region;
6286 rs.sort_by_position_and_track();
6288 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6290 boost::shared_ptr<Playlist> pl = (*r)->region()->playlist();
6292 if (!pl->frozen()) {
6293 /* we haven't seen this playlist before */
6295 /* remember used playlists so we can thaw them later */
6296 used_playlists.push_back(pl);
6300 framepos_t position = (*r)->region()->position();
6302 if (idx == 0 || position < last_region->position()){
6303 last_region = (*r)->region();
6308 (*r)->region()->trim_front( (position - pull_back_frames));
6309 last_region->trim_end( (position - pull_back_frames + crossfade_len));
6311 last_region = (*r)->region();
6316 while (used_playlists.size() > 0) {
6317 list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
6319 used_playlists.pop_front();
6322 _session->commit_reversible_command ();
6326 Editor::tab_to_transient (bool forward)
6328 AnalysisFeatureList positions;
6330 RegionSelection rs = get_regions_from_selection_and_entered ();
6336 framepos_t pos = _session->audible_frame ();
6338 if (!selection->tracks.empty()) {
6340 /* don't waste time searching for transients in duplicate playlists.
6343 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
6345 for (TrackViewList::iterator t = ts.begin(); t != ts.end(); ++t) {
6347 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*t);
6350 boost::shared_ptr<Track> tr = rtv->track();
6352 boost::shared_ptr<Playlist> pl = tr->playlist ();
6354 framepos_t result = pl->find_next_transient (pos, forward ? 1 : -1);
6357 positions.push_back (result);
6370 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6371 (*r)->region()->get_transients (positions);
6375 TransientDetector::cleanup_transients (positions, _session->frame_rate(), 3.0);
6378 AnalysisFeatureList::iterator x;
6380 for (x = positions.begin(); x != positions.end(); ++x) {
6386 if (x != positions.end ()) {
6387 _session->request_locate (*x);
6391 AnalysisFeatureList::reverse_iterator x;
6393 for (x = positions.rbegin(); x != positions.rend(); ++x) {
6399 if (x != positions.rend ()) {
6400 _session->request_locate (*x);
6406 Editor::playhead_forward_to_grid ()
6412 framepos_t pos = playhead_cursor->current_frame ();
6413 if (pos < max_framepos - 1) {
6415 snap_to_internal (pos, 1, false);
6416 _session->request_locate (pos);
6422 Editor::playhead_backward_to_grid ()
6428 framepos_t pos = playhead_cursor->current_frame ();
6431 snap_to_internal (pos, -1, false);
6432 _session->request_locate (pos);
6437 Editor::set_track_height (Height h)
6439 TrackSelection& ts (selection->tracks);
6441 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
6442 (*x)->set_height_enum (h);
6447 Editor::toggle_tracks_active ()
6449 TrackSelection& ts (selection->tracks);
6451 bool target = false;
6457 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
6458 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*x);
6462 target = !rtv->_route->active();
6465 rtv->_route->set_active (target, this);
6471 Editor::remove_tracks ()
6473 TrackSelection& ts (selection->tracks);
6479 vector<string> choices;
6483 const char* trackstr;
6485 vector<boost::shared_ptr<Route> > routes;
6486 bool special_bus = false;
6488 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
6489 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*x);
6493 if (rtv->is_track()) {
6498 routes.push_back (rtv->_route);
6500 if (rtv->route()->is_master() || rtv->route()->is_monitor()) {
6505 if (special_bus && !Config->get_allow_special_bus_removal()) {
6506 MessageDialog msg (_("That would be bad news ...."),
6510 msg.set_secondary_text (string_compose (_(
6511 "Removing the master or monitor bus is such a bad idea\n\
6512 that %1 is not going to allow it.\n\
6514 If you really want to do this sort of thing\n\
6515 edit your ardour.rc file to set the\n\
6516 \"allow-special-bus-removal\" option to be \"yes\""), PROGRAM_NAME));
6523 if (ntracks + nbusses == 0) {
6528 trackstr = _("tracks");
6530 trackstr = _("track");
6534 busstr = _("busses");
6541 prompt = string_compose (_("Do you really want to remove %1 %2 and %3 %4?\n"
6542 "(You may also lose the playlists associated with the %2)\n\n"
6543 "This action cannot be undone, and the session file will be overwritten!"),
6544 ntracks, trackstr, nbusses, busstr);
6546 prompt = string_compose (_("Do you really want to remove %1 %2?\n"
6547 "(You may also lose the playlists associated with the %2)\n\n"
6548 "This action cannot be undone, and the session file will be overwritten!"),
6551 } else if (nbusses) {
6552 prompt = string_compose (_("Do you really want to remove %1 %2?\n\n"
6553 "This action cannot be undon, and the session file will be overwritten"),
6557 choices.push_back (_("No, do nothing."));
6558 if (ntracks + nbusses > 1) {
6559 choices.push_back (_("Yes, remove them."));
6561 choices.push_back (_("Yes, remove it."));
6566 title = string_compose (_("Remove %1"), trackstr);
6568 title = string_compose (_("Remove %1"), busstr);
6571 Choice prompter (title, prompt, choices);
6573 if (prompter.run () != 1) {
6578 Session::StateProtector sp (_session);
6579 for (vector<boost::shared_ptr<Route> >::iterator x = routes.begin(); x != routes.end(); ++x) {
6580 _session->remove_route (*x);
6586 Editor::do_insert_time ()
6588 if (selection->tracks.empty()) {
6592 InsertTimeDialog d (*this);
6593 int response = d.run ();
6595 if (response != RESPONSE_OK) {
6599 if (d.distance() == 0) {
6603 InsertTimeOption opt = d.intersected_region_action ();
6606 get_preferred_edit_position(),
6612 d.move_glued_markers(),
6613 d.move_locked_markers(),
6619 Editor::insert_time (
6620 framepos_t pos, framecnt_t frames, InsertTimeOption opt,
6621 bool all_playlists, bool ignore_music_glue, bool markers_too, bool glued_markers_too, bool locked_markers_too, bool tempo_too
6624 bool commit = false;
6626 if (Config->get_edit_mode() == Lock) {
6630 begin_reversible_command (_("insert time"));
6632 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
6634 for (TrackViewList::iterator x = ts.begin(); x != ts.end(); ++x) {
6638 /* don't operate on any playlist more than once, which could
6639 * happen if "all playlists" is enabled, but there is more
6640 * than 1 track using playlists "from" a given track.
6643 set<boost::shared_ptr<Playlist> > pl;
6645 if (all_playlists) {
6646 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*x);
6648 vector<boost::shared_ptr<Playlist> > all = _session->playlists->playlists_for_track (rtav->track ());
6649 for (vector<boost::shared_ptr<Playlist> >::iterator p = all.begin(); p != all.end(); ++p) {
6654 if ((*x)->playlist ()) {
6655 pl.insert ((*x)->playlist ());
6659 for (set<boost::shared_ptr<Playlist> >::iterator i = pl.begin(); i != pl.end(); ++i) {
6661 (*i)->clear_changes ();
6662 (*i)->clear_owned_changes ();
6664 if (opt == SplitIntersected) {
6668 (*i)->shift (pos, frames, (opt == MoveIntersected), ignore_music_glue);
6670 vector<Command*> cmds;
6672 _session->add_commands (cmds);
6674 _session->add_command (new StatefulDiffCommand (*i));
6679 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*x);
6681 rtav->route ()->shift (pos, frames);
6689 XMLNode& before (_session->locations()->get_state());
6690 Locations::LocationList copy (_session->locations()->list());
6692 for (Locations::LocationList::iterator i = copy.begin(); i != copy.end(); ++i) {
6694 Locations::LocationList::const_iterator tmp;
6696 bool const was_locked = (*i)->locked ();
6697 if (locked_markers_too) {
6701 if ((*i)->position_lock_style() == AudioTime || glued_markers_too) {
6703 if ((*i)->start() >= pos) {
6704 (*i)->set_start ((*i)->start() + frames);
6705 if (!(*i)->is_mark()) {
6706 (*i)->set_end ((*i)->end() + frames);
6719 XMLNode& after (_session->locations()->get_state());
6720 _session->add_command (new MementoCommand<Locations>(*_session->locations(), &before, &after));
6725 _session->tempo_map().insert_time (pos, frames);
6729 commit_reversible_command ();
6734 Editor::fit_selected_tracks ()
6736 if (!selection->tracks.empty()) {
6737 fit_tracks (selection->tracks);
6741 /* no selected tracks - use tracks with selected regions */
6743 if (!selection->regions.empty()) {
6744 for (RegionSelection::iterator r = selection->regions.begin(); r != selection->regions.end(); ++r) {
6745 tvl.push_back (&(*r)->get_time_axis_view ());
6751 } else if (internal_editing()) {
6752 /* no selected tracks, or regions, but in internal edit mode, so follow the mouse and use
6755 if (entered_track) {
6756 tvl.push_back (entered_track);
6764 Editor::fit_tracks (TrackViewList & tracks)
6766 if (tracks.empty()) {
6770 uint32_t child_heights = 0;
6771 int visible_tracks = 0;
6773 for (TrackSelection::iterator t = tracks.begin(); t != tracks.end(); ++t) {
6775 if (!(*t)->marked_for_display()) {
6779 child_heights += (*t)->effective_height() - (*t)->current_height();
6783 /* compute the per-track height from:
6785 total canvas visible height -
6786 height that will be taken by visible children of selected
6787 tracks - height of the ruler/hscroll area
6789 uint32_t h = (uint32_t) floor ((_visible_canvas_height - (child_heights + _trackview_group->canvas_origin().y)) / visible_tracks);
6790 double first_y_pos = DBL_MAX;
6792 if (h < TimeAxisView::preset_height (HeightSmall)) {
6793 MessageDialog msg (*this, _("There are too many tracks to fit in the current window"));
6794 /* too small to be displayed */
6798 undo_visual_stack.push_back (current_visual_state (true));
6799 no_save_visual = true;
6801 /* build a list of all tracks, including children */
6804 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
6806 TimeAxisView::Children c = (*i)->get_child_list ();
6807 for (TimeAxisView::Children::iterator j = c.begin(); j != c.end(); ++j) {
6808 all.push_back (j->get());
6812 /* operate on all tracks, hide unselected ones that are in the middle of selected ones */
6814 bool within_selected = false;
6816 for (TrackViewList::iterator t = all.begin(); t != all.end(); ++t) {
6818 TrackViewList::iterator next;
6823 if ((*t)->marked_for_display ()) {
6824 if (tracks.contains (*t)) {
6825 (*t)->set_height (h);
6826 first_y_pos = std::min ((*t)->y_position (), first_y_pos);
6827 within_selected = true;
6828 } else if (within_selected) {
6829 hide_track_in_display (*t);
6835 set the controls_layout height now, because waiting for its size
6836 request signal handler will cause the vertical adjustment setting to fail
6839 controls_layout.property_height () = _full_canvas_height;
6840 vertical_adjustment.set_value (first_y_pos);
6842 redo_visual_stack.push_back (current_visual_state (true));
6846 Editor::save_visual_state (uint32_t n)
6848 while (visual_states.size() <= n) {
6849 visual_states.push_back (0);
6852 if (visual_states[n] != 0) {
6853 delete visual_states[n];
6856 visual_states[n] = current_visual_state (true);
6861 Editor::goto_visual_state (uint32_t n)
6863 if (visual_states.size() <= n) {
6867 if (visual_states[n] == 0) {
6871 use_visual_state (*visual_states[n]);
6875 Editor::start_visual_state_op (uint32_t n)
6877 save_visual_state (n);
6879 PopUp* pup = new PopUp (WIN_POS_MOUSE, 1000, true);
6881 snprintf (buf, sizeof (buf), _("Saved view %u"), n+1);
6882 pup->set_text (buf);
6887 Editor::cancel_visual_state_op (uint32_t n)
6889 goto_visual_state (n);
6893 Editor::toggle_region_mute ()
6895 if (_ignore_region_action) {
6899 RegionSelection rs = get_regions_from_selection_and_entered ();
6905 if (rs.size() > 1) {
6906 begin_reversible_command (_("mute regions"));
6908 begin_reversible_command (_("mute region"));
6911 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
6913 (*i)->region()->playlist()->clear_changes ();
6914 (*i)->region()->set_muted (!(*i)->region()->muted ());
6915 _session->add_command (new StatefulDiffCommand ((*i)->region()->playlist()));
6919 commit_reversible_command ();
6923 Editor::combine_regions ()
6925 /* foreach track with selected regions, take all selected regions
6926 and join them into a new region containing the subregions (as a
6930 typedef set<RouteTimeAxisView*> RTVS;
6933 if (selection->regions.empty()) {
6937 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
6938 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(&(*i)->get_time_axis_view());
6941 tracks.insert (rtv);
6945 begin_reversible_command (_("combine regions"));
6947 vector<RegionView*> new_selection;
6949 for (RTVS::iterator i = tracks.begin(); i != tracks.end(); ++i) {
6952 if ((rv = (*i)->combine_regions ()) != 0) {
6953 new_selection.push_back (rv);
6957 selection->clear_regions ();
6958 for (vector<RegionView*>::iterator i = new_selection.begin(); i != new_selection.end(); ++i) {
6959 selection->add (*i);
6962 commit_reversible_command ();
6966 Editor::uncombine_regions ()
6968 typedef set<RouteTimeAxisView*> RTVS;
6971 if (selection->regions.empty()) {
6975 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
6976 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(&(*i)->get_time_axis_view());
6979 tracks.insert (rtv);
6983 begin_reversible_command (_("uncombine regions"));
6985 for (RTVS::iterator i = tracks.begin(); i != tracks.end(); ++i) {
6986 (*i)->uncombine_regions ();
6989 commit_reversible_command ();
6993 Editor::toggle_midi_input_active (bool flip_others)
6996 boost::shared_ptr<RouteList> rl (new RouteList);
6998 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
6999 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
7005 boost::shared_ptr<MidiTrack> mt = rtav->midi_track();
7008 rl->push_back (rtav->route());
7009 onoff = !mt->input_active();
7013 _session->set_exclusive_input_active (rl, onoff, flip_others);
7020 lock_dialog = new Gtk::Dialog (string_compose (_("%1: Locked"), PROGRAM_NAME), true);
7022 Gtk::Image* padlock = manage (new Gtk::Image (ARDOUR_UI_UTILS::get_icon ("padlock_closed")));
7023 lock_dialog->get_vbox()->pack_start (*padlock);
7025 ArdourButton* b = manage (new ArdourButton);
7026 b->set_name ("lock button");
7027 b->set_markup (string_compose ("<span size=\"large\" weight=\"bold\">%1</span>", _("Click to unlock")));
7028 b->signal_clicked.connect (sigc::mem_fun (*this, &Editor::unlock));
7029 lock_dialog->get_vbox()->pack_start (*b);
7031 lock_dialog->get_vbox()->show_all ();
7032 lock_dialog->set_size_request (200, 200);
7036 /* The global menu bar continues to be accessible to applications
7037 with modal dialogs, which means that we need to desensitize
7038 all items in the menu bar. Since those items are really just
7039 proxies for actions, that means disabling all actions.
7041 ActionManager::disable_all_actions ();
7043 lock_dialog->present ();
7049 lock_dialog->hide ();
7052 ActionManager::pop_action_state ();
7055 if (ARDOUR_UI::config()->get_lock_gui_after_seconds()) {
7056 start_lock_event_timing ();