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);
2114 Editor::insert_region_list_selection (float times)
2116 RouteTimeAxisView *tv = 0;
2117 boost::shared_ptr<Playlist> playlist;
2119 if (clicked_routeview != 0) {
2120 tv = clicked_routeview;
2121 } else if (!selection->tracks.empty()) {
2122 if ((tv = dynamic_cast<RouteTimeAxisView*>(selection->tracks.front())) == 0) {
2125 } else if (entered_track != 0) {
2126 if ((tv = dynamic_cast<RouteTimeAxisView*>(entered_track)) == 0) {
2133 if ((playlist = tv->playlist()) == 0) {
2137 boost::shared_ptr<Region> region = _regions->get_single_selection ();
2142 begin_reversible_command (_("insert region"));
2143 playlist->clear_changes ();
2144 playlist->add_region ((RegionFactory::create (region, true)), get_preferred_edit_position(), times);
2145 _session->add_command(new StatefulDiffCommand (playlist));
2146 commit_reversible_command ();
2149 /* BUILT-IN EFFECTS */
2152 Editor::reverse_selection ()
2157 /* GAIN ENVELOPE EDITING */
2160 Editor::edit_envelope ()
2167 Editor::transition_to_rolling (bool fwd)
2173 if (_session->config.get_external_sync()) {
2174 switch (Config->get_sync_source()) {
2178 /* transport controlled by the master */
2183 if (_session->is_auditioning()) {
2184 _session->cancel_audition ();
2188 _session->request_transport_speed (fwd ? 1.0f : -1.0f);
2192 Editor::play_from_start ()
2194 _session->request_locate (_session->current_start_frame(), true);
2198 Editor::play_from_edit_point ()
2200 _session->request_locate (get_preferred_edit_position(), true);
2204 Editor::play_from_edit_point_and_return ()
2206 framepos_t start_frame;
2207 framepos_t return_frame;
2209 start_frame = get_preferred_edit_position (true);
2211 if (_session->transport_rolling()) {
2212 _session->request_locate (start_frame, false);
2216 /* don't reset the return frame if its already set */
2218 if ((return_frame = _session->requested_return_frame()) < 0) {
2219 return_frame = _session->audible_frame();
2222 if (start_frame >= 0) {
2223 _session->request_roll_at_and_return (start_frame, return_frame);
2228 Editor::play_selection ()
2230 if (selection->time.empty()) {
2234 _session->request_play_range (&selection->time, true);
2238 Editor::get_preroll ()
2240 return 1.0 /*Config->get_edit_preroll_seconds()*/ * _session->frame_rate();
2245 Editor::maybe_locate_with_edit_preroll ( framepos_t location )
2247 if ( _session->transport_rolling() || !Config->get_always_play_range() )
2250 location -= get_preroll();
2252 //don't try to locate before the beginning of time
2256 //if follow_playhead is on, keep the playhead on the screen
2257 if ( _follow_playhead )
2258 if ( location < leftmost_frame )
2259 location = leftmost_frame;
2261 _session->request_locate( location );
2265 Editor::play_with_preroll ()
2267 if (selection->time.empty()) {
2270 framepos_t preroll = get_preroll();
2272 framepos_t start = 0;
2273 if (selection->time[clicked_selection].start > preroll)
2274 start = selection->time[clicked_selection].start - preroll;
2276 framepos_t end = selection->time[clicked_selection].end + preroll;
2278 AudioRange ar (start, end, 0);
2279 list<AudioRange> lar;
2282 _session->request_play_range (&lar, true);
2287 Editor::play_location (Location& location)
2289 if (location.start() <= location.end()) {
2293 _session->request_bounded_roll (location.start(), location.end());
2297 Editor::loop_location (Location& location)
2299 if (location.start() <= location.end()) {
2305 if ((tll = transport_loop_location()) != 0) {
2306 tll->set (location.start(), location.end());
2308 // enable looping, reposition and start rolling
2309 _session->request_play_loop (true);
2310 _session->request_locate (tll->start(), true);
2315 Editor::do_layer_operation (LayerOperation op)
2317 if (selection->regions.empty ()) {
2321 bool const multiple = selection->regions.size() > 1;
2325 begin_reversible_command (_("raise regions"));
2327 begin_reversible_command (_("raise region"));
2333 begin_reversible_command (_("raise regions to top"));
2335 begin_reversible_command (_("raise region to top"));
2341 begin_reversible_command (_("lower regions"));
2343 begin_reversible_command (_("lower region"));
2349 begin_reversible_command (_("lower regions to bottom"));
2351 begin_reversible_command (_("lower region"));
2356 set<boost::shared_ptr<Playlist> > playlists = selection->regions.playlists ();
2357 for (set<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
2358 (*i)->clear_owned_changes ();
2361 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
2362 boost::shared_ptr<Region> r = (*i)->region ();
2374 r->lower_to_bottom ();
2378 for (set<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
2379 vector<Command*> cmds;
2381 _session->add_commands (cmds);
2384 commit_reversible_command ();
2388 Editor::raise_region ()
2390 do_layer_operation (Raise);
2394 Editor::raise_region_to_top ()
2396 do_layer_operation (RaiseToTop);
2400 Editor::lower_region ()
2402 do_layer_operation (Lower);
2406 Editor::lower_region_to_bottom ()
2408 do_layer_operation (LowerToBottom);
2411 /** Show the region editor for the selected regions */
2413 Editor::show_region_properties ()
2415 selection->foreach_regionview (&RegionView::show_region_editor);
2418 /** Show the midi list editor for the selected MIDI regions */
2420 Editor::show_midi_list_editor ()
2422 selection->foreach_midi_regionview (&MidiRegionView::show_list_editor);
2426 Editor::rename_region ()
2428 RegionSelection rs = get_regions_from_selection_and_entered ();
2434 ArdourDialog d (*this, _("Rename Region"), true, false);
2436 Label label (_("New name:"));
2439 hbox.set_spacing (6);
2440 hbox.pack_start (label, false, false);
2441 hbox.pack_start (entry, true, true);
2443 d.get_vbox()->set_border_width (12);
2444 d.get_vbox()->pack_start (hbox, false, false);
2446 d.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
2447 d.add_button(Gtk::Stock::OK, Gtk::RESPONSE_OK);
2449 d.set_size_request (300, -1);
2451 entry.set_text (rs.front()->region()->name());
2452 entry.select_region (0, -1);
2454 entry.signal_activate().connect (sigc::bind (sigc::mem_fun (d, &Dialog::response), RESPONSE_OK));
2460 int const ret = d.run();
2464 if (ret != RESPONSE_OK) {
2468 std::string str = entry.get_text();
2469 strip_whitespace_edges (str);
2471 rs.front()->region()->set_name (str);
2472 _regions->redisplay ();
2477 Editor::audition_playlist_region_via_route (boost::shared_ptr<Region> region, Route& route)
2479 if (_session->is_auditioning()) {
2480 _session->cancel_audition ();
2483 // note: some potential for creativity here, because region doesn't
2484 // have to belong to the playlist that Route is handling
2486 // bool was_soloed = route.soloed();
2488 route.set_solo (true, this);
2490 _session->request_bounded_roll (region->position(), region->position() + region->length());
2492 /* XXX how to unset the solo state ? */
2495 /** Start an audition of the first selected region */
2497 Editor::play_edit_range ()
2499 framepos_t start, end;
2501 if (get_edit_op_range (start, end)) {
2502 _session->request_bounded_roll (start, end);
2507 Editor::play_selected_region ()
2509 framepos_t start = max_framepos;
2512 RegionSelection rs = get_regions_from_selection_and_entered ();
2518 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
2519 if ((*i)->region()->position() < start) {
2520 start = (*i)->region()->position();
2522 if ((*i)->region()->last_frame() + 1 > end) {
2523 end = (*i)->region()->last_frame() + 1;
2527 _session->request_bounded_roll (start, end);
2531 Editor::audition_playlist_region_standalone (boost::shared_ptr<Region> region)
2533 _session->audition_region (region);
2537 Editor::region_from_selection ()
2539 if (clicked_axisview == 0) {
2543 if (selection->time.empty()) {
2547 framepos_t start = selection->time[clicked_selection].start;
2548 framepos_t end = selection->time[clicked_selection].end;
2550 TrackViewList tracks = get_tracks_for_range_action ();
2552 framepos_t selection_cnt = end - start + 1;
2554 for (TrackSelection::iterator i = tracks.begin(); i != tracks.end(); ++i) {
2555 boost::shared_ptr<Region> current;
2556 boost::shared_ptr<Playlist> pl;
2557 framepos_t internal_start;
2560 if ((pl = (*i)->playlist()) == 0) {
2564 if ((current = pl->top_region_at (start)) == 0) {
2568 internal_start = start - current->position();
2569 RegionFactory::region_name (new_name, current->name(), true);
2573 plist.add (ARDOUR::Properties::start, current->start() + internal_start);
2574 plist.add (ARDOUR::Properties::length, selection_cnt);
2575 plist.add (ARDOUR::Properties::name, new_name);
2576 plist.add (ARDOUR::Properties::layer, 0);
2578 boost::shared_ptr<Region> region (RegionFactory::create (current, plist));
2583 Editor::create_region_from_selection (vector<boost::shared_ptr<Region> >& new_regions)
2585 if (selection->time.empty() || selection->tracks.empty()) {
2589 framepos_t start = selection->time[clicked_selection].start;
2590 framepos_t end = selection->time[clicked_selection].end;
2592 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
2593 sort_track_selection (ts);
2595 for (TrackSelection::iterator i = ts.begin(); i != ts.end(); ++i) {
2596 boost::shared_ptr<Region> current;
2597 boost::shared_ptr<Playlist> playlist;
2598 framepos_t internal_start;
2601 if ((playlist = (*i)->playlist()) == 0) {
2605 if ((current = playlist->top_region_at(start)) == 0) {
2609 internal_start = start - current->position();
2610 RegionFactory::region_name (new_name, current->name(), true);
2614 plist.add (ARDOUR::Properties::start, current->start() + internal_start);
2615 plist.add (ARDOUR::Properties::length, end - start + 1);
2616 plist.add (ARDOUR::Properties::name, new_name);
2618 new_regions.push_back (RegionFactory::create (current, plist));
2623 Editor::split_multichannel_region ()
2625 RegionSelection rs = get_regions_from_selection_and_entered ();
2631 vector< boost::shared_ptr<Region> > v;
2633 for (list<RegionView*>::iterator x = rs.begin(); x != rs.end(); ++x) {
2634 (*x)->region()->separate_by_channel (*_session, v);
2639 Editor::new_region_from_selection ()
2641 region_from_selection ();
2642 cancel_selection ();
2646 add_if_covered (RegionView* rv, const AudioRange* ar, RegionSelection* rs)
2648 switch (rv->region()->coverage (ar->start, ar->end - 1)) {
2649 case Evoral::OverlapNone:
2657 * - selected tracks, or if there are none...
2658 * - tracks containing selected regions, or if there are none...
2663 Editor::get_tracks_for_range_action () const
2667 if (selection->tracks.empty()) {
2669 /* use tracks with selected regions */
2671 RegionSelection rs = selection->regions;
2673 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
2674 TimeAxisView* tv = &(*i)->get_time_axis_view();
2676 if (!t.contains (tv)) {
2682 /* no regions and no tracks: use all tracks */
2688 t = selection->tracks;
2691 return t.filter_to_unique_playlists();
2695 Editor::separate_regions_between (const TimeSelection& ts)
2697 bool in_command = false;
2698 boost::shared_ptr<Playlist> playlist;
2699 RegionSelection new_selection;
2701 TrackViewList tmptracks = get_tracks_for_range_action ();
2702 sort_track_selection (tmptracks);
2704 for (TrackSelection::iterator i = tmptracks.begin(); i != tmptracks.end(); ++i) {
2706 RouteTimeAxisView* rtv;
2708 if ((rtv = dynamic_cast<RouteTimeAxisView*> ((*i))) != 0) {
2710 if (rtv->is_track()) {
2712 /* no edits to destructive tracks */
2714 if (rtv->track()->destructive()) {
2718 if ((playlist = rtv->playlist()) != 0) {
2720 playlist->clear_changes ();
2722 /* XXX need to consider musical time selections here at some point */
2724 double speed = rtv->track()->speed();
2727 for (list<AudioRange>::const_iterator t = ts.begin(); t != ts.end(); ++t) {
2729 sigc::connection c = rtv->view()->RegionViewAdded.connect (
2730 sigc::mem_fun(*this, &Editor::collect_new_region_view));
2732 latest_regionviews.clear ();
2734 playlist->partition ((framepos_t)((*t).start * speed),
2735 (framepos_t)((*t).end * speed), false);
2739 if (!latest_regionviews.empty()) {
2741 rtv->view()->foreach_regionview (sigc::bind (
2742 sigc::ptr_fun (add_if_covered),
2743 &(*t), &new_selection));
2746 begin_reversible_command (_("separate"));
2750 /* pick up changes to existing regions */
2752 vector<Command*> cmds;
2753 playlist->rdiff (cmds);
2754 _session->add_commands (cmds);
2756 /* pick up changes to the playlist itself (adds/removes)
2759 _session->add_command(new StatefulDiffCommand (playlist));
2768 selection->set (new_selection);
2769 set_mouse_mode (MouseObject);
2771 commit_reversible_command ();
2775 struct PlaylistState {
2776 boost::shared_ptr<Playlist> playlist;
2780 /** Take tracks from get_tracks_for_range_action and cut any regions
2781 * on those tracks so that the tracks are empty over the time
2785 Editor::separate_region_from_selection ()
2787 /* preferentially use *all* ranges in the time selection if we're in range mode
2788 to allow discontiguous operation, since get_edit_op_range() currently
2789 returns a single range.
2792 if (!selection->time.empty()) {
2794 separate_regions_between (selection->time);
2801 if (get_edit_op_range (start, end)) {
2803 AudioRange ar (start, end, 1);
2807 separate_regions_between (ts);
2813 Editor::separate_region_from_punch ()
2815 Location* loc = _session->locations()->auto_punch_location();
2817 separate_regions_using_location (*loc);
2822 Editor::separate_region_from_loop ()
2824 Location* loc = _session->locations()->auto_loop_location();
2826 separate_regions_using_location (*loc);
2831 Editor::separate_regions_using_location (Location& loc)
2833 if (loc.is_mark()) {
2837 AudioRange ar (loc.start(), loc.end(), 1);
2842 separate_regions_between (ts);
2845 /** Separate regions under the selected region */
2847 Editor::separate_under_selected_regions ()
2849 vector<PlaylistState> playlists;
2853 rs = get_regions_from_selection_and_entered();
2855 if (!_session || rs.empty()) {
2859 begin_reversible_command (_("separate region under"));
2861 list<boost::shared_ptr<Region> > regions_to_remove;
2863 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
2864 // we can't just remove the region(s) in this loop because
2865 // this removes them from the RegionSelection, and they thus
2866 // disappear from underneath the iterator, and the ++i above
2867 // SEGVs in a puzzling fashion.
2869 // so, first iterate over the regions to be removed from rs and
2870 // add them to the regions_to_remove list, and then
2871 // iterate over the list to actually remove them.
2873 regions_to_remove.push_back ((*i)->region());
2876 for (list<boost::shared_ptr<Region> >::iterator rl = regions_to_remove.begin(); rl != regions_to_remove.end(); ++rl) {
2878 boost::shared_ptr<Playlist> playlist = (*rl)->playlist();
2881 // is this check necessary?
2885 vector<PlaylistState>::iterator i;
2887 //only take state if this is a new playlist.
2888 for (i = playlists.begin(); i != playlists.end(); ++i) {
2889 if ((*i).playlist == playlist) {
2894 if (i == playlists.end()) {
2896 PlaylistState before;
2897 before.playlist = playlist;
2898 before.before = &playlist->get_state();
2900 playlist->freeze ();
2901 playlists.push_back(before);
2904 //Partition on the region bounds
2905 playlist->partition ((*rl)->first_frame() - 1, (*rl)->last_frame() + 1, true);
2907 //Re-add region that was just removed due to the partition operation
2908 playlist->add_region( (*rl), (*rl)->first_frame() );
2911 vector<PlaylistState>::iterator pl;
2913 for (pl = playlists.begin(); pl != playlists.end(); ++pl) {
2914 (*pl).playlist->thaw ();
2915 _session->add_command(new MementoCommand<Playlist>(*(*pl).playlist, (*pl).before, &(*pl).playlist->get_state()));
2918 commit_reversible_command ();
2922 Editor::crop_region_to_selection ()
2924 if (!selection->time.empty()) {
2926 crop_region_to (selection->time.start(), selection->time.end_frame());
2933 if (get_edit_op_range (start, end)) {
2934 crop_region_to (start, end);
2941 Editor::crop_region_to (framepos_t start, framepos_t end)
2943 vector<boost::shared_ptr<Playlist> > playlists;
2944 boost::shared_ptr<Playlist> playlist;
2947 if (selection->tracks.empty()) {
2948 ts = track_views.filter_to_unique_playlists();
2950 ts = selection->tracks.filter_to_unique_playlists ();
2953 sort_track_selection (ts);
2955 for (TrackSelection::iterator i = ts.begin(); i != ts.end(); ++i) {
2957 RouteTimeAxisView* rtv;
2959 if ((rtv = dynamic_cast<RouteTimeAxisView*> ((*i))) != 0) {
2961 boost::shared_ptr<Track> t = rtv->track();
2963 if (t != 0 && ! t->destructive()) {
2965 if ((playlist = rtv->playlist()) != 0) {
2966 playlists.push_back (playlist);
2972 if (playlists.empty()) {
2976 framepos_t the_start;
2980 begin_reversible_command (_("trim to selection"));
2982 for (vector<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
2984 boost::shared_ptr<Region> region;
2988 if ((region = (*i)->top_region_at(the_start)) == 0) {
2992 /* now adjust lengths to that we do the right thing
2993 if the selection extends beyond the region
2996 the_start = max (the_start, (framepos_t) region->position());
2997 if (max_framepos - the_start < region->length()) {
2998 the_end = the_start + region->length() - 1;
3000 the_end = max_framepos;
3002 the_end = min (end, the_end);
3003 cnt = the_end - the_start + 1;
3005 region->clear_changes ();
3006 region->trim_to (the_start, cnt);
3007 _session->add_command (new StatefulDiffCommand (region));
3010 commit_reversible_command ();
3014 Editor::region_fill_track ()
3016 RegionSelection rs = get_regions_from_selection_and_entered ();
3018 if (!_session || rs.empty()) {
3022 framepos_t const end = _session->current_end_frame ();
3024 begin_reversible_command (Operations::region_fill);
3026 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3028 boost::shared_ptr<Region> region ((*i)->region());
3030 boost::shared_ptr<Playlist> pl = region->playlist();
3032 if (end <= region->last_frame()) {
3036 double times = (double) (end - region->last_frame()) / (double) region->length();
3042 pl->clear_changes ();
3043 pl->add_region (RegionFactory::create (region, true), region->last_frame(), times);
3044 _session->add_command (new StatefulDiffCommand (pl));
3047 commit_reversible_command ();
3051 Editor::region_fill_selection ()
3053 if (clicked_routeview == 0 || !clicked_routeview->is_audio_track()) {
3057 if (selection->time.empty()) {
3061 boost::shared_ptr<Region> region = _regions->get_single_selection ();
3066 framepos_t start = selection->time[clicked_selection].start;
3067 framepos_t end = selection->time[clicked_selection].end;
3069 boost::shared_ptr<Playlist> playlist;
3071 if (selection->tracks.empty()) {
3075 framepos_t selection_length = end - start;
3076 float times = (float)selection_length / region->length();
3078 begin_reversible_command (Operations::fill_selection);
3080 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
3082 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
3084 if ((playlist = (*i)->playlist()) == 0) {
3088 playlist->clear_changes ();
3089 playlist->add_region (RegionFactory::create (region, true), start, times);
3090 _session->add_command (new StatefulDiffCommand (playlist));
3093 commit_reversible_command ();
3097 Editor::set_region_sync_position ()
3099 set_sync_point (get_preferred_edit_position (), get_regions_from_selection_and_edit_point ());
3103 Editor::set_sync_point (framepos_t where, const RegionSelection& rs)
3105 bool in_command = false;
3107 for (RegionSelection::const_iterator r = rs.begin(); r != rs.end(); ++r) {
3109 if (!(*r)->region()->covers (where)) {
3113 boost::shared_ptr<Region> region ((*r)->region());
3116 begin_reversible_command (_("set sync point"));
3120 region->clear_changes ();
3121 region->set_sync_position (where);
3122 _session->add_command(new StatefulDiffCommand (region));
3126 commit_reversible_command ();
3130 /** Remove the sync positions of the selection */
3132 Editor::remove_region_sync ()
3134 RegionSelection rs = get_regions_from_selection_and_entered ();
3140 begin_reversible_command (_("remove region sync"));
3142 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3144 (*i)->region()->clear_changes ();
3145 (*i)->region()->clear_sync_position ();
3146 _session->add_command(new StatefulDiffCommand ((*i)->region()));
3149 commit_reversible_command ();
3153 Editor::naturalize_region ()
3155 RegionSelection rs = get_regions_from_selection_and_entered ();
3161 if (rs.size() > 1) {
3162 begin_reversible_command (_("move regions to original position"));
3164 begin_reversible_command (_("move region to original position"));
3167 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3168 (*i)->region()->clear_changes ();
3169 (*i)->region()->move_to_natural_position ();
3170 _session->add_command (new StatefulDiffCommand ((*i)->region()));
3173 commit_reversible_command ();
3177 Editor::align_regions (RegionPoint what)
3179 RegionSelection const rs = get_regions_from_selection_and_edit_point ();
3185 begin_reversible_command (_("align selection"));
3187 framepos_t const position = get_preferred_edit_position ();
3189 for (RegionSelection::const_iterator i = rs.begin(); i != rs.end(); ++i) {
3190 align_region_internal ((*i)->region(), what, position);
3193 commit_reversible_command ();
3196 struct RegionSortByTime {
3197 bool operator() (const RegionView* a, const RegionView* b) {
3198 return a->region()->position() < b->region()->position();
3203 Editor::align_regions_relative (RegionPoint point)
3205 RegionSelection const rs = get_regions_from_selection_and_edit_point ();
3211 framepos_t const position = get_preferred_edit_position ();
3213 framepos_t distance = 0;
3217 list<RegionView*> sorted;
3218 rs.by_position (sorted);
3220 boost::shared_ptr<Region> r ((*sorted.begin())->region());
3225 if (position > r->position()) {
3226 distance = position - r->position();
3228 distance = r->position() - position;
3234 if (position > r->last_frame()) {
3235 distance = position - r->last_frame();
3236 pos = r->position() + distance;
3238 distance = r->last_frame() - position;
3239 pos = r->position() - distance;
3245 pos = r->adjust_to_sync (position);
3246 if (pos > r->position()) {
3247 distance = pos - r->position();
3249 distance = r->position() - pos;
3255 if (pos == r->position()) {
3259 begin_reversible_command (_("align selection (relative)"));
3261 /* move first one specially */
3263 r->clear_changes ();
3264 r->set_position (pos);
3265 _session->add_command(new StatefulDiffCommand (r));
3267 /* move rest by the same amount */
3271 for (list<RegionView*>::iterator i = sorted.begin(); i != sorted.end(); ++i) {
3273 boost::shared_ptr<Region> region ((*i)->region());
3275 region->clear_changes ();
3278 region->set_position (region->position() + distance);
3280 region->set_position (region->position() - distance);
3283 _session->add_command(new StatefulDiffCommand (region));
3287 commit_reversible_command ();
3291 Editor::align_region (boost::shared_ptr<Region> region, RegionPoint point, framepos_t position)
3293 begin_reversible_command (_("align region"));
3294 align_region_internal (region, point, position);
3295 commit_reversible_command ();
3299 Editor::align_region_internal (boost::shared_ptr<Region> region, RegionPoint point, framepos_t position)
3301 region->clear_changes ();
3305 region->set_position (region->adjust_to_sync (position));
3309 if (position > region->length()) {
3310 region->set_position (position - region->length());
3315 region->set_position (position);
3319 _session->add_command(new StatefulDiffCommand (region));
3323 Editor::trim_region_front ()
3329 Editor::trim_region_back ()
3331 trim_region (false);
3335 Editor::trim_region (bool front)
3337 framepos_t where = get_preferred_edit_position();
3338 RegionSelection rs = get_regions_from_selection_and_edit_point ();
3344 begin_reversible_command (front ? _("trim front") : _("trim back"));
3346 for (list<RegionView*>::const_iterator i = rs.by_layer().begin(); i != rs.by_layer().end(); ++i) {
3347 if (!(*i)->region()->locked()) {
3349 (*i)->region()->clear_changes ();
3352 (*i)->region()->trim_front (where);
3353 maybe_locate_with_edit_preroll ( where );
3355 (*i)->region()->trim_end (where);
3356 maybe_locate_with_edit_preroll ( where );
3359 _session->add_command (new StatefulDiffCommand ((*i)->region()));
3363 commit_reversible_command ();
3366 /** Trim the end of the selected regions to the position of the edit cursor */
3368 Editor::trim_region_to_loop ()
3370 Location* loc = _session->locations()->auto_loop_location();
3374 trim_region_to_location (*loc, _("trim to loop"));
3378 Editor::trim_region_to_punch ()
3380 Location* loc = _session->locations()->auto_punch_location();
3384 trim_region_to_location (*loc, _("trim to punch"));
3388 Editor::trim_region_to_location (const Location& loc, const char* str)
3390 RegionSelection rs = get_regions_from_selection_and_entered ();
3392 begin_reversible_command (str);
3394 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
3395 RegionView* rv = (*x);
3397 /* require region to span proposed trim */
3398 switch (rv->region()->coverage (loc.start(), loc.end())) {
3399 case Evoral::OverlapInternal:
3405 RouteTimeAxisView* tav = dynamic_cast<RouteTimeAxisView*> (&rv->get_time_axis_view());
3414 if (tav->track() != 0) {
3415 speed = tav->track()->speed();
3418 start = session_frame_to_track_frame (loc.start(), speed);
3419 end = session_frame_to_track_frame (loc.end(), speed);
3421 rv->region()->clear_changes ();
3422 rv->region()->trim_to (start, (end - start));
3423 _session->add_command(new StatefulDiffCommand (rv->region()));
3426 commit_reversible_command ();
3430 Editor::trim_region_to_previous_region_end ()
3432 return trim_to_region(false);
3436 Editor::trim_region_to_next_region_start ()
3438 return trim_to_region(true);
3442 Editor::trim_to_region(bool forward)
3444 RegionSelection rs = get_regions_from_selection_and_entered ();
3446 begin_reversible_command (_("trim to region"));
3448 boost::shared_ptr<Region> next_region;
3450 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
3452 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*x);
3458 AudioTimeAxisView* atav = dynamic_cast<AudioTimeAxisView*> (&arv->get_time_axis_view());
3466 if (atav->track() != 0) {
3467 speed = atav->track()->speed();
3471 boost::shared_ptr<Region> region = arv->region();
3472 boost::shared_ptr<Playlist> playlist (region->playlist());
3474 region->clear_changes ();
3478 next_region = playlist->find_next_region (region->first_frame(), Start, 1);
3484 region->trim_end((framepos_t) ( (next_region->first_frame() - 1) * speed));
3485 arv->region_changed (PropertyChange (ARDOUR::Properties::length));
3489 next_region = playlist->find_next_region (region->first_frame(), Start, 0);
3495 region->trim_front((framepos_t) ((next_region->last_frame() + 1) * speed));
3497 arv->region_changed (ARDOUR::bounds_change);
3500 _session->add_command(new StatefulDiffCommand (region));
3503 commit_reversible_command ();
3507 Editor::unfreeze_route ()
3509 if (clicked_routeview == 0 || !clicked_routeview->is_track()) {
3513 clicked_routeview->track()->unfreeze ();
3517 Editor::_freeze_thread (void* arg)
3519 return static_cast<Editor*>(arg)->freeze_thread ();
3523 Editor::freeze_thread ()
3525 /* create event pool because we may need to talk to the session */
3526 SessionEvent::create_per_thread_pool ("freeze events", 64);
3527 /* create per-thread buffers for process() tree to use */
3528 clicked_routeview->audio_track()->freeze_me (*current_interthread_info);
3529 current_interthread_info->done = true;
3534 Editor::freeze_route ()
3540 /* stop transport before we start. this is important */
3542 _session->request_transport_speed (0.0);
3544 /* wait for just a little while, because the above call is asynchronous */
3546 Glib::usleep (250000);
3548 if (clicked_routeview == 0 || !clicked_routeview->is_audio_track()) {
3552 if (!clicked_routeview->track()->bounceable (clicked_routeview->track()->main_outs(), true)) {
3554 _("This track/bus cannot be frozen because the signal adds or loses channels before reaching the outputs.\n"
3555 "This is typically caused by plugins that generate stereo output from mono input or vice versa.")
3557 d.set_title (_("Cannot freeze"));
3562 if (clicked_routeview->track()->has_external_redirects()) {
3563 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"
3564 "Freezing will only process the signal as far as the first send/insert/return."),
3565 clicked_routeview->track()->name()), true, MESSAGE_INFO, BUTTONS_NONE, true);
3567 d.add_button (_("Freeze anyway"), Gtk::RESPONSE_OK);
3568 d.add_button (_("Don't freeze"), Gtk::RESPONSE_CANCEL);
3569 d.set_title (_("Freeze Limits"));
3571 int response = d.run ();
3574 case Gtk::RESPONSE_CANCEL:
3581 InterThreadInfo itt;
3582 current_interthread_info = &itt;
3584 InterthreadProgressWindow ipw (current_interthread_info, _("Freeze"), _("Cancel Freeze"));
3586 pthread_create_and_store (X_("freezer"), &itt.thread, _freeze_thread, this);
3588 set_canvas_cursor (_cursors->wait);
3590 while (!itt.done && !itt.cancel) {
3591 gtk_main_iteration ();
3594 current_interthread_info = 0;
3595 set_canvas_cursor (current_canvas_cursor);
3599 Editor::bounce_range_selection (bool replace, bool enable_processing)
3601 if (selection->time.empty()) {
3605 TrackSelection views = selection->tracks;
3607 for (TrackViewList::iterator i = views.begin(); i != views.end(); ++i) {
3609 if (enable_processing) {
3611 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*i);
3613 if (rtv && rtv->track() && replace && enable_processing && !rtv->track()->bounceable (rtv->track()->main_outs(), false)) {
3615 _("You can't perform this operation because the processing of the signal "
3616 "will cause one or more of the tracks to end up with a region with more channels than this track has inputs.\n\n"
3617 "You can do this without processing, which is a different operation.")
3619 d.set_title (_("Cannot bounce"));
3626 framepos_t start = selection->time[clicked_selection].start;
3627 framepos_t end = selection->time[clicked_selection].end;
3628 framepos_t cnt = end - start + 1;
3630 begin_reversible_command (_("bounce range"));
3632 for (TrackViewList::iterator i = views.begin(); i != views.end(); ++i) {
3634 RouteTimeAxisView* rtv;
3636 if ((rtv = dynamic_cast<RouteTimeAxisView*> (*i)) == 0) {
3640 boost::shared_ptr<Playlist> playlist;
3642 if ((playlist = rtv->playlist()) == 0) {
3646 InterThreadInfo itt;
3648 playlist->clear_changes ();
3649 playlist->clear_owned_changes ();
3651 boost::shared_ptr<Region> r;
3653 if (enable_processing) {
3654 r = rtv->track()->bounce_range (start, start+cnt, itt, rtv->track()->main_outs(), false);
3656 r = rtv->track()->bounce_range (start, start+cnt, itt, boost::shared_ptr<Processor>(), false);
3664 list<AudioRange> ranges;
3665 ranges.push_back (AudioRange (start, start+cnt, 0));
3666 playlist->cut (ranges); // discard result
3667 playlist->add_region (r, start);
3670 vector<Command*> cmds;
3671 playlist->rdiff (cmds);
3672 _session->add_commands (cmds);
3674 _session->add_command (new StatefulDiffCommand (playlist));
3677 commit_reversible_command ();
3680 /** Delete selected regions, automation points or a time range */
3687 /** Cut selected regions, automation points or a time range */
3694 /** Copy selected regions, automation points or a time range */
3702 /** @return true if a Cut, Copy or Clear is possible */
3704 Editor::can_cut_copy () const
3706 switch (effective_mouse_mode()) {
3709 if (!selection->regions.empty() || !selection->points.empty()) {
3715 if (!selection->time.empty()) {
3728 /** Cut, copy or clear selected regions, automation points or a time range.
3729 * @param op Operation (Cut, Copy or Clear)
3732 Editor::cut_copy (CutCopyOp op)
3734 /* only cancel selection if cut/copy is successful.*/
3740 opname = _("delete");
3749 opname = _("clear");
3753 /* if we're deleting something, and the mouse is still pressed,
3754 the thing we started a drag for will be gone when we release
3755 the mouse button(s). avoid this. see part 2 at the end of
3759 if (op == Delete || op == Cut || op == Clear) {
3760 if (_drags->active ()) {
3765 if ( op != Clear ) //"Delete" doesn't change copy/paste buf
3766 cut_buffer->clear ();
3768 if (entered_marker) {
3770 /* cut/delete op while pointing at a marker */
3773 Location* loc = find_location_from_marker (entered_marker, ignored);
3775 if (_session && loc) {
3776 Glib::signal_idle().connect (sigc::bind (sigc::mem_fun(*this, &Editor::really_remove_marker), loc));
3783 if (internal_editing()) {
3785 switch (effective_mouse_mode()) {
3788 begin_reversible_command (opname + ' ' + X_("MIDI"));
3790 commit_reversible_command ();
3799 bool did_edit = false;
3801 switch (effective_mouse_mode()) {
3803 if (!selection->points.empty()) {
3804 begin_reversible_command (opname + _(" points"));
3806 cut_copy_points (op);
3807 if (op == Cut || op == Delete) {
3808 selection->clear_points ();
3815 if (!selection->regions.empty() || !selection->points.empty()) {
3819 if (selection->regions.empty()) {
3820 thing_name = _("points");
3821 } else if (selection->points.empty()) {
3822 thing_name = _("regions");
3824 thing_name = _("objects");
3827 begin_reversible_command (opname + ' ' + thing_name);
3830 if (!selection->regions.empty()) {
3831 cut_copy_regions (op, selection->regions);
3833 if (op == Cut || op == Delete) {
3834 selection->clear_regions ();
3838 if (!selection->points.empty()) {
3839 cut_copy_points (op);
3841 if (op == Cut || op == Delete) {
3842 selection->clear_points ();
3849 if (selection->time.empty()) {
3850 framepos_t start, end;
3851 /* no time selection, see if we can get an edit range
3854 if (get_edit_op_range (start, end)) {
3855 selection->set (start, end);
3858 if (!selection->time.empty()) {
3859 begin_reversible_command (opname + _(" range"));
3862 cut_copy_ranges (op);
3864 if (op == Cut || op == Delete) {
3865 selection->clear_time ();
3875 commit_reversible_command ();
3878 if (op == Delete || op == Cut || op == Clear) {
3883 struct AutomationRecord {
3884 AutomationRecord () : state (0) {}
3885 AutomationRecord (XMLNode* s) : state (s) {}
3887 XMLNode* state; ///< state before any operation
3888 boost::shared_ptr<Evoral::ControlList> copy; ///< copied events for the cut buffer
3891 /** Cut, copy or clear selected automation points.
3892 * @param op Operation (Cut, Copy or Clear)
3895 Editor::cut_copy_points (CutCopyOp op)
3897 if (selection->points.empty ()) {
3901 /* XXX: not ideal, as there may be more than one track involved in the point selection */
3902 _last_cut_copy_source_track = &selection->points.front()->line().trackview;
3904 /* Keep a record of the AutomationLists that we end up using in this operation */
3905 typedef std::map<boost::shared_ptr<AutomationList>, AutomationRecord> Lists;
3908 /* Go through all selected points, making an AutomationRecord for each distinct AutomationList */
3909 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
3910 boost::shared_ptr<AutomationList> al = (*i)->line().the_list();
3911 if (lists.find (al) == lists.end ()) {
3912 /* We haven't seen this list yet, so make a record for it. This includes
3913 taking a copy of its current state, in case this is needed for undo later.
3915 lists[al] = AutomationRecord (&al->get_state ());
3919 if (op == Cut || op == Copy) {
3920 /* This operation will involve putting things in the cut buffer, so create an empty
3921 ControlList for each of our source lists to put the cut buffer data in.
3923 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
3924 i->second.copy = i->first->create (i->first->parameter ());
3927 /* Add all selected points to the relevant copy ControlLists */
3928 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
3929 boost::shared_ptr<AutomationList> al = (*i)->line().the_list();
3930 AutomationList::const_iterator j = (*i)->model ();
3931 lists[al].copy->add ((*j)->when, (*j)->value);
3934 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
3935 /* Correct this copy list so that it starts at time 0 */
3936 double const start = i->second.copy->front()->when;
3937 for (AutomationList::iterator j = i->second.copy->begin(); j != i->second.copy->end(); ++j) {
3938 (*j)->when -= start;
3941 /* And add it to the cut buffer */
3942 cut_buffer->add (i->second.copy);
3946 if (op == Delete || op == Cut) {
3947 /* This operation needs to remove things from the main AutomationList, so do that now */
3949 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
3950 i->first->freeze ();
3953 /* Remove each selected point from its AutomationList */
3954 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
3955 boost::shared_ptr<AutomationList> al = (*i)->line().the_list();
3956 al->erase ((*i)->model ());
3959 /* Thaw the lists and add undo records for them */
3960 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
3961 boost::shared_ptr<AutomationList> al = i->first;
3963 _session->add_command (new MementoCommand<AutomationList> (*al.get(), i->second.state, &(al->get_state ())));
3968 /** Cut, copy or clear selected automation points.
3969 * @param op Operation (Cut, Copy or Clear)
3972 Editor::cut_copy_midi (CutCopyOp op)
3974 for (MidiRegionSelection::iterator i = selection->midi_regions.begin(); i != selection->midi_regions.end(); ++i) {
3975 MidiRegionView* mrv = *i;
3976 mrv->cut_copy_clear (op);
3982 struct lt_playlist {
3983 bool operator () (const PlaylistState& a, const PlaylistState& b) {
3984 return a.playlist < b.playlist;
3988 struct PlaylistMapping {
3990 boost::shared_ptr<Playlist> pl;
3992 PlaylistMapping (TimeAxisView* tvp) : tv (tvp) {}
3995 /** Remove `clicked_regionview' */
3997 Editor::remove_clicked_region ()
3999 if (clicked_routeview == 0 || clicked_regionview == 0) {
4003 boost::shared_ptr<Playlist> playlist = clicked_routeview->playlist();
4005 begin_reversible_command (_("remove region"));
4006 playlist->clear_changes ();
4007 playlist->clear_owned_changes ();
4008 playlist->remove_region (clicked_regionview->region());
4010 /* We might have removed regions, which alters other regions' layering_index,
4011 so we need to do a recursive diff here.
4013 vector<Command*> cmds;
4014 playlist->rdiff (cmds);
4015 _session->add_commands (cmds);
4017 _session->add_command(new StatefulDiffCommand (playlist));
4018 commit_reversible_command ();
4022 /** Remove the selected regions */
4024 Editor::remove_selected_regions ()
4026 RegionSelection rs = get_regions_from_selection_and_entered ();
4028 if (!_session || rs.empty()) {
4032 begin_reversible_command (_("remove region"));
4034 list<boost::shared_ptr<Region> > regions_to_remove;
4036 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
4037 // we can't just remove the region(s) in this loop because
4038 // this removes them from the RegionSelection, and they thus
4039 // disappear from underneath the iterator, and the ++i above
4040 // SEGVs in a puzzling fashion.
4042 // so, first iterate over the regions to be removed from rs and
4043 // add them to the regions_to_remove list, and then
4044 // iterate over the list to actually remove them.
4046 regions_to_remove.push_back ((*i)->region());
4049 vector<boost::shared_ptr<Playlist> > playlists;
4051 for (list<boost::shared_ptr<Region> >::iterator rl = regions_to_remove.begin(); rl != regions_to_remove.end(); ++rl) {
4053 boost::shared_ptr<Playlist> playlist = (*rl)->playlist();
4056 // is this check necessary?
4060 /* get_regions_from_selection_and_entered() guarantees that
4061 the playlists involved are unique, so there is no need
4065 playlists.push_back (playlist);
4067 playlist->clear_changes ();
4068 playlist->clear_owned_changes ();
4069 playlist->freeze ();
4070 playlist->remove_region (*rl);
4073 vector<boost::shared_ptr<Playlist> >::iterator pl;
4075 for (pl = playlists.begin(); pl != playlists.end(); ++pl) {
4078 /* We might have removed regions, which alters other regions' layering_index,
4079 so we need to do a recursive diff here.
4081 vector<Command*> cmds;
4082 (*pl)->rdiff (cmds);
4083 _session->add_commands (cmds);
4085 _session->add_command(new StatefulDiffCommand (*pl));
4088 commit_reversible_command ();
4091 /** Cut, copy or clear selected regions.
4092 * @param op Operation (Cut, Copy or Clear)
4095 Editor::cut_copy_regions (CutCopyOp op, RegionSelection& rs)
4097 /* we can't use a std::map here because the ordering is important, and we can't trivially sort
4098 a map when we want ordered access to both elements. i think.
4101 vector<PlaylistMapping> pmap;
4103 framepos_t first_position = max_framepos;
4105 typedef set<boost::shared_ptr<Playlist> > FreezeList;
4106 FreezeList freezelist;
4108 /* get ordering correct before we cut/copy */
4110 rs.sort_by_position_and_track ();
4112 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
4114 first_position = min ((framepos_t) (*x)->region()->position(), first_position);
4116 if (op == Cut || op == Clear || op == Delete) {
4117 boost::shared_ptr<Playlist> pl = (*x)->region()->playlist();
4120 FreezeList::iterator fl;
4122 // only take state if this is a new playlist.
4123 for (fl = freezelist.begin(); fl != freezelist.end(); ++fl) {
4129 if (fl == freezelist.end()) {
4130 pl->clear_changes();
4131 pl->clear_owned_changes ();
4133 freezelist.insert (pl);
4138 TimeAxisView* tv = &(*x)->get_time_axis_view();
4139 vector<PlaylistMapping>::iterator z;
4141 for (z = pmap.begin(); z != pmap.end(); ++z) {
4142 if ((*z).tv == tv) {
4147 if (z == pmap.end()) {
4148 pmap.push_back (PlaylistMapping (tv));
4152 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ) {
4154 boost::shared_ptr<Playlist> pl = (*x)->region()->playlist();
4157 /* region not yet associated with a playlist (e.g. unfinished
4164 TimeAxisView& tv = (*x)->get_time_axis_view();
4165 boost::shared_ptr<Playlist> npl;
4166 RegionSelection::iterator tmp;
4173 vector<PlaylistMapping>::iterator z;
4175 for (z = pmap.begin(); z != pmap.end(); ++z) {
4176 if ((*z).tv == &tv) {
4181 assert (z != pmap.end());
4184 npl = PlaylistFactory::create (pl->data_type(), *_session, "cutlist", true);
4192 boost::shared_ptr<Region> r = (*x)->region();
4193 boost::shared_ptr<Region> _xx;
4199 pl->remove_region (r);
4203 _xx = RegionFactory::create (r);
4204 npl->add_region (_xx, r->position() - first_position);
4205 pl->remove_region (r);
4209 /* copy region before adding, so we're not putting same object into two different playlists */
4210 npl->add_region (RegionFactory::create (r), r->position() - first_position);
4214 pl->remove_region (r);
4223 list<boost::shared_ptr<Playlist> > foo;
4225 /* the pmap is in the same order as the tracks in which selected regions occured */
4227 for (vector<PlaylistMapping>::iterator i = pmap.begin(); i != pmap.end(); ++i) {
4230 foo.push_back ((*i).pl);
4235 cut_buffer->set (foo);
4239 _last_cut_copy_source_track = 0;
4241 _last_cut_copy_source_track = pmap.front().tv;
4245 for (FreezeList::iterator pl = freezelist.begin(); pl != freezelist.end(); ++pl) {
4248 /* We might have removed regions, which alters other regions' layering_index,
4249 so we need to do a recursive diff here.
4251 vector<Command*> cmds;
4252 (*pl)->rdiff (cmds);
4253 _session->add_commands (cmds);
4255 _session->add_command (new StatefulDiffCommand (*pl));
4260 Editor::cut_copy_ranges (CutCopyOp op)
4262 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4264 /* Sort the track selection now, so that it if is used, the playlists
4265 selected by the calls below to cut_copy_clear are in the order that
4266 their tracks appear in the editor. This makes things like paste
4267 of ranges work properly.
4270 sort_track_selection (ts);
4273 if (!entered_track) {
4276 ts.push_back (entered_track);
4279 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4280 (*i)->cut_copy_clear (*selection, op);
4285 Editor::paste (float times, bool from_context)
4287 DEBUG_TRACE (DEBUG::CutNPaste, "paste to preferred edit pos\n");
4289 paste_internal (get_preferred_edit_position (false, from_context), times);
4293 Editor::mouse_paste ()
4298 if (!mouse_frame (where, ignored)) {
4303 paste_internal (where, 1);
4307 Editor::paste_internal (framepos_t position, float times)
4309 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("apparent paste position is %1\n", position));
4311 if (internal_editing()) {
4312 if (cut_buffer->midi_notes.empty()) {
4316 if (cut_buffer->empty()) {
4321 if (position == max_framepos) {
4322 position = get_preferred_edit_position();
4323 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("preferred edit position is %1\n", position));
4327 TrackViewList::iterator i;
4330 /* get everything in the correct order */
4332 if (_edit_point == Editing::EditAtMouse && entered_track) {
4333 /* With the mouse edit point, paste onto the track under the mouse */
4334 ts.push_back (entered_track);
4335 } else if (!selection->tracks.empty()) {
4336 /* Otherwise, if there are some selected tracks, paste to them */
4337 ts = selection->tracks.filter_to_unique_playlists ();
4338 sort_track_selection (ts);
4339 } else if (_last_cut_copy_source_track) {
4340 /* Otherwise paste to the track that the cut/copy came from;
4341 see discussion in mantis #3333.
4343 ts.push_back (_last_cut_copy_source_track);
4346 if (internal_editing ()) {
4348 /* undo/redo is handled by individual tracks/regions */
4350 for (nth = 0, i = ts.begin(); i != ts.end(); ++i, ++nth) {
4353 RegionSelection::iterator r;
4354 MidiNoteSelection::iterator cb;
4356 get_regions_at (rs, position, ts);
4358 for (cb = cut_buffer->midi_notes.begin(), r = rs.begin();
4359 cb != cut_buffer->midi_notes.end() && r != rs.end(); ++r) {
4360 MidiRegionView* mrv = dynamic_cast<MidiRegionView*> (*r);
4362 mrv->paste (position, times, **cb);
4370 /* we do redo (do you do voodoo?) */
4372 begin_reversible_command (Operations::paste);
4374 for (nth = 0, i = ts.begin(); i != ts.end(); ++i, ++nth) {
4375 (*i)->paste (position, times, *cut_buffer, nth);
4378 commit_reversible_command ();
4383 Editor::duplicate_some_regions (RegionSelection& regions, float times)
4385 boost::shared_ptr<Playlist> playlist;
4386 RegionSelection sel = regions; // clear (below) may clear the argument list if its the current region selection
4387 RegionSelection foo;
4389 framepos_t const start_frame = regions.start ();
4390 framepos_t const end_frame = regions.end_frame ();
4392 begin_reversible_command (Operations::duplicate_region);
4394 selection->clear_regions ();
4396 for (RegionSelection::iterator i = sel.begin(); i != sel.end(); ++i) {
4398 boost::shared_ptr<Region> r ((*i)->region());
4400 TimeAxisView& tv = (*i)->get_time_axis_view();
4401 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (&tv);
4402 latest_regionviews.clear ();
4403 sigc::connection c = rtv->view()->RegionViewAdded.connect (sigc::mem_fun(*this, &Editor::collect_new_region_view));
4405 playlist = (*i)->region()->playlist();
4406 playlist->clear_changes ();
4407 playlist->duplicate (r, end_frame + (r->first_frame() - start_frame), times);
4408 _session->add_command(new StatefulDiffCommand (playlist));
4412 foo.insert (foo.end(), latest_regionviews.begin(), latest_regionviews.end());
4415 commit_reversible_command ();
4418 selection->set (foo);
4423 Editor::duplicate_selection (float times)
4425 if (selection->time.empty() || selection->tracks.empty()) {
4429 boost::shared_ptr<Playlist> playlist;
4430 vector<boost::shared_ptr<Region> > new_regions;
4431 vector<boost::shared_ptr<Region> >::iterator ri;
4433 create_region_from_selection (new_regions);
4435 if (new_regions.empty()) {
4439 begin_reversible_command (_("duplicate selection"));
4441 ri = new_regions.begin();
4443 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4445 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4446 if ((playlist = (*i)->playlist()) == 0) {
4449 playlist->clear_changes ();
4450 playlist->duplicate (*ri, selection->time[clicked_selection].end, times);
4451 _session->add_command (new StatefulDiffCommand (playlist));
4454 if (ri == new_regions.end()) {
4459 commit_reversible_command ();
4462 /** Reset all selected points to the relevant default value */
4464 Editor::reset_point_selection ()
4466 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
4467 ARDOUR::AutomationList::iterator j = (*i)->model ();
4468 (*j)->value = (*i)->line().the_list()->default_value ();
4473 Editor::center_playhead ()
4475 float const page = _visible_canvas_width * samples_per_pixel;
4476 center_screen_internal (playhead_cursor->current_frame (), page);
4480 Editor::center_edit_point ()
4482 float const page = _visible_canvas_width * samples_per_pixel;
4483 center_screen_internal (get_preferred_edit_position(), page);
4486 /** Caller must begin and commit a reversible command */
4488 Editor::clear_playlist (boost::shared_ptr<Playlist> playlist)
4490 playlist->clear_changes ();
4492 _session->add_command (new StatefulDiffCommand (playlist));
4496 Editor::nudge_track (bool use_edit, bool forwards)
4498 boost::shared_ptr<Playlist> playlist;
4499 framepos_t distance;
4500 framepos_t next_distance;
4504 start = get_preferred_edit_position();
4509 if ((distance = get_nudge_distance (start, next_distance)) == 0) {
4513 if (selection->tracks.empty()) {
4517 begin_reversible_command (_("nudge track"));
4519 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4521 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4523 if ((playlist = (*i)->playlist()) == 0) {
4527 playlist->clear_changes ();
4528 playlist->clear_owned_changes ();
4530 playlist->nudge_after (start, distance, forwards);
4532 vector<Command*> cmds;
4534 playlist->rdiff (cmds);
4535 _session->add_commands (cmds);
4537 _session->add_command (new StatefulDiffCommand (playlist));
4540 commit_reversible_command ();
4544 Editor::remove_last_capture ()
4546 vector<string> choices;
4553 if (Config->get_verify_remove_last_capture()) {
4554 prompt = _("Do you really want to destroy the last capture?"
4555 "\n(This is destructive and cannot be undone)");
4557 choices.push_back (_("No, do nothing."));
4558 choices.push_back (_("Yes, destroy it."));
4560 Gtkmm2ext::Choice prompter (_("Destroy last capture"), prompt, choices);
4562 if (prompter.run () == 1) {
4563 _session->remove_last_capture ();
4564 _regions->redisplay ();
4568 _session->remove_last_capture();
4569 _regions->redisplay ();
4574 Editor::normalize_region ()
4580 RegionSelection rs = get_regions_from_selection_and_entered ();
4586 NormalizeDialog dialog (rs.size() > 1);
4588 if (dialog.run () == RESPONSE_CANCEL) {
4592 set_canvas_cursor (_cursors->wait);
4595 /* XXX: should really only count audio regions here */
4596 int const regions = rs.size ();
4598 /* Make a list of the selected audio regions' maximum amplitudes, and also
4599 obtain the maximum amplitude of them all.
4601 list<double> max_amps;
4603 for (RegionSelection::const_iterator i = rs.begin(); i != rs.end(); ++i) {
4604 AudioRegionView const * arv = dynamic_cast<AudioRegionView const *> (*i);
4606 dialog.descend (1.0 / regions);
4607 double const a = arv->audio_region()->maximum_amplitude (&dialog);
4610 /* the user cancelled the operation */
4611 set_canvas_cursor (current_canvas_cursor);
4615 max_amps.push_back (a);
4616 max_amp = max (max_amp, a);
4621 begin_reversible_command (_("normalize"));
4623 list<double>::const_iterator a = max_amps.begin ();
4625 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
4626 AudioRegionView* const arv = dynamic_cast<AudioRegionView*> (*r);
4631 arv->region()->clear_changes ();
4633 double const amp = dialog.normalize_individually() ? *a : max_amp;
4635 arv->audio_region()->normalize (amp, dialog.target ());
4636 _session->add_command (new StatefulDiffCommand (arv->region()));
4641 commit_reversible_command ();
4642 set_canvas_cursor (current_canvas_cursor);
4647 Editor::reset_region_scale_amplitude ()
4653 RegionSelection rs = get_regions_from_selection_and_entered ();
4659 begin_reversible_command ("reset gain");
4661 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
4662 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
4665 arv->region()->clear_changes ();
4666 arv->audio_region()->set_scale_amplitude (1.0f);
4667 _session->add_command (new StatefulDiffCommand (arv->region()));
4670 commit_reversible_command ();
4674 Editor::adjust_region_gain (bool up)
4676 RegionSelection rs = get_regions_from_selection_and_entered ();
4678 if (!_session || rs.empty()) {
4682 begin_reversible_command ("adjust region gain");
4684 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
4685 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
4690 arv->region()->clear_changes ();
4692 double dB = accurate_coefficient_to_dB (arv->audio_region()->scale_amplitude ());
4700 arv->audio_region()->set_scale_amplitude (dB_to_coefficient (dB));
4701 _session->add_command (new StatefulDiffCommand (arv->region()));
4704 commit_reversible_command ();
4709 Editor::reverse_region ()
4715 Reverse rev (*_session);
4716 apply_filter (rev, _("reverse regions"));
4720 Editor::strip_region_silence ()
4726 RegionSelection rs = get_regions_from_selection_and_entered ();
4732 std::list<RegionView*> audio_only;
4734 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
4735 AudioRegionView* const arv = dynamic_cast<AudioRegionView*> (*i);
4737 audio_only.push_back (arv);
4741 StripSilenceDialog d (_session, audio_only);
4742 int const r = d.run ();
4746 if (r == Gtk::RESPONSE_OK) {
4747 ARDOUR::AudioIntervalMap silences;
4748 d.silences (silences);
4749 StripSilence s (*_session, silences, d.fade_length());
4750 apply_filter (s, _("strip silence"), &d);
4755 Editor::apply_midi_note_edit_op_to_region (MidiOperator& op, MidiRegionView& mrv)
4757 Evoral::Sequence<Evoral::MusicalTime>::Notes selected;
4758 mrv.selection_as_notelist (selected, true);
4760 vector<Evoral::Sequence<Evoral::MusicalTime>::Notes> v;
4761 v.push_back (selected);
4763 framepos_t pos_frames = mrv.midi_region()->position() - mrv.midi_region()->start();
4764 double pos_beats = _session->tempo_map().framewalk_to_beats(0, pos_frames);
4766 return op (mrv.midi_region()->model(), pos_beats, v);
4770 Editor::apply_midi_note_edit_op (MidiOperator& op)
4774 RegionSelection rs = get_regions_from_selection_and_entered ();
4780 begin_reversible_command (op.name ());
4782 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
4783 RegionSelection::iterator tmp = r;
4786 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*r);
4789 cmd = apply_midi_note_edit_op_to_region (op, *mrv);
4792 _session->add_command (cmd);
4799 commit_reversible_command ();
4803 Editor::fork_region ()
4805 RegionSelection rs = get_regions_from_selection_and_entered ();
4811 begin_reversible_command (_("Fork Region(s)"));
4813 set_canvas_cursor (_cursors->wait);
4816 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
4817 RegionSelection::iterator tmp = r;
4820 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*>(*r);
4824 boost::shared_ptr<Playlist> playlist = mrv->region()->playlist();
4825 boost::shared_ptr<MidiSource> new_source = _session->create_midi_source_by_stealing_name (mrv->midi_view()->track());
4826 boost::shared_ptr<MidiRegion> newregion = mrv->midi_region()->clone (new_source);
4828 playlist->clear_changes ();
4829 playlist->replace_region (mrv->region(), newregion, mrv->region()->position());
4830 _session->add_command(new StatefulDiffCommand (playlist));
4832 error << string_compose (_("Could not unlink %1"), mrv->region()->name()) << endmsg;
4839 commit_reversible_command ();
4841 set_canvas_cursor (current_canvas_cursor);
4845 Editor::quantize_region ()
4847 int selected_midi_region_cnt = 0;
4853 RegionSelection rs = get_regions_from_selection_and_entered ();
4859 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
4860 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*r);
4862 selected_midi_region_cnt++;
4866 if (selected_midi_region_cnt == 0) {
4870 QuantizeDialog* qd = new QuantizeDialog (*this);
4873 const int r = qd->run ();
4876 if (r == Gtk::RESPONSE_OK) {
4877 Quantize quant (*_session, qd->snap_start(), qd->snap_end(),
4878 qd->start_grid_size(), qd->end_grid_size(),
4879 qd->strength(), qd->swing(), qd->threshold());
4881 apply_midi_note_edit_op (quant);
4886 Editor::insert_patch_change (bool from_context)
4888 RegionSelection rs = get_regions_from_selection_and_entered ();
4894 const framepos_t p = get_preferred_edit_position (false, from_context);
4896 /* XXX: bit of a hack; use the MIDNAM from the first selected region;
4897 there may be more than one, but the PatchChangeDialog can only offer
4898 one set of patch menus.
4900 MidiRegionView* first = dynamic_cast<MidiRegionView*> (rs.front ());
4902 Evoral::PatchChange<Evoral::MusicalTime> empty (0, 0, 0, 0);
4903 PatchChangeDialog d (0, _session, empty, first->instrument_info(), Gtk::Stock::ADD);
4905 if (d.run() == RESPONSE_CANCEL) {
4909 for (RegionSelection::iterator i = rs.begin (); i != rs.end(); ++i) {
4910 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*i);
4912 if (p >= mrv->region()->first_frame() && p <= mrv->region()->last_frame()) {
4913 mrv->add_patch_change (p - mrv->region()->position(), d.patch ());
4920 Editor::apply_filter (Filter& filter, string command, ProgressReporter* progress)
4922 RegionSelection rs = get_regions_from_selection_and_entered ();
4928 begin_reversible_command (command);
4930 set_canvas_cursor (_cursors->wait);
4934 int const N = rs.size ();
4936 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
4937 RegionSelection::iterator tmp = r;
4940 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
4942 boost::shared_ptr<Playlist> playlist = arv->region()->playlist();
4945 progress->descend (1.0 / N);
4948 if (arv->audio_region()->apply (filter, progress) == 0) {
4950 playlist->clear_changes ();
4951 playlist->clear_owned_changes ();
4953 if (filter.results.empty ()) {
4955 /* no regions returned; remove the old one */
4956 playlist->remove_region (arv->region ());
4960 std::vector<boost::shared_ptr<Region> >::iterator res = filter.results.begin ();
4962 /* first region replaces the old one */
4963 playlist->replace_region (arv->region(), *res, (*res)->position());
4967 while (res != filter.results.end()) {
4968 playlist->add_region (*res, (*res)->position());
4974 /* We might have removed regions, which alters other regions' layering_index,
4975 so we need to do a recursive diff here.
4977 vector<Command*> cmds;
4978 playlist->rdiff (cmds);
4979 _session->add_commands (cmds);
4981 _session->add_command(new StatefulDiffCommand (playlist));
4987 progress->ascend ();
4995 commit_reversible_command ();
4998 set_canvas_cursor (current_canvas_cursor);
5002 Editor::external_edit_region ()
5008 Editor::reset_region_gain_envelopes ()
5010 RegionSelection rs = get_regions_from_selection_and_entered ();
5012 if (!_session || rs.empty()) {
5016 _session->begin_reversible_command (_("reset region gain"));
5018 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5019 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
5021 boost::shared_ptr<AutomationList> alist (arv->audio_region()->envelope());
5022 XMLNode& before (alist->get_state());
5024 arv->audio_region()->set_default_envelope ();
5025 _session->add_command (new MementoCommand<AutomationList>(*arv->audio_region()->envelope().get(), &before, &alist->get_state()));
5029 _session->commit_reversible_command ();
5033 Editor::set_region_gain_visibility (RegionView* rv)
5035 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (rv);
5037 arv->update_envelope_visibility();
5042 Editor::set_gain_envelope_visibility ()
5048 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5049 AudioTimeAxisView* v = dynamic_cast<AudioTimeAxisView*>(*i);
5051 v->audio_view()->foreach_regionview (sigc::mem_fun (this, &Editor::set_region_gain_visibility));
5057 Editor::toggle_gain_envelope_active ()
5059 if (_ignore_region_action) {
5063 RegionSelection rs = get_regions_from_selection_and_entered ();
5065 if (!_session || rs.empty()) {
5069 _session->begin_reversible_command (_("region gain envelope active"));
5071 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5072 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
5074 arv->region()->clear_changes ();
5075 arv->audio_region()->set_envelope_active (!arv->audio_region()->envelope_active());
5076 _session->add_command (new StatefulDiffCommand (arv->region()));
5080 _session->commit_reversible_command ();
5084 Editor::toggle_region_lock ()
5086 if (_ignore_region_action) {
5090 RegionSelection rs = get_regions_from_selection_and_entered ();
5092 if (!_session || rs.empty()) {
5096 _session->begin_reversible_command (_("toggle region lock"));
5098 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5099 (*i)->region()->clear_changes ();
5100 (*i)->region()->set_locked (!(*i)->region()->locked());
5101 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5104 _session->commit_reversible_command ();
5108 Editor::toggle_region_video_lock ()
5110 if (_ignore_region_action) {
5114 RegionSelection rs = get_regions_from_selection_and_entered ();
5116 if (!_session || rs.empty()) {
5120 _session->begin_reversible_command (_("Toggle Video Lock"));
5122 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5123 (*i)->region()->clear_changes ();
5124 (*i)->region()->set_video_locked (!(*i)->region()->video_locked());
5125 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5128 _session->commit_reversible_command ();
5132 Editor::toggle_region_lock_style ()
5134 if (_ignore_region_action) {
5138 RegionSelection rs = get_regions_from_selection_and_entered ();
5140 if (!_session || rs.empty()) {
5144 _session->begin_reversible_command (_("region lock style"));
5146 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5147 (*i)->region()->clear_changes ();
5148 PositionLockStyle const ns = (*i)->region()->position_lock_style() == AudioTime ? MusicTime : AudioTime;
5149 (*i)->region()->set_position_lock_style (ns);
5150 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5153 _session->commit_reversible_command ();
5157 Editor::toggle_opaque_region ()
5159 if (_ignore_region_action) {
5163 RegionSelection rs = get_regions_from_selection_and_entered ();
5165 if (!_session || rs.empty()) {
5169 _session->begin_reversible_command (_("change region opacity"));
5171 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5172 (*i)->region()->clear_changes ();
5173 (*i)->region()->set_opaque (!(*i)->region()->opaque());
5174 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5177 _session->commit_reversible_command ();
5181 Editor::toggle_record_enable ()
5183 bool new_state = false;
5185 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5186 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5189 if (!rtav->is_track())
5193 new_state = !rtav->track()->record_enabled();
5197 rtav->track()->set_record_enabled (new_state, this);
5202 Editor::toggle_solo ()
5204 bool new_state = false;
5206 boost::shared_ptr<RouteList> rl (new RouteList);
5208 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5209 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5216 new_state = !rtav->route()->soloed ();
5220 rl->push_back (rtav->route());
5223 _session->set_solo (rl, new_state, Session::rt_cleanup, true);
5227 Editor::toggle_mute ()
5229 bool new_state = false;
5231 boost::shared_ptr<RouteList> rl (new RouteList);
5233 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5234 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5241 new_state = !rtav->route()->muted();
5245 rl->push_back (rtav->route());
5248 _session->set_mute (rl, new_state, Session::rt_cleanup, true);
5252 Editor::toggle_solo_isolate ()
5257 Editor::set_fade_length (bool in)
5259 RegionSelection rs = get_regions_from_selection_and_entered ();
5265 /* we need a region to measure the offset from the start */
5267 RegionView* rv = rs.front ();
5269 framepos_t pos = get_preferred_edit_position();
5273 if (pos > rv->region()->last_frame() || pos < rv->region()->first_frame()) {
5274 /* edit point is outside the relevant region */
5279 if (pos <= rv->region()->position()) {
5283 len = pos - rv->region()->position();
5284 cmd = _("set fade in length");
5286 if (pos >= rv->region()->last_frame()) {
5290 len = rv->region()->last_frame() - pos;
5291 cmd = _("set fade out length");
5294 begin_reversible_command (cmd);
5296 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5297 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5303 boost::shared_ptr<AutomationList> alist;
5305 alist = tmp->audio_region()->fade_in();
5307 alist = tmp->audio_region()->fade_out();
5310 XMLNode &before = alist->get_state();
5313 tmp->audio_region()->set_fade_in_length (len);
5314 tmp->audio_region()->set_fade_in_active (true);
5316 tmp->audio_region()->set_fade_out_length (len);
5317 tmp->audio_region()->set_fade_out_active (true);
5320 XMLNode &after = alist->get_state();
5321 _session->add_command(new MementoCommand<AutomationList>(*alist, &before, &after));
5324 commit_reversible_command ();
5328 Editor::set_fade_in_shape (FadeShape shape)
5330 RegionSelection rs = get_regions_from_selection_and_entered ();
5336 begin_reversible_command (_("set fade in shape"));
5338 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5339 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5345 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_in();
5346 XMLNode &before = alist->get_state();
5348 tmp->audio_region()->set_fade_in_shape (shape);
5350 XMLNode &after = alist->get_state();
5351 _session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
5354 commit_reversible_command ();
5359 Editor::set_fade_out_shape (FadeShape shape)
5361 RegionSelection rs = get_regions_from_selection_and_entered ();
5367 begin_reversible_command (_("set fade out shape"));
5369 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5370 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5376 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_out();
5377 XMLNode &before = alist->get_state();
5379 tmp->audio_region()->set_fade_out_shape (shape);
5381 XMLNode &after = alist->get_state();
5382 _session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
5385 commit_reversible_command ();
5389 Editor::set_fade_in_active (bool yn)
5391 RegionSelection rs = get_regions_from_selection_and_entered ();
5397 begin_reversible_command (_("set fade in active"));
5399 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5400 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5407 boost::shared_ptr<AudioRegion> ar (tmp->audio_region());
5409 ar->clear_changes ();
5410 ar->set_fade_in_active (yn);
5411 _session->add_command (new StatefulDiffCommand (ar));
5414 commit_reversible_command ();
5418 Editor::set_fade_out_active (bool yn)
5420 RegionSelection rs = get_regions_from_selection_and_entered ();
5426 begin_reversible_command (_("set fade out active"));
5428 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5429 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5435 boost::shared_ptr<AudioRegion> ar (tmp->audio_region());
5437 ar->clear_changes ();
5438 ar->set_fade_out_active (yn);
5439 _session->add_command(new StatefulDiffCommand (ar));
5442 commit_reversible_command ();
5446 Editor::toggle_region_fades (int dir)
5448 if (_ignore_region_action) {
5452 boost::shared_ptr<AudioRegion> ar;
5455 RegionSelection rs = get_regions_from_selection_and_entered ();
5461 RegionSelection::iterator i;
5462 for (i = rs.begin(); i != rs.end(); ++i) {
5463 if ((ar = boost::dynamic_pointer_cast<AudioRegion>((*i)->region())) != 0) {
5465 yn = ar->fade_out_active ();
5467 yn = ar->fade_in_active ();
5473 if (i == rs.end()) {
5477 /* XXX should this undo-able? */
5479 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5480 if ((ar = boost::dynamic_pointer_cast<AudioRegion>((*i)->region())) == 0) {
5483 if (dir == 1 || dir == 0) {
5484 ar->set_fade_in_active (!yn);
5487 if (dir == -1 || dir == 0) {
5488 ar->set_fade_out_active (!yn);
5494 /** Update region fade visibility after its configuration has been changed */
5496 Editor::update_region_fade_visibility ()
5498 bool _fade_visibility = _session->config.get_show_region_fades ();
5500 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5501 AudioTimeAxisView* v = dynamic_cast<AudioTimeAxisView*>(*i);
5503 if (_fade_visibility) {
5504 v->audio_view()->show_all_fades ();
5506 v->audio_view()->hide_all_fades ();
5513 Editor::set_edit_point ()
5518 if (!mouse_frame (where, ignored)) {
5524 if (selection->markers.empty()) {
5526 mouse_add_new_marker (where);
5531 Location* loc = find_location_from_marker (selection->markers.front(), ignored);
5534 loc->move_to (where);
5540 Editor::set_playhead_cursor ()
5542 if (entered_marker) {
5543 _session->request_locate (entered_marker->position(), _session->transport_rolling());
5548 if (!mouse_frame (where, ignored)) {
5555 _session->request_locate (where, _session->transport_rolling());
5559 if ( Config->get_always_play_range() )
5560 cancel_time_selection();
5564 Editor::split_region ()
5566 if ( !selection->time.empty()) {
5567 separate_regions_between (selection->time);
5571 RegionSelection rs = get_regions_from_selection_and_edit_point ();
5573 framepos_t where = get_preferred_edit_position ();
5579 split_regions_at (where, rs);
5582 struct EditorOrderRouteSorter {
5583 bool operator() (boost::shared_ptr<Route> a, boost::shared_ptr<Route> b) {
5584 return a->order_key () < b->order_key ();
5589 Editor::select_next_route()
5591 if (selection->tracks.empty()) {
5592 selection->set (track_views.front());
5596 TimeAxisView* current = selection->tracks.front();
5600 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5601 if (*i == current) {
5603 if (i != track_views.end()) {
5606 current = (*(track_views.begin()));
5607 //selection->set (*(track_views.begin()));
5612 rui = dynamic_cast<RouteUI *>(current);
5613 } while ( current->hidden() || (rui != NULL && !rui->route()->active()));
5615 selection->set(current);
5617 ensure_time_axis_view_is_visible (*current);
5621 Editor::select_prev_route()
5623 if (selection->tracks.empty()) {
5624 selection->set (track_views.front());
5628 TimeAxisView* current = selection->tracks.front();
5632 for (TrackViewList::reverse_iterator i = track_views.rbegin(); i != track_views.rend(); ++i) {
5633 if (*i == current) {
5635 if (i != track_views.rend()) {
5638 current = *(track_views.rbegin());
5643 rui = dynamic_cast<RouteUI *>(current);
5644 } while ( current->hidden() || (rui != NULL && !rui->route()->active()));
5646 selection->set (current);
5648 ensure_time_axis_view_is_visible (*current);
5652 Editor::set_loop_from_selection (bool play)
5654 if (_session == 0 || selection->time.empty()) {
5658 framepos_t start = selection->time[clicked_selection].start;
5659 framepos_t end = selection->time[clicked_selection].end;
5661 set_loop_range (start, end, _("set loop range from selection"));
5664 _session->request_play_loop (true);
5665 _session->request_locate (start, true);
5670 Editor::set_loop_from_edit_range (bool play)
5672 if (_session == 0) {
5679 if (!get_edit_op_range (start, end)) {
5683 set_loop_range (start, end, _("set loop range from edit range"));
5686 _session->request_play_loop (true);
5687 _session->request_locate (start, true);
5692 Editor::set_loop_from_region (bool play)
5694 framepos_t start = max_framepos;
5697 RegionSelection rs = get_regions_from_selection_and_entered ();
5703 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5704 if ((*i)->region()->position() < start) {
5705 start = (*i)->region()->position();
5707 if ((*i)->region()->last_frame() + 1 > end) {
5708 end = (*i)->region()->last_frame() + 1;
5712 set_loop_range (start, end, _("set loop range from region"));
5715 _session->request_play_loop (true);
5716 _session->request_locate (start, true);
5721 Editor::set_punch_from_selection ()
5723 if (_session == 0 || selection->time.empty()) {
5727 framepos_t start = selection->time[clicked_selection].start;
5728 framepos_t end = selection->time[clicked_selection].end;
5730 set_punch_range (start, end, _("set punch range from selection"));
5734 Editor::set_punch_from_edit_range ()
5736 if (_session == 0) {
5743 if (!get_edit_op_range (start, end)) {
5747 set_punch_range (start, end, _("set punch range from edit range"));
5751 Editor::set_punch_from_region ()
5753 framepos_t start = max_framepos;
5756 RegionSelection rs = get_regions_from_selection_and_entered ();
5762 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5763 if ((*i)->region()->position() < start) {
5764 start = (*i)->region()->position();
5766 if ((*i)->region()->last_frame() + 1 > end) {
5767 end = (*i)->region()->last_frame() + 1;
5771 set_punch_range (start, end, _("set punch range from region"));
5775 Editor::pitch_shift_region ()
5777 RegionSelection rs = get_regions_from_selection_and_entered ();
5779 RegionSelection audio_rs;
5780 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5781 if (dynamic_cast<AudioRegionView*> (*i)) {
5782 audio_rs.push_back (*i);
5786 if (audio_rs.empty()) {
5790 pitch_shift (audio_rs, 1.2);
5794 Editor::transpose_region ()
5796 RegionSelection rs = get_regions_from_selection_and_entered ();
5798 list<MidiRegionView*> midi_region_views;
5799 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5800 MidiRegionView* mrv = dynamic_cast<MidiRegionView*> (*i);
5802 midi_region_views.push_back (mrv);
5807 int const r = d.run ();
5808 if (r != RESPONSE_ACCEPT) {
5812 for (list<MidiRegionView*>::iterator i = midi_region_views.begin(); i != midi_region_views.end(); ++i) {
5813 (*i)->midi_region()->transpose (d.semitones ());
5818 Editor::set_tempo_from_region ()
5820 RegionSelection rs = get_regions_from_selection_and_entered ();
5822 if (!_session || rs.empty()) {
5826 RegionView* rv = rs.front();
5828 define_one_bar (rv->region()->position(), rv->region()->last_frame() + 1);
5832 Editor::use_range_as_bar ()
5834 framepos_t start, end;
5835 if (get_edit_op_range (start, end)) {
5836 define_one_bar (start, end);
5841 Editor::define_one_bar (framepos_t start, framepos_t end)
5843 framepos_t length = end - start;
5845 const Meter& m (_session->tempo_map().meter_at (start));
5847 /* length = 1 bar */
5849 /* now we want frames per beat.
5850 we have frames per bar, and beats per bar, so ...
5853 /* XXXX METER MATH */
5855 double frames_per_beat = length / m.divisions_per_bar();
5857 /* beats per minute = */
5859 double beats_per_minute = (_session->frame_rate() * 60.0) / frames_per_beat;
5861 /* now decide whether to:
5863 (a) set global tempo
5864 (b) add a new tempo marker
5868 const TempoSection& t (_session->tempo_map().tempo_section_at (start));
5870 bool do_global = false;
5872 if ((_session->tempo_map().n_tempos() == 1) && (_session->tempo_map().n_meters() == 1)) {
5874 /* only 1 tempo & 1 meter: ask if the user wants to set the tempo
5875 at the start, or create a new marker
5878 vector<string> options;
5879 options.push_back (_("Cancel"));
5880 options.push_back (_("Add new marker"));
5881 options.push_back (_("Set global tempo"));
5884 _("Define one bar"),
5885 _("Do you want to set the global tempo or add a new tempo marker?"),
5889 c.set_default_response (2);
5905 /* more than 1 tempo and/or meter section already, go ahead do the "usual":
5906 if the marker is at the region starter, change it, otherwise add
5911 begin_reversible_command (_("set tempo from region"));
5912 XMLNode& before (_session->tempo_map().get_state());
5915 _session->tempo_map().change_initial_tempo (beats_per_minute, t.note_type());
5916 } else if (t.frame() == start) {
5917 _session->tempo_map().change_existing_tempo_at (start, beats_per_minute, t.note_type());
5919 Timecode::BBT_Time bbt;
5920 _session->tempo_map().bbt_time (start, bbt);
5921 _session->tempo_map().add_tempo (Tempo (beats_per_minute, t.note_type()), bbt);
5924 XMLNode& after (_session->tempo_map().get_state());
5926 _session->add_command (new MementoCommand<TempoMap>(_session->tempo_map(), &before, &after));
5927 commit_reversible_command ();
5931 Editor::split_region_at_transients ()
5933 AnalysisFeatureList positions;
5935 RegionSelection rs = get_regions_from_selection_and_entered ();
5937 if (!_session || rs.empty()) {
5941 _session->begin_reversible_command (_("split regions"));
5943 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ) {
5945 RegionSelection::iterator tmp;
5950 boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion> ((*i)->region());
5952 if (ar && (ar->get_transients (positions) == 0)) {
5953 split_region_at_points ((*i)->region(), positions, true);
5960 _session->commit_reversible_command ();
5965 Editor::split_region_at_points (boost::shared_ptr<Region> r, AnalysisFeatureList& positions, bool can_ferret, bool select_new)
5967 bool use_rhythmic_rodent = false;
5969 boost::shared_ptr<Playlist> pl = r->playlist();
5971 list<boost::shared_ptr<Region> > new_regions;
5977 if (positions.empty()) {
5982 if (positions.size() > 20 && can_ferret) {
5983 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);
5984 MessageDialog msg (msgstr,
5987 Gtk::BUTTONS_OK_CANCEL);
5990 msg.add_button (_("Call for the Ferret!"), RESPONSE_APPLY);
5991 msg.set_secondary_text (_("Press OK to continue with this split operation\nor ask the Ferret dialog to tune the analysis"));
5993 msg.set_secondary_text (_("Press OK to continue with this split operation"));
5996 msg.set_title (_("Excessive split?"));
5999 int response = msg.run();
6005 case RESPONSE_APPLY:
6006 use_rhythmic_rodent = true;
6013 if (use_rhythmic_rodent) {
6014 show_rhythm_ferret ();
6018 AnalysisFeatureList::const_iterator x;
6020 pl->clear_changes ();
6021 pl->clear_owned_changes ();
6023 x = positions.begin();
6025 if (x == positions.end()) {
6030 pl->remove_region (r);
6034 while (x != positions.end()) {
6036 /* deal with positons that are out of scope of present region bounds */
6037 if (*x <= 0 || *x > r->length()) {
6042 /* file start = original start + how far we from the initial position ?
6045 framepos_t file_start = r->start() + pos;
6047 /* length = next position - current position
6050 framepos_t len = (*x) - pos;
6052 /* XXX we do we really want to allow even single-sample regions?
6053 shouldn't we have some kind of lower limit on region size?
6062 if (RegionFactory::region_name (new_name, r->name())) {
6066 /* do NOT announce new regions 1 by one, just wait till they are all done */
6070 plist.add (ARDOUR::Properties::start, file_start);
6071 plist.add (ARDOUR::Properties::length, len);
6072 plist.add (ARDOUR::Properties::name, new_name);
6073 plist.add (ARDOUR::Properties::layer, 0);
6075 boost::shared_ptr<Region> nr = RegionFactory::create (r->sources(), plist, false);
6076 /* because we set annouce to false, manually add the new region to the
6079 RegionFactory::map_add (nr);
6081 pl->add_region (nr, r->position() + pos);
6084 new_regions.push_front(nr);
6093 RegionFactory::region_name (new_name, r->name());
6095 /* Add the final region */
6098 plist.add (ARDOUR::Properties::start, r->start() + pos);
6099 plist.add (ARDOUR::Properties::length, r->last_frame() - (r->position() + pos) + 1);
6100 plist.add (ARDOUR::Properties::name, new_name);
6101 plist.add (ARDOUR::Properties::layer, 0);
6103 boost::shared_ptr<Region> nr = RegionFactory::create (r->sources(), plist, false);
6104 /* because we set annouce to false, manually add the new region to the
6107 RegionFactory::map_add (nr);
6108 pl->add_region (nr, r->position() + pos);
6111 new_regions.push_front(nr);
6116 /* We might have removed regions, which alters other regions' layering_index,
6117 so we need to do a recursive diff here.
6119 vector<Command*> cmds;
6121 _session->add_commands (cmds);
6123 _session->add_command (new StatefulDiffCommand (pl));
6127 for (list<boost::shared_ptr<Region> >::iterator i = new_regions.begin(); i != new_regions.end(); ++i){
6128 set_selected_regionview_from_region_list ((*i), Selection::Add);
6134 Editor::place_transient()
6140 RegionSelection rs = get_regions_from_selection_and_edit_point ();
6146 framepos_t where = get_preferred_edit_position();
6148 _session->begin_reversible_command (_("place transient"));
6150 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6151 framepos_t position = (*r)->region()->position();
6152 (*r)->region()->add_transient(where - position);
6155 _session->commit_reversible_command ();
6159 Editor::remove_transient(ArdourCanvas::Item* item)
6165 ArdourCanvas::Line* _line = reinterpret_cast<ArdourCanvas::Line*> (item);
6168 AudioRegionView* _arv = reinterpret_cast<AudioRegionView*> (item->get_data ("regionview"));
6169 _arv->remove_transient (*(float*) _line->get_data ("position"));
6173 Editor::snap_regions_to_grid ()
6175 list <boost::shared_ptr<Playlist > > used_playlists;
6177 RegionSelection rs = get_regions_from_selection_and_entered ();
6179 if (!_session || rs.empty()) {
6183 _session->begin_reversible_command (_("snap regions to grid"));
6185 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6187 boost::shared_ptr<Playlist> pl = (*r)->region()->playlist();
6189 if (!pl->frozen()) {
6190 /* we haven't seen this playlist before */
6192 /* remember used playlists so we can thaw them later */
6193 used_playlists.push_back(pl);
6197 framepos_t start_frame = (*r)->region()->first_frame ();
6198 snap_to (start_frame);
6199 (*r)->region()->set_position (start_frame);
6202 while (used_playlists.size() > 0) {
6203 list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
6205 used_playlists.pop_front();
6208 _session->commit_reversible_command ();
6212 Editor::close_region_gaps ()
6214 list <boost::shared_ptr<Playlist > > used_playlists;
6216 RegionSelection rs = get_regions_from_selection_and_entered ();
6218 if (!_session || rs.empty()) {
6222 Dialog dialog (_("Close Region Gaps"));
6225 table.set_spacings (12);
6226 table.set_border_width (12);
6227 Label* l = manage (left_aligned_label (_("Crossfade length")));
6228 table.attach (*l, 0, 1, 0, 1);
6230 SpinButton spin_crossfade (1, 0);
6231 spin_crossfade.set_range (0, 15);
6232 spin_crossfade.set_increments (1, 1);
6233 spin_crossfade.set_value (5);
6234 table.attach (spin_crossfade, 1, 2, 0, 1);
6236 table.attach (*manage (new Label (_("ms"))), 2, 3, 0, 1);
6238 l = manage (left_aligned_label (_("Pull-back length")));
6239 table.attach (*l, 0, 1, 1, 2);
6241 SpinButton spin_pullback (1, 0);
6242 spin_pullback.set_range (0, 100);
6243 spin_pullback.set_increments (1, 1);
6244 spin_pullback.set_value(30);
6245 table.attach (spin_pullback, 1, 2, 1, 2);
6247 table.attach (*manage (new Label (_("ms"))), 2, 3, 1, 2);
6249 dialog.get_vbox()->pack_start (table);
6250 dialog.add_button (Stock::CANCEL, RESPONSE_CANCEL);
6251 dialog.add_button (_("Ok"), RESPONSE_ACCEPT);
6254 if (dialog.run () == RESPONSE_CANCEL) {
6258 framepos_t crossfade_len = spin_crossfade.get_value();
6259 framepos_t pull_back_frames = spin_pullback.get_value();
6261 crossfade_len = lrintf (crossfade_len * _session->frame_rate()/1000);
6262 pull_back_frames = lrintf (pull_back_frames * _session->frame_rate()/1000);
6264 /* Iterate over the region list and make adjacent regions overlap by crossfade_len_ms */
6266 _session->begin_reversible_command (_("close region gaps"));
6269 boost::shared_ptr<Region> last_region;
6271 rs.sort_by_position_and_track();
6273 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6275 boost::shared_ptr<Playlist> pl = (*r)->region()->playlist();
6277 if (!pl->frozen()) {
6278 /* we haven't seen this playlist before */
6280 /* remember used playlists so we can thaw them later */
6281 used_playlists.push_back(pl);
6285 framepos_t position = (*r)->region()->position();
6287 if (idx == 0 || position < last_region->position()){
6288 last_region = (*r)->region();
6293 (*r)->region()->trim_front( (position - pull_back_frames));
6294 last_region->trim_end( (position - pull_back_frames + crossfade_len));
6296 last_region = (*r)->region();
6301 while (used_playlists.size() > 0) {
6302 list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
6304 used_playlists.pop_front();
6307 _session->commit_reversible_command ();
6311 Editor::tab_to_transient (bool forward)
6313 AnalysisFeatureList positions;
6315 RegionSelection rs = get_regions_from_selection_and_entered ();
6321 framepos_t pos = _session->audible_frame ();
6323 if (!selection->tracks.empty()) {
6325 /* don't waste time searching for transients in duplicate playlists.
6328 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
6330 for (TrackViewList::iterator t = ts.begin(); t != ts.end(); ++t) {
6332 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*t);
6335 boost::shared_ptr<Track> tr = rtv->track();
6337 boost::shared_ptr<Playlist> pl = tr->playlist ();
6339 framepos_t result = pl->find_next_transient (pos, forward ? 1 : -1);
6342 positions.push_back (result);
6355 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6356 (*r)->region()->get_transients (positions);
6360 TransientDetector::cleanup_transients (positions, _session->frame_rate(), 3.0);
6363 AnalysisFeatureList::iterator x;
6365 for (x = positions.begin(); x != positions.end(); ++x) {
6371 if (x != positions.end ()) {
6372 _session->request_locate (*x);
6376 AnalysisFeatureList::reverse_iterator x;
6378 for (x = positions.rbegin(); x != positions.rend(); ++x) {
6384 if (x != positions.rend ()) {
6385 _session->request_locate (*x);
6391 Editor::playhead_forward_to_grid ()
6397 framepos_t pos = playhead_cursor->current_frame ();
6398 if (pos < max_framepos - 1) {
6400 snap_to_internal (pos, 1, false);
6401 _session->request_locate (pos);
6407 Editor::playhead_backward_to_grid ()
6413 framepos_t pos = playhead_cursor->current_frame ();
6416 snap_to_internal (pos, -1, false);
6417 _session->request_locate (pos);
6422 Editor::set_track_height (Height h)
6424 TrackSelection& ts (selection->tracks);
6426 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
6427 (*x)->set_height_enum (h);
6432 Editor::toggle_tracks_active ()
6434 TrackSelection& ts (selection->tracks);
6436 bool target = false;
6442 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
6443 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*x);
6447 target = !rtv->_route->active();
6450 rtv->_route->set_active (target, this);
6456 Editor::remove_tracks ()
6458 TrackSelection& ts (selection->tracks);
6464 vector<string> choices;
6468 const char* trackstr;
6470 vector<boost::shared_ptr<Route> > routes;
6471 bool special_bus = false;
6473 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
6474 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*x);
6478 if (rtv->is_track()) {
6483 routes.push_back (rtv->_route);
6485 if (rtv->route()->is_master() || rtv->route()->is_monitor()) {
6490 if (special_bus && !Config->get_allow_special_bus_removal()) {
6491 MessageDialog msg (_("That would be bad news ...."),
6495 msg.set_secondary_text (string_compose (_(
6496 "Removing the master or monitor bus is such a bad idea\n\
6497 that %1 is not going to allow it.\n\
6499 If you really want to do this sort of thing\n\
6500 edit your ardour.rc file to set the\n\
6501 \"allow-special-bus-removal\" option to be \"yes\""), PROGRAM_NAME));
6508 if (ntracks + nbusses == 0) {
6513 trackstr = _("tracks");
6515 trackstr = _("track");
6519 busstr = _("busses");
6526 prompt = string_compose (_("Do you really want to remove %1 %2 and %3 %4?\n"
6527 "(You may also lose the playlists associated with the %2)\n\n"
6528 "This action cannot be undone, and the session file will be overwritten!"),
6529 ntracks, trackstr, nbusses, busstr);
6531 prompt = string_compose (_("Do you really want to remove %1 %2?\n"
6532 "(You may also lose the playlists associated with the %2)\n\n"
6533 "This action cannot be undone, and the session file will be overwritten!"),
6536 } else if (nbusses) {
6537 prompt = string_compose (_("Do you really want to remove %1 %2?\n\n"
6538 "This action cannot be undon, and the session file will be overwritten"),
6542 choices.push_back (_("No, do nothing."));
6543 if (ntracks + nbusses > 1) {
6544 choices.push_back (_("Yes, remove them."));
6546 choices.push_back (_("Yes, remove it."));
6551 title = string_compose (_("Remove %1"), trackstr);
6553 title = string_compose (_("Remove %1"), busstr);
6556 Choice prompter (title, prompt, choices);
6558 if (prompter.run () != 1) {
6563 Session::StateProtector sp (_session);
6564 for (vector<boost::shared_ptr<Route> >::iterator x = routes.begin(); x != routes.end(); ++x) {
6565 _session->remove_route (*x);
6571 Editor::do_insert_time ()
6573 if (selection->tracks.empty()) {
6577 InsertTimeDialog d (*this);
6578 int response = d.run ();
6580 if (response != RESPONSE_OK) {
6584 if (d.distance() == 0) {
6588 InsertTimeOption opt = d.intersected_region_action ();
6591 get_preferred_edit_position(),
6597 d.move_glued_markers(),
6598 d.move_locked_markers(),
6604 Editor::insert_time (
6605 framepos_t pos, framecnt_t frames, InsertTimeOption opt,
6606 bool all_playlists, bool ignore_music_glue, bool markers_too, bool glued_markers_too, bool locked_markers_too, bool tempo_too
6609 bool commit = false;
6611 if (Config->get_edit_mode() == Lock) {
6615 begin_reversible_command (_("insert time"));
6617 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
6619 for (TrackViewList::iterator x = ts.begin(); x != ts.end(); ++x) {
6623 /* don't operate on any playlist more than once, which could
6624 * happen if "all playlists" is enabled, but there is more
6625 * than 1 track using playlists "from" a given track.
6628 set<boost::shared_ptr<Playlist> > pl;
6630 if (all_playlists) {
6631 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*x);
6633 vector<boost::shared_ptr<Playlist> > all = _session->playlists->playlists_for_track (rtav->track ());
6634 for (vector<boost::shared_ptr<Playlist> >::iterator p = all.begin(); p != all.end(); ++p) {
6639 if ((*x)->playlist ()) {
6640 pl.insert ((*x)->playlist ());
6644 for (set<boost::shared_ptr<Playlist> >::iterator i = pl.begin(); i != pl.end(); ++i) {
6646 (*i)->clear_changes ();
6647 (*i)->clear_owned_changes ();
6649 if (opt == SplitIntersected) {
6653 (*i)->shift (pos, frames, (opt == MoveIntersected), ignore_music_glue);
6655 vector<Command*> cmds;
6657 _session->add_commands (cmds);
6659 _session->add_command (new StatefulDiffCommand (*i));
6664 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*x);
6666 rtav->route ()->shift (pos, frames);
6674 XMLNode& before (_session->locations()->get_state());
6675 Locations::LocationList copy (_session->locations()->list());
6677 for (Locations::LocationList::iterator i = copy.begin(); i != copy.end(); ++i) {
6679 Locations::LocationList::const_iterator tmp;
6681 bool const was_locked = (*i)->locked ();
6682 if (locked_markers_too) {
6686 if ((*i)->position_lock_style() == AudioTime || glued_markers_too) {
6688 if ((*i)->start() >= pos) {
6689 (*i)->set_start ((*i)->start() + frames);
6690 if (!(*i)->is_mark()) {
6691 (*i)->set_end ((*i)->end() + frames);
6704 XMLNode& after (_session->locations()->get_state());
6705 _session->add_command (new MementoCommand<Locations>(*_session->locations(), &before, &after));
6710 _session->tempo_map().insert_time (pos, frames);
6714 commit_reversible_command ();
6719 Editor::fit_selected_tracks ()
6721 if (!selection->tracks.empty()) {
6722 fit_tracks (selection->tracks);
6726 /* no selected tracks - use tracks with selected regions */
6728 if (!selection->regions.empty()) {
6729 for (RegionSelection::iterator r = selection->regions.begin(); r != selection->regions.end(); ++r) {
6730 tvl.push_back (&(*r)->get_time_axis_view ());
6736 } else if (internal_editing()) {
6737 /* no selected tracks, or regions, but in internal edit mode, so follow the mouse and use
6740 if (entered_track) {
6741 tvl.push_back (entered_track);
6749 Editor::fit_tracks (TrackViewList & tracks)
6751 if (tracks.empty()) {
6755 uint32_t child_heights = 0;
6756 int visible_tracks = 0;
6758 for (TrackSelection::iterator t = tracks.begin(); t != tracks.end(); ++t) {
6760 if (!(*t)->marked_for_display()) {
6764 child_heights += (*t)->effective_height() - (*t)->current_height();
6768 /* compute the per-track height from:
6770 total canvas visible height -
6771 height that will be taken by visible children of selected
6772 tracks - height of the ruler/hscroll area
6774 uint32_t h = (uint32_t) floor ((_visible_canvas_height - (child_heights + _trackview_group->canvas_origin().y)) / visible_tracks);
6775 double first_y_pos = DBL_MAX;
6777 if (h < TimeAxisView::preset_height (HeightSmall)) {
6778 MessageDialog msg (*this, _("There are too many tracks to fit in the current window"));
6779 /* too small to be displayed */
6783 undo_visual_stack.push_back (current_visual_state (true));
6784 no_save_visual = true;
6786 /* build a list of all tracks, including children */
6789 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
6791 TimeAxisView::Children c = (*i)->get_child_list ();
6792 for (TimeAxisView::Children::iterator j = c.begin(); j != c.end(); ++j) {
6793 all.push_back (j->get());
6797 /* operate on all tracks, hide unselected ones that are in the middle of selected ones */
6799 bool within_selected = false;
6801 for (TrackViewList::iterator t = all.begin(); t != all.end(); ++t) {
6803 TrackViewList::iterator next;
6808 if ((*t)->marked_for_display ()) {
6809 if (tracks.contains (*t)) {
6810 (*t)->set_height (h);
6811 first_y_pos = std::min ((*t)->y_position (), first_y_pos);
6812 within_selected = true;
6813 } else if (within_selected) {
6814 hide_track_in_display (*t);
6820 set the controls_layout height now, because waiting for its size
6821 request signal handler will cause the vertical adjustment setting to fail
6824 controls_layout.property_height () = _full_canvas_height;
6825 vertical_adjustment.set_value (first_y_pos);
6827 redo_visual_stack.push_back (current_visual_state (true));
6831 Editor::save_visual_state (uint32_t n)
6833 while (visual_states.size() <= n) {
6834 visual_states.push_back (0);
6837 if (visual_states[n] != 0) {
6838 delete visual_states[n];
6841 visual_states[n] = current_visual_state (true);
6846 Editor::goto_visual_state (uint32_t n)
6848 if (visual_states.size() <= n) {
6852 if (visual_states[n] == 0) {
6856 use_visual_state (*visual_states[n]);
6860 Editor::start_visual_state_op (uint32_t n)
6862 save_visual_state (n);
6864 PopUp* pup = new PopUp (WIN_POS_MOUSE, 1000, true);
6866 snprintf (buf, sizeof (buf), _("Saved view %u"), n+1);
6867 pup->set_text (buf);
6872 Editor::cancel_visual_state_op (uint32_t n)
6874 goto_visual_state (n);
6878 Editor::toggle_region_mute ()
6880 if (_ignore_region_action) {
6884 RegionSelection rs = get_regions_from_selection_and_entered ();
6890 if (rs.size() > 1) {
6891 begin_reversible_command (_("mute regions"));
6893 begin_reversible_command (_("mute region"));
6896 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
6898 (*i)->region()->playlist()->clear_changes ();
6899 (*i)->region()->set_muted (!(*i)->region()->muted ());
6900 _session->add_command (new StatefulDiffCommand ((*i)->region()->playlist()));
6904 commit_reversible_command ();
6908 Editor::combine_regions ()
6910 /* foreach track with selected regions, take all selected regions
6911 and join them into a new region containing the subregions (as a
6915 typedef set<RouteTimeAxisView*> RTVS;
6918 if (selection->regions.empty()) {
6922 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
6923 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(&(*i)->get_time_axis_view());
6926 tracks.insert (rtv);
6930 begin_reversible_command (_("combine regions"));
6932 vector<RegionView*> new_selection;
6934 for (RTVS::iterator i = tracks.begin(); i != tracks.end(); ++i) {
6937 if ((rv = (*i)->combine_regions ()) != 0) {
6938 new_selection.push_back (rv);
6942 selection->clear_regions ();
6943 for (vector<RegionView*>::iterator i = new_selection.begin(); i != new_selection.end(); ++i) {
6944 selection->add (*i);
6947 commit_reversible_command ();
6951 Editor::uncombine_regions ()
6953 typedef set<RouteTimeAxisView*> RTVS;
6956 if (selection->regions.empty()) {
6960 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
6961 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(&(*i)->get_time_axis_view());
6964 tracks.insert (rtv);
6968 begin_reversible_command (_("uncombine regions"));
6970 for (RTVS::iterator i = tracks.begin(); i != tracks.end(); ++i) {
6971 (*i)->uncombine_regions ();
6974 commit_reversible_command ();
6978 Editor::toggle_midi_input_active (bool flip_others)
6981 boost::shared_ptr<RouteList> rl (new RouteList);
6983 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
6984 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
6990 boost::shared_ptr<MidiTrack> mt = rtav->midi_track();
6993 rl->push_back (rtav->route());
6994 onoff = !mt->input_active();
6998 _session->set_exclusive_input_active (rl, onoff, flip_others);
7005 lock_dialog = new Gtk::Dialog (string_compose (_("%1: Locked"), PROGRAM_NAME), true);
7007 Gtk::Image* padlock = manage (new Gtk::Image (ARDOUR_UI_UTILS::get_icon ("padlock_closed")));
7008 lock_dialog->get_vbox()->pack_start (*padlock);
7010 ArdourButton* b = manage (new ArdourButton);
7011 b->set_name ("lock button");
7012 b->set_markup (string_compose ("<span size=\"large\" weight=\"bold\">%1</span>", _("Click to unlock")));
7013 b->signal_clicked.connect (sigc::mem_fun (*this, &Editor::unlock));
7014 lock_dialog->get_vbox()->pack_start (*b);
7016 lock_dialog->get_vbox()->show_all ();
7017 lock_dialog->set_size_request (200, 200);
7021 /* The global menu bar continues to be accessible to applications
7022 with modal dialogs, which means that we need to desensitize
7023 all items in the menu bar. Since those items are really just
7024 proxies for actions, that means disabling all actions.
7026 ActionManager::disable_all_actions ();
7028 lock_dialog->present ();
7034 lock_dialog->hide ();
7037 ActionManager::pop_action_state ();
7040 if (ARDOUR_UI::config()->get_lock_gui_after_seconds()) {
7041 start_lock_event_timing ();