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"
60 #include "ardour_ui.h"
61 #include "audio_region_view.h"
62 #include "audio_streamview.h"
63 #include "audio_time_axis.h"
64 #include "automation_time_axis.h"
65 #include "control_point.h"
69 #include "editor_cursors.h"
70 #include "editor_drag.h"
71 #include "editor_regions.h"
72 #include "editor_routes.h"
73 #include "gtk-custom-hruler.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"
97 using namespace ARDOUR;
100 using namespace Gtkmm2ext;
101 using namespace Editing;
102 using Gtkmm2ext::Keyboard;
104 /***********************************************************************
106 ***********************************************************************/
109 Editor::undo (uint32_t n)
111 if (_drags->active ()) {
121 Editor::redo (uint32_t n)
123 if (_drags->active ()) {
133 Editor::split_regions_at (framepos_t where, RegionSelection& regions)
137 list <boost::shared_ptr<Playlist > > used_playlists;
139 if (regions.empty()) {
143 begin_reversible_command (_("split"));
145 // if splitting a single region, and snap-to is using
146 // region boundaries, don't pay attention to them
148 if (regions.size() == 1) {
149 switch (_snap_type) {
150 case SnapToRegionStart:
151 case SnapToRegionSync:
152 case SnapToRegionEnd:
161 EditorFreeze(); /* Emit Signal */
164 for (RegionSelection::iterator a = regions.begin(); a != regions.end(); ) {
166 RegionSelection::iterator tmp;
168 /* XXX this test needs to be more complicated, to make sure we really
169 have something to split.
172 if (!(*a)->region()->covers (where)) {
180 boost::shared_ptr<Playlist> pl = (*a)->region()->playlist();
188 /* we haven't seen this playlist before */
190 /* remember used playlists so we can thaw them later */
191 used_playlists.push_back(pl);
196 pl->clear_changes ();
197 pl->split_region ((*a)->region(), where);
198 _session->add_command (new StatefulDiffCommand (pl));
204 while (used_playlists.size() > 0) {
205 list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
207 used_playlists.pop_front();
210 commit_reversible_command ();
213 EditorThaw(); /* Emit Signal */
217 /** Move one extreme of the current range selection. If more than one range is selected,
218 * the start of the earliest range or the end of the latest range is moved.
220 * @param move_end true to move the end of the current range selection, false to move
222 * @param next true to move the extreme to the next region boundary, false to move to
226 Editor::move_range_selection_start_or_end_to_region_boundary (bool move_end, bool next)
228 if (selection->time.start() == selection->time.end_frame()) {
232 framepos_t start = selection->time.start ();
233 framepos_t end = selection->time.end_frame ();
235 /* the position of the thing we may move */
236 framepos_t pos = move_end ? end : start;
237 int dir = next ? 1 : -1;
239 /* so we don't find the current region again */
240 if (dir > 0 || pos > 0) {
244 framepos_t const target = get_region_boundary (pos, dir, true, false);
259 begin_reversible_command (_("alter selection"));
260 selection->set_preserving_all_ranges (start, end);
261 commit_reversible_command ();
265 Editor::nudge_forward_release (GdkEventButton* ev)
267 if (ev->state & Keyboard::PrimaryModifier) {
268 nudge_forward (false, true);
270 nudge_forward (false, false);
276 Editor::nudge_backward_release (GdkEventButton* ev)
278 if (ev->state & Keyboard::PrimaryModifier) {
279 nudge_backward (false, true);
281 nudge_backward (false, false);
288 Editor::nudge_forward (bool next, bool force_playhead)
291 framepos_t next_distance;
297 RegionSelection rs = get_regions_from_selection_and_entered ();
299 if (!force_playhead && !rs.empty()) {
301 begin_reversible_command (_("nudge regions forward"));
303 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
304 boost::shared_ptr<Region> r ((*i)->region());
306 distance = get_nudge_distance (r->position(), next_distance);
309 distance = next_distance;
313 r->set_position (r->position() + distance);
314 _session->add_command (new StatefulDiffCommand (r));
317 commit_reversible_command ();
320 } else if (!force_playhead && !selection->markers.empty()) {
324 begin_reversible_command (_("nudge location forward"));
326 for (MarkerSelection::iterator i = selection->markers.begin(); i != selection->markers.end(); ++i) {
328 Location* loc = find_location_from_marker ((*i), is_start);
332 XMLNode& before (loc->get_state());
335 distance = get_nudge_distance (loc->start(), next_distance);
337 distance = next_distance;
339 if (max_framepos - distance > loc->start() + loc->length()) {
340 loc->set_start (loc->start() + distance);
342 loc->set_start (max_framepos - loc->length());
345 distance = get_nudge_distance (loc->end(), next_distance);
347 distance = next_distance;
349 if (max_framepos - distance > loc->end()) {
350 loc->set_end (loc->end() + distance);
352 loc->set_end (max_framepos);
355 XMLNode& after (loc->get_state());
356 _session->add_command (new MementoCommand<Location>(*loc, &before, &after));
360 commit_reversible_command ();
363 distance = get_nudge_distance (playhead_cursor->current_frame (), next_distance);
364 _session->request_locate (playhead_cursor->current_frame () + distance);
369 Editor::nudge_backward (bool next, bool force_playhead)
372 framepos_t next_distance;
378 RegionSelection rs = get_regions_from_selection_and_entered ();
380 if (!force_playhead && !rs.empty()) {
382 begin_reversible_command (_("nudge regions backward"));
384 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
385 boost::shared_ptr<Region> r ((*i)->region());
387 distance = get_nudge_distance (r->position(), next_distance);
390 distance = next_distance;
395 if (r->position() > distance) {
396 r->set_position (r->position() - distance);
400 _session->add_command (new StatefulDiffCommand (r));
403 commit_reversible_command ();
405 } else if (!force_playhead && !selection->markers.empty()) {
409 begin_reversible_command (_("nudge location forward"));
411 for (MarkerSelection::iterator i = selection->markers.begin(); i != selection->markers.end(); ++i) {
413 Location* loc = find_location_from_marker ((*i), is_start);
417 XMLNode& before (loc->get_state());
420 distance = get_nudge_distance (loc->start(), next_distance);
422 distance = next_distance;
424 if (distance < loc->start()) {
425 loc->set_start (loc->start() - distance);
430 distance = get_nudge_distance (loc->end(), next_distance);
433 distance = next_distance;
436 if (distance < loc->end() - loc->length()) {
437 loc->set_end (loc->end() - distance);
439 loc->set_end (loc->length());
443 XMLNode& after (loc->get_state());
444 _session->add_command (new MementoCommand<Location>(*loc, &before, &after));
448 commit_reversible_command ();
452 distance = get_nudge_distance (playhead_cursor->current_frame (), next_distance);
454 if (playhead_cursor->current_frame () > distance) {
455 _session->request_locate (playhead_cursor->current_frame () - distance);
457 _session->goto_start();
463 Editor::nudge_forward_capture_offset ()
465 RegionSelection rs = get_regions_from_selection_and_entered ();
467 if (!_session || rs.empty()) {
471 begin_reversible_command (_("nudge forward"));
473 framepos_t const distance = _session->worst_output_latency();
475 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
476 boost::shared_ptr<Region> r ((*i)->region());
479 r->set_position (r->position() + distance);
480 _session->add_command(new StatefulDiffCommand (r));
483 commit_reversible_command ();
487 Editor::nudge_backward_capture_offset ()
489 RegionSelection rs = get_regions_from_selection_and_entered ();
491 if (!_session || rs.empty()) {
495 begin_reversible_command (_("nudge backward"));
497 framepos_t const distance = _session->worst_output_latency();
499 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
500 boost::shared_ptr<Region> r ((*i)->region());
504 if (r->position() > distance) {
505 r->set_position (r->position() - distance);
509 _session->add_command(new StatefulDiffCommand (r));
512 commit_reversible_command ();
515 struct RegionSelectionPositionSorter {
516 bool operator() (RegionView* a, RegionView* b) {
517 return a->region()->position() < b->region()->position();
522 Editor::sequence_regions ()
525 framepos_t r_end_prev;
533 RegionSelection rs = get_regions_from_selection_and_entered ();
534 rs.sort(RegionSelectionPositionSorter());
538 begin_reversible_command (_("sequence regions"));
539 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
540 boost::shared_ptr<Region> r ((*i)->region());
548 if(r->position_locked())
555 r->set_position(r_end_prev);
558 _session->add_command (new StatefulDiffCommand (r));
560 r_end=r->position() + r->length();
564 commit_reversible_command ();
572 Editor::move_to_start ()
574 _session->goto_start ();
578 Editor::move_to_end ()
581 _session->request_locate (_session->current_end_frame());
585 Editor::build_region_boundary_cache ()
588 vector<RegionPoint> interesting_points;
589 boost::shared_ptr<Region> r;
590 TrackViewList tracks;
593 region_boundary_cache.clear ();
599 switch (_snap_type) {
600 case SnapToRegionStart:
601 interesting_points.push_back (Start);
603 case SnapToRegionEnd:
604 interesting_points.push_back (End);
606 case SnapToRegionSync:
607 interesting_points.push_back (SyncPoint);
609 case SnapToRegionBoundary:
610 interesting_points.push_back (Start);
611 interesting_points.push_back (End);
614 fatal << string_compose (_("build_region_boundary_cache called with snap_type = %1"), _snap_type) << endmsg;
619 TimeAxisView *ontrack = 0;
622 if (!selection->tracks.empty()) {
623 tlist = selection->tracks.filter_to_unique_playlists ();
625 tlist = track_views.filter_to_unique_playlists ();
628 while (pos < _session->current_end_frame() && !at_end) {
631 framepos_t lpos = max_framepos;
633 for (vector<RegionPoint>::iterator p = interesting_points.begin(); p != interesting_points.end(); ++p) {
635 if ((r = find_next_region (pos, *p, 1, tlist, &ontrack)) == 0) {
636 if (*p == interesting_points.back()) {
639 /* move to next point type */
645 rpos = r->first_frame();
649 rpos = r->last_frame();
653 rpos = r->sync_position ();
661 RouteTimeAxisView *rtav;
663 if (ontrack != 0 && (rtav = dynamic_cast<RouteTimeAxisView*>(ontrack)) != 0 ) {
664 if (rtav->track() != 0) {
665 speed = rtav->track()->speed();
669 rpos = track_frame_to_session_frame (rpos, speed);
675 /* prevent duplicates, but we don't use set<> because we want to be able
679 vector<framepos_t>::iterator ri;
681 for (ri = region_boundary_cache.begin(); ri != region_boundary_cache.end(); ++ri) {
687 if (ri == region_boundary_cache.end()) {
688 region_boundary_cache.push_back (rpos);
695 /* finally sort to be sure that the order is correct */
697 sort (region_boundary_cache.begin(), region_boundary_cache.end());
700 boost::shared_ptr<Region>
701 Editor::find_next_region (framepos_t frame, RegionPoint point, int32_t dir, TrackViewList& tracks, TimeAxisView **ontrack)
703 TrackViewList::iterator i;
704 framepos_t closest = max_framepos;
705 boost::shared_ptr<Region> ret;
709 framepos_t track_frame;
710 RouteTimeAxisView *rtav;
712 for (i = tracks.begin(); i != tracks.end(); ++i) {
715 boost::shared_ptr<Region> r;
718 if ( (rtav = dynamic_cast<RouteTimeAxisView*>(*i)) != 0 ) {
719 if (rtav->track()!=0)
720 track_speed = rtav->track()->speed();
723 track_frame = session_frame_to_track_frame(frame, track_speed);
725 if ((r = (*i)->find_next_region (track_frame, point, dir)) == 0) {
731 rpos = r->first_frame ();
735 rpos = r->last_frame ();
739 rpos = r->sync_position ();
743 // rpos is a "track frame", converting it to "_session frame"
744 rpos = track_frame_to_session_frame(rpos, track_speed);
747 distance = rpos - frame;
749 distance = frame - rpos;
752 if (distance < closest) {
764 Editor::find_next_region_boundary (framepos_t pos, int32_t dir, const TrackViewList& tracks)
766 framecnt_t distance = max_framepos;
767 framepos_t current_nearest = -1;
769 for (TrackViewList::const_iterator i = tracks.begin(); i != tracks.end(); ++i) {
770 framepos_t contender;
773 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*i);
779 if ((contender = rtv->find_next_region_boundary (pos, dir)) < 0) {
783 d = ::llabs (pos - contender);
786 current_nearest = contender;
791 return current_nearest;
795 Editor::get_region_boundary (framepos_t pos, int32_t dir, bool with_selection, bool only_onscreen)
800 if (with_selection && Config->get_region_boundaries_from_selected_tracks()) {
802 if (!selection->tracks.empty()) {
804 target = find_next_region_boundary (pos, dir, selection->tracks);
808 if (only_onscreen || Config->get_region_boundaries_from_onscreen_tracks()) {
809 get_onscreen_tracks (tvl);
810 target = find_next_region_boundary (pos, dir, tvl);
812 target = find_next_region_boundary (pos, dir, track_views);
818 if (only_onscreen || Config->get_region_boundaries_from_onscreen_tracks()) {
819 get_onscreen_tracks (tvl);
820 target = find_next_region_boundary (pos, dir, tvl);
822 target = find_next_region_boundary (pos, dir, track_views);
830 Editor::cursor_to_region_boundary (bool with_selection, int32_t dir)
832 framepos_t pos = playhead_cursor->current_frame ();
839 // so we don't find the current region again..
840 if (dir > 0 || pos > 0) {
844 if ((target = get_region_boundary (pos, dir, with_selection, false)) < 0) {
848 _session->request_locate (target);
852 Editor::cursor_to_next_region_boundary (bool with_selection)
854 cursor_to_region_boundary (with_selection, 1);
858 Editor::cursor_to_previous_region_boundary (bool with_selection)
860 cursor_to_region_boundary (with_selection, -1);
864 Editor::cursor_to_region_point (EditorCursor* cursor, RegionPoint point, int32_t dir)
866 boost::shared_ptr<Region> r;
867 framepos_t pos = cursor->current_frame ();
873 TimeAxisView *ontrack = 0;
875 // so we don't find the current region again..
879 if (!selection->tracks.empty()) {
881 r = find_next_region (pos, point, dir, selection->tracks, &ontrack);
883 } else if (clicked_axisview) {
886 t.push_back (clicked_axisview);
888 r = find_next_region (pos, point, dir, t, &ontrack);
892 r = find_next_region (pos, point, dir, track_views, &ontrack);
901 pos = r->first_frame ();
905 pos = r->last_frame ();
909 pos = r->sync_position ();
914 RouteTimeAxisView *rtav;
916 if ( ontrack != 0 && (rtav = dynamic_cast<RouteTimeAxisView*>(ontrack)) != 0 ) {
917 if (rtav->track() != 0) {
918 speed = rtav->track()->speed();
922 pos = track_frame_to_session_frame(pos, speed);
924 if (cursor == playhead_cursor) {
925 _session->request_locate (pos);
927 cursor->set_position (pos);
932 Editor::cursor_to_next_region_point (EditorCursor* cursor, RegionPoint point)
934 cursor_to_region_point (cursor, point, 1);
938 Editor::cursor_to_previous_region_point (EditorCursor* cursor, RegionPoint point)
940 cursor_to_region_point (cursor, point, -1);
944 Editor::cursor_to_selection_start (EditorCursor *cursor)
948 switch (mouse_mode) {
950 if (!selection->regions.empty()) {
951 pos = selection->regions.start();
956 if (!selection->time.empty()) {
957 pos = selection->time.start ();
965 if (cursor == playhead_cursor) {
966 _session->request_locate (pos);
968 cursor->set_position (pos);
973 Editor::cursor_to_selection_end (EditorCursor *cursor)
977 switch (mouse_mode) {
979 if (!selection->regions.empty()) {
980 pos = selection->regions.end_frame();
985 if (!selection->time.empty()) {
986 pos = selection->time.end_frame ();
994 if (cursor == playhead_cursor) {
995 _session->request_locate (pos);
997 cursor->set_position (pos);
1002 Editor::selected_marker_to_region_boundary (bool with_selection, int32_t dir)
1012 if (selection->markers.empty()) {
1016 if (!mouse_frame (mouse, ignored)) {
1020 add_location_mark (mouse);
1023 if ((loc = find_location_from_marker (selection->markers.front(), ignored)) == 0) {
1027 framepos_t pos = loc->start();
1029 // so we don't find the current region again..
1030 if (dir > 0 || pos > 0) {
1034 if ((target = get_region_boundary (pos, dir, with_selection, false)) < 0) {
1038 loc->move_to (target);
1042 Editor::selected_marker_to_next_region_boundary (bool with_selection)
1044 selected_marker_to_region_boundary (with_selection, 1);
1048 Editor::selected_marker_to_previous_region_boundary (bool with_selection)
1050 selected_marker_to_region_boundary (with_selection, -1);
1054 Editor::selected_marker_to_region_point (RegionPoint point, int32_t dir)
1056 boost::shared_ptr<Region> r;
1061 if (!_session || selection->markers.empty()) {
1065 if ((loc = find_location_from_marker (selection->markers.front(), ignored)) == 0) {
1069 TimeAxisView *ontrack = 0;
1073 // so we don't find the current region again..
1077 if (!selection->tracks.empty()) {
1079 r = find_next_region (pos, point, dir, selection->tracks, &ontrack);
1083 r = find_next_region (pos, point, dir, track_views, &ontrack);
1092 pos = r->first_frame ();
1096 pos = r->last_frame ();
1100 pos = r->adjust_to_sync (r->first_frame());
1105 RouteTimeAxisView *rtav;
1107 if (ontrack != 0 && (rtav = dynamic_cast<RouteTimeAxisView*>(ontrack)) != 0) {
1108 if (rtav->track() != 0) {
1109 speed = rtav->track()->speed();
1113 pos = track_frame_to_session_frame(pos, speed);
1119 Editor::selected_marker_to_next_region_point (RegionPoint point)
1121 selected_marker_to_region_point (point, 1);
1125 Editor::selected_marker_to_previous_region_point (RegionPoint point)
1127 selected_marker_to_region_point (point, -1);
1131 Editor::selected_marker_to_selection_start ()
1137 if (!_session || selection->markers.empty()) {
1141 if ((loc = find_location_from_marker (selection->markers.front(), ignored)) == 0) {
1145 switch (mouse_mode) {
1147 if (!selection->regions.empty()) {
1148 pos = selection->regions.start();
1153 if (!selection->time.empty()) {
1154 pos = selection->time.start ();
1166 Editor::selected_marker_to_selection_end ()
1172 if (!_session || selection->markers.empty()) {
1176 if ((loc = find_location_from_marker (selection->markers.front(), ignored)) == 0) {
1180 switch (mouse_mode) {
1182 if (!selection->regions.empty()) {
1183 pos = selection->regions.end_frame();
1188 if (!selection->time.empty()) {
1189 pos = selection->time.end_frame ();
1201 Editor::scroll_playhead (bool forward)
1203 framepos_t pos = playhead_cursor->current_frame ();
1204 framecnt_t delta = (framecnt_t) floor (current_page_samples() / 0.8);
1207 if (pos == max_framepos) {
1211 if (pos < max_framepos - delta) {
1230 _session->request_locate (pos);
1234 Editor::cursor_align (bool playhead_to_edit)
1240 if (playhead_to_edit) {
1242 if (selection->markers.empty()) {
1246 _session->request_locate (selection->markers.front()->position(), _session->transport_rolling());
1249 /* move selected markers to playhead */
1251 for (MarkerSelection::iterator i = selection->markers.begin(); i != selection->markers.end(); ++i) {
1254 Location* loc = find_location_from_marker (*i, ignored);
1256 if (loc->is_mark()) {
1257 loc->set_start (playhead_cursor->current_frame ());
1259 loc->set (playhead_cursor->current_frame (),
1260 playhead_cursor->current_frame () + loc->length());
1267 Editor::scroll_backward (float pages)
1269 framepos_t const one_page = (framepos_t) rint (_visible_canvas_width * samples_per_pixel);
1270 framepos_t const cnt = (framepos_t) floor (pages * one_page);
1273 if (leftmost_frame < cnt) {
1276 frame = leftmost_frame - cnt;
1279 reset_x_origin (frame);
1283 Editor::scroll_forward (float pages)
1285 framepos_t const one_page = (framepos_t) rint (_visible_canvas_width * samples_per_pixel);
1286 framepos_t const cnt = (framepos_t) floor (pages * one_page);
1289 if (max_framepos - cnt < leftmost_frame) {
1290 frame = max_framepos - cnt;
1292 frame = leftmost_frame + cnt;
1295 reset_x_origin (frame);
1299 Editor::scroll_tracks_down ()
1301 double vert_value = vertical_adjustment.get_value() + vertical_adjustment.get_page_size();
1302 if (vert_value > vertical_adjustment.get_upper() - _visible_canvas_height) {
1303 vert_value = vertical_adjustment.get_upper() - _visible_canvas_height;
1306 vertical_adjustment.set_value (vert_value);
1310 Editor::scroll_tracks_up ()
1312 vertical_adjustment.set_value (vertical_adjustment.get_value() - vertical_adjustment.get_page_size());
1316 Editor::scroll_tracks_down_line ()
1318 double vert_value = vertical_adjustment.get_value() + 60;
1320 if (vert_value > vertical_adjustment.get_upper() - _visible_canvas_height) {
1321 vert_value = vertical_adjustment.get_upper() - _visible_canvas_height;
1324 vertical_adjustment.set_value (vert_value);
1328 Editor::scroll_tracks_up_line ()
1330 reset_y_origin (vertical_adjustment.get_value() - 60);
1334 Editor::scroll_down_one_track ()
1336 double vertical_pos = vertical_adjustment.get_value () + vertical_adjustment.get_page_size() - 1.0;
1338 TrackViewList::reverse_iterator next = track_views.rend();
1339 std::pair<TimeAxisView*,double> res;
1341 for (TrackViewList::reverse_iterator t = track_views.rbegin(); t != track_views.rend(); ++t) {
1342 if ((*t)->hidden()) {
1346 res = (*t)->covers_y_position (vertical_pos);
1355 /* move to the track below the first one that covers the */
1357 if (next != track_views.rend()) {
1358 ensure_track_visible (*next);
1366 Editor::scroll_up_one_track ()
1368 double vertical_pos = vertical_adjustment.get_value ();
1370 TrackViewList::iterator prev = track_views.end();
1371 std::pair<TimeAxisView*,double> res;
1373 for (TrackViewList::iterator t = track_views.begin(); t != track_views.end(); ++t) {
1375 if ((*t)->hidden()) {
1379 res = (*t)->covers_y_position(vertical_pos);
1388 if (prev != track_views.end()) {
1389 ensure_track_visible (*prev);
1399 Editor::tav_zoom_step (bool coarser)
1401 _routes->suspend_redisplay ();
1405 if (selection->tracks.empty()) {
1408 ts = &selection->tracks;
1411 for (TrackViewList::iterator i = ts->begin(); i != ts->end(); ++i) {
1412 TimeAxisView *tv = (static_cast<TimeAxisView*>(*i));
1413 tv->step_height (coarser);
1416 _routes->resume_redisplay ();
1420 Editor::tav_zoom_smooth (bool coarser, bool force_all)
1422 _routes->suspend_redisplay ();
1426 if (selection->tracks.empty() || force_all) {
1429 ts = &selection->tracks;
1432 for (TrackViewList::iterator i = ts->begin(); i != ts->end(); ++i) {
1433 TimeAxisView *tv = (static_cast<TimeAxisView*>(*i));
1434 uint32_t h = tv->current_height ();
1439 if (h >= TimeAxisView::preset_height (HeightSmall)) {
1444 tv->set_height (h + 5);
1448 _routes->resume_redisplay ();
1452 Editor::clamp_samples_per_pixel (framecnt_t& fpp) const
1454 bool clamped = false;
1461 if (max_framepos / fpp < 800) {
1462 fpp = max_framepos / 800;
1470 Editor::temporal_zoom_step (bool coarser)
1472 ENSURE_GUI_THREAD (*this, &Editor::temporal_zoom_step, coarser)
1474 framecnt_t nspp = samples_per_pixel;
1482 temporal_zoom (nspp);
1486 Editor::temporal_zoom (framecnt_t fpp)
1492 framepos_t current_page = current_page_samples();
1493 framepos_t current_leftmost = leftmost_frame;
1494 framepos_t current_rightmost;
1495 framepos_t current_center;
1496 framepos_t new_page_size;
1497 framepos_t half_page_size;
1498 framepos_t leftmost_after_zoom = 0;
1500 bool in_track_canvas;
1504 clamp_samples_per_pixel (fpp);
1505 if (fpp == samples_per_pixel) {
1509 // Imposing an arbitrary limit to zoom out as too much zoom out produces
1510 // segfaults for lack of memory. If somebody decides this is not high enough I
1511 // believe it can be raisen to higher values but some limit must be in place.
1513 // This constant represents 1 day @ 48kHz on a 1600 pixel wide display
1514 // all of which is used for the editor track displays. The whole day
1515 // would be 4147200000 samples, so 2592000 samples per pixel.
1517 nfpp = min (fpp, (framecnt_t) 2592000);
1518 nfpp = max ((framecnt_t) 1, fpp);
1520 new_page_size = (framepos_t) floor (_visible_canvas_width * nfpp);
1521 half_page_size = new_page_size / 2;
1523 switch (zoom_focus) {
1525 leftmost_after_zoom = current_leftmost;
1528 case ZoomFocusRight:
1529 current_rightmost = leftmost_frame + current_page;
1530 if (current_rightmost < new_page_size) {
1531 leftmost_after_zoom = 0;
1533 leftmost_after_zoom = current_rightmost - new_page_size;
1537 case ZoomFocusCenter:
1538 current_center = current_leftmost + (current_page/2);
1539 if (current_center < half_page_size) {
1540 leftmost_after_zoom = 0;
1542 leftmost_after_zoom = current_center - half_page_size;
1546 case ZoomFocusPlayhead:
1547 /* centre playhead */
1548 l = playhead_cursor->current_frame () - (new_page_size * 0.5);
1551 leftmost_after_zoom = 0;
1552 } else if (l > max_framepos) {
1553 leftmost_after_zoom = max_framepos - new_page_size;
1555 leftmost_after_zoom = (framepos_t) l;
1559 case ZoomFocusMouse:
1560 /* try to keep the mouse over the same point in the display */
1562 if (!mouse_frame (where, in_track_canvas)) {
1563 /* use playhead instead */
1564 where = playhead_cursor->current_frame ();
1566 if (where < half_page_size) {
1567 leftmost_after_zoom = 0;
1569 leftmost_after_zoom = where - half_page_size;
1574 l = - ((new_page_size * ((where - current_leftmost)/(double)current_page)) - where);
1577 leftmost_after_zoom = 0;
1578 } else if (l > max_framepos) {
1579 leftmost_after_zoom = max_framepos - new_page_size;
1581 leftmost_after_zoom = (framepos_t) l;
1588 /* try to keep the edit point in the same place */
1589 where = get_preferred_edit_position ();
1593 double l = - ((new_page_size * ((where - current_leftmost)/(double)current_page)) - where);
1596 leftmost_after_zoom = 0;
1597 } else if (l > max_framepos) {
1598 leftmost_after_zoom = max_framepos - new_page_size;
1600 leftmost_after_zoom = (framepos_t) l;
1604 /* edit point not defined */
1611 // leftmost_after_zoom = min (leftmost_after_zoom, _session->current_end_frame());
1613 reposition_and_zoom (leftmost_after_zoom, nfpp);
1617 Editor::temporal_zoom_region (bool both_axes)
1619 framepos_t start = max_framepos;
1621 set<TimeAxisView*> tracks;
1623 RegionSelection rs = get_regions_from_selection_and_entered ();
1629 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
1631 if ((*i)->region()->position() < start) {
1632 start = (*i)->region()->position();
1635 if ((*i)->region()->last_frame() + 1 > end) {
1636 end = (*i)->region()->last_frame() + 1;
1639 tracks.insert (&((*i)->get_time_axis_view()));
1642 /* now comes an "interesting" hack ... make sure we leave a little space
1643 at each end of the editor so that the zoom doesn't fit the region
1644 precisely to the screen.
1647 GdkScreen* screen = gdk_screen_get_default ();
1648 gint pixwidth = gdk_screen_get_width (screen);
1649 gint mmwidth = gdk_screen_get_width_mm (screen);
1650 double pix_per_mm = (double) pixwidth/ (double) mmwidth;
1651 double one_centimeter_in_pixels = pix_per_mm * 10.0;
1653 if ((start == 0 && end == 0) || end < start) {
1657 framepos_t range = end - start;
1658 double new_fpp = (double) range / (double) _visible_canvas_width;
1659 framepos_t extra_samples = (framepos_t) floor (one_centimeter_in_pixels * new_fpp);
1661 if (start > extra_samples) {
1662 start -= extra_samples;
1667 if (max_framepos - extra_samples > end) {
1668 end += extra_samples;
1673 /* if we're zooming on both axes we need to save track heights etc.
1676 undo_visual_stack.push_back (current_visual_state (both_axes));
1678 PBD::Unwinder<bool> nsv (no_save_visual, true);
1680 temporal_zoom_by_frame (start, end);
1683 uint32_t per_track_height = (uint32_t) floor ((_visible_canvas_height - 10.0) / tracks.size());
1685 /* set visible track heights appropriately */
1687 for (set<TimeAxisView*>::iterator t = tracks.begin(); t != tracks.end(); ++t) {
1688 (*t)->set_height (per_track_height);
1691 /* hide irrelevant tracks */
1693 _routes->suspend_redisplay ();
1695 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1696 if (find (tracks.begin(), tracks.end(), (*i)) == tracks.end()) {
1697 hide_track_in_display (*i);
1701 _routes->resume_redisplay ();
1703 vertical_adjustment.set_value (0.0);
1706 redo_visual_stack.push_back (current_visual_state (both_axes));
1710 Editor::zoom_to_region (bool both_axes)
1712 temporal_zoom_region (both_axes);
1716 Editor::temporal_zoom_selection ()
1718 if (!selection) return;
1720 if (selection->time.empty()) {
1724 framepos_t start = selection->time[clicked_selection].start;
1725 framepos_t end = selection->time[clicked_selection].end;
1727 temporal_zoom_by_frame (start, end);
1731 Editor::temporal_zoom_session ()
1733 ENSURE_GUI_THREAD (*this, &Editor::temporal_zoom_session)
1736 framecnt_t const l = _session->current_end_frame() - _session->current_start_frame();
1737 double s = _session->current_start_frame() - l * 0.01;
1741 framecnt_t const e = _session->current_end_frame() + l * 0.01;
1742 temporal_zoom_by_frame (framecnt_t (s), e);
1747 Editor::temporal_zoom_by_frame (framepos_t start, framepos_t end)
1749 if (!_session) return;
1751 if ((start == 0 && end == 0) || end < start) {
1755 framepos_t range = end - start;
1757 double const new_fpp = (double) range / (double) _visible_canvas_width;
1759 framepos_t new_page = (framepos_t) floor (_visible_canvas_width * new_fpp);
1760 framepos_t middle = (framepos_t) floor ((double) start + ((double) range / 2.0f));
1761 framepos_t new_leftmost = (framepos_t) floor ((double) middle - ((double) new_page / 2.0f));
1763 if (new_leftmost > middle) {
1767 if (new_leftmost < 0) {
1771 reposition_and_zoom (new_leftmost, new_fpp);
1775 Editor::temporal_zoom_to_frame (bool coarser, framepos_t frame)
1780 double range_before = frame - leftmost_frame;
1783 new_fpp = samples_per_pixel;
1786 new_fpp *= 1.61803399;
1787 range_before *= 1.61803399;
1789 new_fpp = max(1.0,(new_fpp/1.61803399));
1790 range_before /= 1.61803399;
1793 if (new_fpp == samples_per_pixel) {
1797 framepos_t new_leftmost = frame - (framepos_t)range_before;
1799 if (new_leftmost > frame) {
1803 if (new_leftmost < 0) {
1807 reposition_and_zoom (new_leftmost, new_fpp);
1812 Editor::choose_new_marker_name(string &name) {
1814 if (!Config->get_name_new_markers()) {
1815 /* don't prompt user for a new name */
1819 ArdourPrompter dialog (true);
1821 dialog.set_prompt (_("New Name:"));
1823 dialog.set_title (_("New Location Marker"));
1825 dialog.set_name ("MarkNameWindow");
1826 dialog.set_size_request (250, -1);
1827 dialog.set_position (Gtk::WIN_POS_MOUSE);
1829 dialog.add_button (Stock::OK, RESPONSE_ACCEPT);
1830 dialog.set_initial_text (name);
1834 switch (dialog.run ()) {
1835 case RESPONSE_ACCEPT:
1841 dialog.get_result(name);
1848 Editor::add_location_from_selection ()
1852 if (selection->time.empty()) {
1856 if (_session == 0 || clicked_axisview == 0) {
1860 framepos_t start = selection->time[clicked_selection].start;
1861 framepos_t end = selection->time[clicked_selection].end;
1863 _session->locations()->next_available_name(rangename,"selection");
1864 Location *location = new Location (*_session, start, end, rangename, Location::IsRangeMarker);
1866 _session->begin_reversible_command (_("add marker"));
1867 XMLNode &before = _session->locations()->get_state();
1868 _session->locations()->add (location, true);
1869 XMLNode &after = _session->locations()->get_state();
1870 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
1871 _session->commit_reversible_command ();
1875 Editor::add_location_mark (framepos_t where)
1879 select_new_marker = true;
1881 _session->locations()->next_available_name(markername,"mark");
1882 if (!choose_new_marker_name(markername)) {
1885 Location *location = new Location (*_session, where, where, markername, Location::IsMark);
1886 _session->begin_reversible_command (_("add marker"));
1887 XMLNode &before = _session->locations()->get_state();
1888 _session->locations()->add (location, true);
1889 XMLNode &after = _session->locations()->get_state();
1890 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
1891 _session->commit_reversible_command ();
1895 Editor::add_location_from_playhead_cursor ()
1897 add_location_mark (_session->audible_frame());
1900 /** Add a range marker around each selected region */
1902 Editor::add_locations_from_region ()
1904 RegionSelection rs = get_regions_from_selection_and_entered ();
1910 _session->begin_reversible_command (selection->regions.size () > 1 ? _("add markers") : _("add marker"));
1911 XMLNode &before = _session->locations()->get_state();
1913 for (RegionSelection::iterator i = rs.begin (); i != rs.end (); ++i) {
1915 boost::shared_ptr<Region> region = (*i)->region ();
1917 Location *location = new Location (*_session, region->position(), region->last_frame(), region->name(), Location::IsRangeMarker);
1919 _session->locations()->add (location, true);
1922 XMLNode &after = _session->locations()->get_state();
1923 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
1924 _session->commit_reversible_command ();
1927 /** Add a single range marker around all selected regions */
1929 Editor::add_location_from_region ()
1931 RegionSelection rs = get_regions_from_selection_and_entered ();
1937 _session->begin_reversible_command (_("add marker"));
1938 XMLNode &before = _session->locations()->get_state();
1942 if (rs.size() > 1) {
1943 _session->locations()->next_available_name(markername, "regions");
1945 RegionView* rv = *(rs.begin());
1946 boost::shared_ptr<Region> region = rv->region();
1947 markername = region->name();
1950 if (!choose_new_marker_name(markername)) {
1954 // single range spanning all selected
1955 Location *location = new Location (*_session, selection->regions.start(), selection->regions.end_frame(), markername, Location::IsRangeMarker);
1956 _session->locations()->add (location, true);
1958 XMLNode &after = _session->locations()->get_state();
1959 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
1960 _session->commit_reversible_command ();
1966 Editor::jump_forward_to_mark ()
1972 framepos_t pos = _session->locations()->first_mark_after (playhead_cursor->current_frame());
1978 _session->request_locate (pos, _session->transport_rolling());
1982 Editor::jump_backward_to_mark ()
1988 framepos_t pos = _session->locations()->first_mark_before (playhead_cursor->current_frame());
1994 _session->request_locate (pos, _session->transport_rolling());
2000 framepos_t const pos = _session->audible_frame ();
2003 _session->locations()->next_available_name (markername, "mark");
2005 if (!choose_new_marker_name (markername)) {
2009 _session->locations()->add (new Location (*_session, pos, 0, markername, Location::IsMark), true);
2013 Editor::clear_markers ()
2016 _session->begin_reversible_command (_("clear markers"));
2017 XMLNode &before = _session->locations()->get_state();
2018 _session->locations()->clear_markers ();
2019 XMLNode &after = _session->locations()->get_state();
2020 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2021 _session->commit_reversible_command ();
2026 Editor::clear_ranges ()
2029 _session->begin_reversible_command (_("clear ranges"));
2030 XMLNode &before = _session->locations()->get_state();
2032 Location * looploc = _session->locations()->auto_loop_location();
2033 Location * punchloc = _session->locations()->auto_punch_location();
2034 Location * sessionloc = _session->locations()->session_range_location();
2036 _session->locations()->clear_ranges ();
2038 if (looploc) _session->locations()->add (looploc);
2039 if (punchloc) _session->locations()->add (punchloc);
2040 if (sessionloc) _session->locations()->add (sessionloc);
2042 XMLNode &after = _session->locations()->get_state();
2043 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2044 _session->commit_reversible_command ();
2049 Editor::clear_locations ()
2051 _session->begin_reversible_command (_("clear locations"));
2052 XMLNode &before = _session->locations()->get_state();
2053 _session->locations()->clear ();
2054 XMLNode &after = _session->locations()->get_state();
2055 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2056 _session->commit_reversible_command ();
2057 _session->locations()->clear ();
2061 Editor::unhide_markers ()
2063 for (LocationMarkerMap::iterator i = location_markers.begin(); i != location_markers.end(); ++i) {
2064 Location *l = (*i).first;
2065 if (l->is_hidden() && l->is_mark()) {
2066 l->set_hidden(false, this);
2072 Editor::unhide_ranges ()
2074 for (LocationMarkerMap::iterator i = location_markers.begin(); i != location_markers.end(); ++i) {
2075 Location *l = (*i).first;
2076 if (l->is_hidden() && l->is_range_marker()) {
2077 l->set_hidden(false, this);
2082 /* INSERT/REPLACE */
2085 Editor::insert_region_list_selection (float times)
2087 RouteTimeAxisView *tv = 0;
2088 boost::shared_ptr<Playlist> playlist;
2090 if (clicked_routeview != 0) {
2091 tv = clicked_routeview;
2092 } else if (!selection->tracks.empty()) {
2093 if ((tv = dynamic_cast<RouteTimeAxisView*>(selection->tracks.front())) == 0) {
2096 } else if (entered_track != 0) {
2097 if ((tv = dynamic_cast<RouteTimeAxisView*>(entered_track)) == 0) {
2104 if ((playlist = tv->playlist()) == 0) {
2108 boost::shared_ptr<Region> region = _regions->get_single_selection ();
2113 begin_reversible_command (_("insert region"));
2114 playlist->clear_changes ();
2115 playlist->add_region ((RegionFactory::create (region, true)), get_preferred_edit_position(), times);
2116 if (Config->get_edit_mode() == Ripple)
2117 playlist->ripple (get_preferred_edit_position(), region->length() * times, boost::shared_ptr<Region>());
2119 _session->add_command(new StatefulDiffCommand (playlist));
2120 commit_reversible_command ();
2123 /* BUILT-IN EFFECTS */
2126 Editor::reverse_selection ()
2131 /* GAIN ENVELOPE EDITING */
2134 Editor::edit_envelope ()
2141 Editor::transition_to_rolling (bool fwd)
2147 if (_session->config.get_external_sync()) {
2148 switch (Config->get_sync_source()) {
2152 /* transport controlled by the master */
2157 if (_session->is_auditioning()) {
2158 _session->cancel_audition ();
2162 _session->request_transport_speed (fwd ? 1.0f : -1.0f);
2166 Editor::play_from_start ()
2168 _session->request_locate (_session->current_start_frame(), true);
2172 Editor::play_from_edit_point ()
2174 _session->request_locate (get_preferred_edit_position(), true);
2178 Editor::play_from_edit_point_and_return ()
2180 framepos_t start_frame;
2181 framepos_t return_frame;
2183 start_frame = get_preferred_edit_position (true);
2185 if (_session->transport_rolling()) {
2186 _session->request_locate (start_frame, false);
2190 /* don't reset the return frame if its already set */
2192 if ((return_frame = _session->requested_return_frame()) < 0) {
2193 return_frame = _session->audible_frame();
2196 if (start_frame >= 0) {
2197 _session->request_roll_at_and_return (start_frame, return_frame);
2202 Editor::play_selection ()
2204 if (selection->time.empty()) {
2208 _session->request_play_range (&selection->time, true);
2212 Editor::get_preroll ()
2214 return 1.0 /*Config->get_edit_preroll_seconds()*/ * _session->frame_rate();
2219 Editor::maybe_locate_with_edit_preroll ( framepos_t location )
2221 if ( _session->transport_rolling() || !Config->get_always_play_range() )
2224 location -= get_preroll();
2226 //don't try to locate before the beginning of time
2230 //if follow_playhead is on, keep the playhead on the screen
2231 if ( _follow_playhead )
2232 if ( location < leftmost_frame )
2233 location = leftmost_frame;
2235 _session->request_locate( location );
2239 Editor::play_with_preroll ()
2241 if (selection->time.empty()) {
2244 framepos_t preroll = get_preroll();
2246 framepos_t start = 0;
2247 if (selection->time[clicked_selection].start > preroll)
2248 start = selection->time[clicked_selection].start - preroll;
2250 framepos_t end = selection->time[clicked_selection].end + preroll;
2252 AudioRange ar (start, end, 0);
2253 list<AudioRange> lar;
2256 _session->request_play_range (&lar, true);
2261 Editor::play_location (Location& location)
2263 if (location.start() <= location.end()) {
2267 _session->request_bounded_roll (location.start(), location.end());
2271 Editor::loop_location (Location& location)
2273 if (location.start() <= location.end()) {
2279 if ((tll = transport_loop_location()) != 0) {
2280 tll->set (location.start(), location.end());
2282 // enable looping, reposition and start rolling
2283 _session->request_play_loop (true);
2284 _session->request_locate (tll->start(), true);
2289 Editor::do_layer_operation (LayerOperation op)
2291 if (selection->regions.empty ()) {
2295 bool const multiple = selection->regions.size() > 1;
2299 begin_reversible_command (_("raise regions"));
2301 begin_reversible_command (_("raise region"));
2307 begin_reversible_command (_("raise regions to top"));
2309 begin_reversible_command (_("raise region to top"));
2315 begin_reversible_command (_("lower regions"));
2317 begin_reversible_command (_("lower region"));
2323 begin_reversible_command (_("lower regions to bottom"));
2325 begin_reversible_command (_("lower region"));
2330 set<boost::shared_ptr<Playlist> > playlists = selection->regions.playlists ();
2331 for (set<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
2332 (*i)->clear_owned_changes ();
2335 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
2336 boost::shared_ptr<Region> r = (*i)->region ();
2348 r->lower_to_bottom ();
2352 for (set<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
2353 vector<Command*> cmds;
2355 _session->add_commands (cmds);
2358 commit_reversible_command ();
2362 Editor::raise_region ()
2364 do_layer_operation (Raise);
2368 Editor::raise_region_to_top ()
2370 do_layer_operation (RaiseToTop);
2374 Editor::lower_region ()
2376 do_layer_operation (Lower);
2380 Editor::lower_region_to_bottom ()
2382 do_layer_operation (LowerToBottom);
2385 /** Show the region editor for the selected regions */
2387 Editor::show_region_properties ()
2389 selection->foreach_regionview (&RegionView::show_region_editor);
2392 /** Show the midi list editor for the selected MIDI regions */
2394 Editor::show_midi_list_editor ()
2396 selection->foreach_midi_regionview (&MidiRegionView::show_list_editor);
2400 Editor::rename_region ()
2402 RegionSelection rs = get_regions_from_selection_and_entered ();
2408 ArdourDialog d (*this, _("Rename Region"), true, false);
2410 Label label (_("New name:"));
2413 hbox.set_spacing (6);
2414 hbox.pack_start (label, false, false);
2415 hbox.pack_start (entry, true, true);
2417 d.get_vbox()->set_border_width (12);
2418 d.get_vbox()->pack_start (hbox, false, false);
2420 d.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
2421 d.add_button(Gtk::Stock::OK, Gtk::RESPONSE_OK);
2423 d.set_size_request (300, -1);
2425 entry.set_text (rs.front()->region()->name());
2426 entry.select_region (0, -1);
2428 entry.signal_activate().connect (sigc::bind (sigc::mem_fun (d, &Dialog::response), RESPONSE_OK));
2434 int const ret = d.run();
2438 if (ret != RESPONSE_OK) {
2442 std::string str = entry.get_text();
2443 strip_whitespace_edges (str);
2445 rs.front()->region()->set_name (str);
2446 _regions->redisplay ();
2451 Editor::audition_playlist_region_via_route (boost::shared_ptr<Region> region, Route& route)
2453 if (_session->is_auditioning()) {
2454 _session->cancel_audition ();
2457 // note: some potential for creativity here, because region doesn't
2458 // have to belong to the playlist that Route is handling
2460 // bool was_soloed = route.soloed();
2462 route.set_solo (true, this);
2464 _session->request_bounded_roll (region->position(), region->position() + region->length());
2466 /* XXX how to unset the solo state ? */
2469 /** Start an audition of the first selected region */
2471 Editor::play_edit_range ()
2473 framepos_t start, end;
2475 if (get_edit_op_range (start, end)) {
2476 _session->request_bounded_roll (start, end);
2481 Editor::play_selected_region ()
2483 framepos_t start = max_framepos;
2486 RegionSelection rs = get_regions_from_selection_and_entered ();
2492 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
2493 if ((*i)->region()->position() < start) {
2494 start = (*i)->region()->position();
2496 if ((*i)->region()->last_frame() + 1 > end) {
2497 end = (*i)->region()->last_frame() + 1;
2501 _session->request_bounded_roll (start, end);
2505 Editor::audition_playlist_region_standalone (boost::shared_ptr<Region> region)
2507 _session->audition_region (region);
2511 Editor::region_from_selection ()
2513 if (clicked_axisview == 0) {
2517 if (selection->time.empty()) {
2521 framepos_t start = selection->time[clicked_selection].start;
2522 framepos_t end = selection->time[clicked_selection].end;
2524 TrackViewList tracks = get_tracks_for_range_action ();
2526 framepos_t selection_cnt = end - start + 1;
2528 for (TrackSelection::iterator i = tracks.begin(); i != tracks.end(); ++i) {
2529 boost::shared_ptr<Region> current;
2530 boost::shared_ptr<Playlist> pl;
2531 framepos_t internal_start;
2534 if ((pl = (*i)->playlist()) == 0) {
2538 if ((current = pl->top_region_at (start)) == 0) {
2542 internal_start = start - current->position();
2543 RegionFactory::region_name (new_name, current->name(), true);
2547 plist.add (ARDOUR::Properties::start, current->start() + internal_start);
2548 plist.add (ARDOUR::Properties::length, selection_cnt);
2549 plist.add (ARDOUR::Properties::name, new_name);
2550 plist.add (ARDOUR::Properties::layer, 0);
2552 boost::shared_ptr<Region> region (RegionFactory::create (current, plist));
2557 Editor::create_region_from_selection (vector<boost::shared_ptr<Region> >& new_regions)
2559 if (selection->time.empty() || selection->tracks.empty()) {
2563 framepos_t start = selection->time[clicked_selection].start;
2564 framepos_t end = selection->time[clicked_selection].end;
2566 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
2567 sort_track_selection (ts);
2569 for (TrackSelection::iterator i = ts.begin(); i != ts.end(); ++i) {
2570 boost::shared_ptr<Region> current;
2571 boost::shared_ptr<Playlist> playlist;
2572 framepos_t internal_start;
2575 if ((playlist = (*i)->playlist()) == 0) {
2579 if ((current = playlist->top_region_at(start)) == 0) {
2583 internal_start = start - current->position();
2584 RegionFactory::region_name (new_name, current->name(), true);
2588 plist.add (ARDOUR::Properties::start, current->start() + internal_start);
2589 plist.add (ARDOUR::Properties::length, end - start + 1);
2590 plist.add (ARDOUR::Properties::name, new_name);
2592 new_regions.push_back (RegionFactory::create (current, plist));
2597 Editor::split_multichannel_region ()
2599 RegionSelection rs = get_regions_from_selection_and_entered ();
2605 vector< boost::shared_ptr<Region> > v;
2607 for (list<RegionView*>::iterator x = rs.begin(); x != rs.end(); ++x) {
2608 (*x)->region()->separate_by_channel (*_session, v);
2613 Editor::new_region_from_selection ()
2615 region_from_selection ();
2616 cancel_selection ();
2620 add_if_covered (RegionView* rv, const AudioRange* ar, RegionSelection* rs)
2622 switch (rv->region()->coverage (ar->start, ar->end - 1)) {
2623 case Evoral::OverlapNone:
2631 * - selected tracks, or if there are none...
2632 * - tracks containing selected regions, or if there are none...
2637 Editor::get_tracks_for_range_action () const
2641 if (selection->tracks.empty()) {
2643 /* use tracks with selected regions */
2645 RegionSelection rs = selection->regions;
2647 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
2648 TimeAxisView* tv = &(*i)->get_time_axis_view();
2650 if (!t.contains (tv)) {
2656 /* no regions and no tracks: use all tracks */
2662 t = selection->tracks;
2665 return t.filter_to_unique_playlists();
2669 Editor::separate_regions_between (const TimeSelection& ts)
2671 bool in_command = false;
2672 boost::shared_ptr<Playlist> playlist;
2673 RegionSelection new_selection;
2675 TrackViewList tmptracks = get_tracks_for_range_action ();
2676 sort_track_selection (tmptracks);
2678 for (TrackSelection::iterator i = tmptracks.begin(); i != tmptracks.end(); ++i) {
2680 RouteTimeAxisView* rtv;
2682 if ((rtv = dynamic_cast<RouteTimeAxisView*> ((*i))) != 0) {
2684 if (rtv->is_track()) {
2686 /* no edits to destructive tracks */
2688 if (rtv->track()->destructive()) {
2692 if ((playlist = rtv->playlist()) != 0) {
2694 playlist->clear_changes ();
2696 /* XXX need to consider musical time selections here at some point */
2698 double speed = rtv->track()->speed();
2701 for (list<AudioRange>::const_iterator t = ts.begin(); t != ts.end(); ++t) {
2703 sigc::connection c = rtv->view()->RegionViewAdded.connect (
2704 sigc::mem_fun(*this, &Editor::collect_new_region_view));
2706 latest_regionviews.clear ();
2708 playlist->partition ((framepos_t)((*t).start * speed),
2709 (framepos_t)((*t).end * speed), false);
2713 if (!latest_regionviews.empty()) {
2715 rtv->view()->foreach_regionview (sigc::bind (
2716 sigc::ptr_fun (add_if_covered),
2717 &(*t), &new_selection));
2720 begin_reversible_command (_("separate"));
2724 /* pick up changes to existing regions */
2726 vector<Command*> cmds;
2727 playlist->rdiff (cmds);
2728 _session->add_commands (cmds);
2730 /* pick up changes to the playlist itself (adds/removes)
2733 _session->add_command(new StatefulDiffCommand (playlist));
2742 selection->set (new_selection);
2743 set_mouse_mode (MouseObject);
2745 commit_reversible_command ();
2749 struct PlaylistState {
2750 boost::shared_ptr<Playlist> playlist;
2754 /** Take tracks from get_tracks_for_range_action and cut any regions
2755 * on those tracks so that the tracks are empty over the time
2759 Editor::separate_region_from_selection ()
2761 /* preferentially use *all* ranges in the time selection if we're in range mode
2762 to allow discontiguous operation, since get_edit_op_range() currently
2763 returns a single range.
2766 if (!selection->time.empty()) {
2768 separate_regions_between (selection->time);
2775 if (get_edit_op_range (start, end)) {
2777 AudioRange ar (start, end, 1);
2781 separate_regions_between (ts);
2787 Editor::separate_region_from_punch ()
2789 Location* loc = _session->locations()->auto_punch_location();
2791 separate_regions_using_location (*loc);
2796 Editor::separate_region_from_loop ()
2798 Location* loc = _session->locations()->auto_loop_location();
2800 separate_regions_using_location (*loc);
2805 Editor::separate_regions_using_location (Location& loc)
2807 if (loc.is_mark()) {
2811 AudioRange ar (loc.start(), loc.end(), 1);
2816 separate_regions_between (ts);
2819 /** Separate regions under the selected region */
2821 Editor::separate_under_selected_regions ()
2823 vector<PlaylistState> playlists;
2827 rs = get_regions_from_selection_and_entered();
2829 if (!_session || rs.empty()) {
2833 begin_reversible_command (_("separate region under"));
2835 list<boost::shared_ptr<Region> > regions_to_remove;
2837 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
2838 // we can't just remove the region(s) in this loop because
2839 // this removes them from the RegionSelection, and they thus
2840 // disappear from underneath the iterator, and the ++i above
2841 // SEGVs in a puzzling fashion.
2843 // so, first iterate over the regions to be removed from rs and
2844 // add them to the regions_to_remove list, and then
2845 // iterate over the list to actually remove them.
2847 regions_to_remove.push_back ((*i)->region());
2850 for (list<boost::shared_ptr<Region> >::iterator rl = regions_to_remove.begin(); rl != regions_to_remove.end(); ++rl) {
2852 boost::shared_ptr<Playlist> playlist = (*rl)->playlist();
2855 // is this check necessary?
2859 vector<PlaylistState>::iterator i;
2861 //only take state if this is a new playlist.
2862 for (i = playlists.begin(); i != playlists.end(); ++i) {
2863 if ((*i).playlist == playlist) {
2868 if (i == playlists.end()) {
2870 PlaylistState before;
2871 before.playlist = playlist;
2872 before.before = &playlist->get_state();
2874 playlist->freeze ();
2875 playlists.push_back(before);
2878 //Partition on the region bounds
2879 playlist->partition ((*rl)->first_frame() - 1, (*rl)->last_frame() + 1, true);
2881 //Re-add region that was just removed due to the partition operation
2882 playlist->add_region( (*rl), (*rl)->first_frame() );
2885 vector<PlaylistState>::iterator pl;
2887 for (pl = playlists.begin(); pl != playlists.end(); ++pl) {
2888 (*pl).playlist->thaw ();
2889 _session->add_command(new MementoCommand<Playlist>(*(*pl).playlist, (*pl).before, &(*pl).playlist->get_state()));
2892 commit_reversible_command ();
2896 Editor::crop_region_to_selection ()
2898 if (!selection->time.empty()) {
2900 crop_region_to (selection->time.start(), selection->time.end_frame());
2907 if (get_edit_op_range (start, end)) {
2908 crop_region_to (start, end);
2915 Editor::crop_region_to (framepos_t start, framepos_t end)
2917 vector<boost::shared_ptr<Playlist> > playlists;
2918 boost::shared_ptr<Playlist> playlist;
2921 if (selection->tracks.empty()) {
2922 ts = track_views.filter_to_unique_playlists();
2924 ts = selection->tracks.filter_to_unique_playlists ();
2927 sort_track_selection (ts);
2929 for (TrackSelection::iterator i = ts.begin(); i != ts.end(); ++i) {
2931 RouteTimeAxisView* rtv;
2933 if ((rtv = dynamic_cast<RouteTimeAxisView*> ((*i))) != 0) {
2935 boost::shared_ptr<Track> t = rtv->track();
2937 if (t != 0 && ! t->destructive()) {
2939 if ((playlist = rtv->playlist()) != 0) {
2940 playlists.push_back (playlist);
2946 if (playlists.empty()) {
2950 framepos_t the_start;
2954 begin_reversible_command (_("trim to selection"));
2956 for (vector<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
2958 boost::shared_ptr<Region> region;
2962 if ((region = (*i)->top_region_at(the_start)) == 0) {
2966 /* now adjust lengths to that we do the right thing
2967 if the selection extends beyond the region
2970 the_start = max (the_start, (framepos_t) region->position());
2971 if (max_framepos - the_start < region->length()) {
2972 the_end = the_start + region->length() - 1;
2974 the_end = max_framepos;
2976 the_end = min (end, the_end);
2977 cnt = the_end - the_start + 1;
2979 region->clear_changes ();
2980 region->trim_to (the_start, cnt);
2981 _session->add_command (new StatefulDiffCommand (region));
2984 commit_reversible_command ();
2988 Editor::region_fill_track ()
2990 RegionSelection rs = get_regions_from_selection_and_entered ();
2992 if (!_session || rs.empty()) {
2996 framepos_t const end = _session->current_end_frame ();
2998 begin_reversible_command (Operations::region_fill);
3000 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3002 boost::shared_ptr<Region> region ((*i)->region());
3004 boost::shared_ptr<Playlist> pl = region->playlist();
3006 if (end <= region->last_frame()) {
3010 double times = (double) (end - region->last_frame()) / (double) region->length();
3016 pl->clear_changes ();
3017 pl->add_region (RegionFactory::create (region, true), region->last_frame(), times);
3018 _session->add_command (new StatefulDiffCommand (pl));
3021 commit_reversible_command ();
3025 Editor::region_fill_selection ()
3027 if (clicked_routeview == 0 || !clicked_routeview->is_audio_track()) {
3031 if (selection->time.empty()) {
3035 boost::shared_ptr<Region> region = _regions->get_single_selection ();
3040 framepos_t start = selection->time[clicked_selection].start;
3041 framepos_t end = selection->time[clicked_selection].end;
3043 boost::shared_ptr<Playlist> playlist;
3045 if (selection->tracks.empty()) {
3049 framepos_t selection_length = end - start;
3050 float times = (float)selection_length / region->length();
3052 begin_reversible_command (Operations::fill_selection);
3054 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
3056 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
3058 if ((playlist = (*i)->playlist()) == 0) {
3062 playlist->clear_changes ();
3063 playlist->add_region (RegionFactory::create (region, true), start, times);
3064 _session->add_command (new StatefulDiffCommand (playlist));
3067 commit_reversible_command ();
3071 Editor::set_region_sync_position ()
3073 set_sync_point (get_preferred_edit_position (), get_regions_from_selection_and_edit_point ());
3077 Editor::set_sync_point (framepos_t where, const RegionSelection& rs)
3079 bool in_command = false;
3081 for (RegionSelection::const_iterator r = rs.begin(); r != rs.end(); ++r) {
3083 if (!(*r)->region()->covers (where)) {
3087 boost::shared_ptr<Region> region ((*r)->region());
3090 begin_reversible_command (_("set sync point"));
3094 region->clear_changes ();
3095 region->set_sync_position (where);
3096 _session->add_command(new StatefulDiffCommand (region));
3100 commit_reversible_command ();
3104 /** Remove the sync positions of the selection */
3106 Editor::remove_region_sync ()
3108 RegionSelection rs = get_regions_from_selection_and_entered ();
3114 begin_reversible_command (_("remove region sync"));
3116 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3118 (*i)->region()->clear_changes ();
3119 (*i)->region()->clear_sync_position ();
3120 _session->add_command(new StatefulDiffCommand ((*i)->region()));
3123 commit_reversible_command ();
3127 Editor::naturalize_region ()
3129 RegionSelection rs = get_regions_from_selection_and_entered ();
3135 if (rs.size() > 1) {
3136 begin_reversible_command (_("move regions to original position"));
3138 begin_reversible_command (_("move region to original position"));
3141 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3142 (*i)->region()->clear_changes ();
3143 (*i)->region()->move_to_natural_position ();
3144 _session->add_command (new StatefulDiffCommand ((*i)->region()));
3147 commit_reversible_command ();
3151 Editor::align_regions (RegionPoint what)
3153 RegionSelection const rs = get_regions_from_selection_and_edit_point ();
3159 begin_reversible_command (_("align selection"));
3161 framepos_t const position = get_preferred_edit_position ();
3163 for (RegionSelection::const_iterator i = rs.begin(); i != rs.end(); ++i) {
3164 align_region_internal ((*i)->region(), what, position);
3167 commit_reversible_command ();
3170 struct RegionSortByTime {
3171 bool operator() (const RegionView* a, const RegionView* b) {
3172 return a->region()->position() < b->region()->position();
3177 Editor::align_regions_relative (RegionPoint point)
3179 RegionSelection const rs = get_regions_from_selection_and_edit_point ();
3185 framepos_t const position = get_preferred_edit_position ();
3187 framepos_t distance = 0;
3191 list<RegionView*> sorted;
3192 rs.by_position (sorted);
3194 boost::shared_ptr<Region> r ((*sorted.begin())->region());
3199 if (position > r->position()) {
3200 distance = position - r->position();
3202 distance = r->position() - position;
3208 if (position > r->last_frame()) {
3209 distance = position - r->last_frame();
3210 pos = r->position() + distance;
3212 distance = r->last_frame() - position;
3213 pos = r->position() - distance;
3219 pos = r->adjust_to_sync (position);
3220 if (pos > r->position()) {
3221 distance = pos - r->position();
3223 distance = r->position() - pos;
3229 if (pos == r->position()) {
3233 begin_reversible_command (_("align selection (relative)"));
3235 /* move first one specially */
3237 r->clear_changes ();
3238 r->set_position (pos);
3239 _session->add_command(new StatefulDiffCommand (r));
3241 /* move rest by the same amount */
3245 for (list<RegionView*>::iterator i = sorted.begin(); i != sorted.end(); ++i) {
3247 boost::shared_ptr<Region> region ((*i)->region());
3249 region->clear_changes ();
3252 region->set_position (region->position() + distance);
3254 region->set_position (region->position() - distance);
3257 _session->add_command(new StatefulDiffCommand (region));
3261 commit_reversible_command ();
3265 Editor::align_region (boost::shared_ptr<Region> region, RegionPoint point, framepos_t position)
3267 begin_reversible_command (_("align region"));
3268 align_region_internal (region, point, position);
3269 commit_reversible_command ();
3273 Editor::align_region_internal (boost::shared_ptr<Region> region, RegionPoint point, framepos_t position)
3275 region->clear_changes ();
3279 region->set_position (region->adjust_to_sync (position));
3283 if (position > region->length()) {
3284 region->set_position (position - region->length());
3289 region->set_position (position);
3293 _session->add_command(new StatefulDiffCommand (region));
3297 Editor::trim_region_front ()
3303 Editor::trim_region_back ()
3305 trim_region (false);
3309 Editor::trim_region (bool front)
3311 framepos_t where = get_preferred_edit_position();
3312 RegionSelection rs = get_regions_from_selection_and_edit_point ();
3318 begin_reversible_command (front ? _("trim front") : _("trim back"));
3320 for (list<RegionView*>::const_iterator i = rs.by_layer().begin(); i != rs.by_layer().end(); ++i) {
3321 if (!(*i)->region()->locked()) {
3323 (*i)->region()->clear_changes ();
3326 (*i)->region()->trim_front (where);
3327 maybe_locate_with_edit_preroll ( where );
3329 (*i)->region()->trim_end (where);
3330 maybe_locate_with_edit_preroll ( where );
3333 _session->add_command (new StatefulDiffCommand ((*i)->region()));
3337 commit_reversible_command ();
3340 /** Trim the end of the selected regions to the position of the edit cursor */
3342 Editor::trim_region_to_loop ()
3344 Location* loc = _session->locations()->auto_loop_location();
3348 trim_region_to_location (*loc, _("trim to loop"));
3352 Editor::trim_region_to_punch ()
3354 Location* loc = _session->locations()->auto_punch_location();
3358 trim_region_to_location (*loc, _("trim to punch"));
3362 Editor::trim_region_to_location (const Location& loc, const char* str)
3364 RegionSelection rs = get_regions_from_selection_and_entered ();
3366 begin_reversible_command (str);
3368 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
3369 RegionView* rv = (*x);
3371 /* require region to span proposed trim */
3372 switch (rv->region()->coverage (loc.start(), loc.end())) {
3373 case Evoral::OverlapInternal:
3379 RouteTimeAxisView* tav = dynamic_cast<RouteTimeAxisView*> (&rv->get_time_axis_view());
3388 if (tav->track() != 0) {
3389 speed = tav->track()->speed();
3392 start = session_frame_to_track_frame (loc.start(), speed);
3393 end = session_frame_to_track_frame (loc.end(), speed);
3395 rv->region()->clear_changes ();
3396 rv->region()->trim_to (start, (end - start));
3397 _session->add_command(new StatefulDiffCommand (rv->region()));
3400 commit_reversible_command ();
3404 Editor::trim_region_to_previous_region_end ()
3406 return trim_to_region(false);
3410 Editor::trim_region_to_next_region_start ()
3412 return trim_to_region(true);
3416 Editor::trim_to_region(bool forward)
3418 RegionSelection rs = get_regions_from_selection_and_entered ();
3420 begin_reversible_command (_("trim to region"));
3422 boost::shared_ptr<Region> next_region;
3424 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
3426 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*x);
3432 AudioTimeAxisView* atav = dynamic_cast<AudioTimeAxisView*> (&arv->get_time_axis_view());
3440 if (atav->track() != 0) {
3441 speed = atav->track()->speed();
3445 boost::shared_ptr<Region> region = arv->region();
3446 boost::shared_ptr<Playlist> playlist (region->playlist());
3448 region->clear_changes ();
3452 next_region = playlist->find_next_region (region->first_frame(), Start, 1);
3458 region->trim_end((framepos_t) ( (next_region->first_frame() - 1) * speed));
3459 arv->region_changed (PropertyChange (ARDOUR::Properties::length));
3463 next_region = playlist->find_next_region (region->first_frame(), Start, 0);
3469 region->trim_front((framepos_t) ((next_region->last_frame() + 1) * speed));
3471 arv->region_changed (ARDOUR::bounds_change);
3474 _session->add_command(new StatefulDiffCommand (region));
3477 commit_reversible_command ();
3481 Editor::unfreeze_route ()
3483 if (clicked_routeview == 0 || !clicked_routeview->is_track()) {
3487 clicked_routeview->track()->unfreeze ();
3491 Editor::_freeze_thread (void* arg)
3493 return static_cast<Editor*>(arg)->freeze_thread ();
3497 Editor::freeze_thread ()
3499 /* create event pool because we may need to talk to the session */
3500 SessionEvent::create_per_thread_pool ("freeze events", 64);
3501 /* create per-thread buffers for process() tree to use */
3502 current_interthread_info->process_thread.get_buffers ();
3503 clicked_routeview->audio_track()->freeze_me (*current_interthread_info);
3504 current_interthread_info->done = true;
3505 current_interthread_info->process_thread.drop_buffers();
3510 Editor::freeze_route ()
3516 /* stop transport before we start. this is important */
3518 _session->request_transport_speed (0.0);
3520 /* wait for just a little while, because the above call is asynchronous */
3522 Glib::usleep (250000);
3524 if (clicked_routeview == 0 || !clicked_routeview->is_audio_track()) {
3528 if (!clicked_routeview->track()->bounceable (clicked_routeview->track()->main_outs(), true)) {
3530 _("This track/bus cannot be frozen because the signal adds or loses channels before reaching the outputs.\n"
3531 "This is typically caused by plugins that generate stereo output from mono input or vice versa.")
3533 d.set_title (_("Cannot freeze"));
3538 if (clicked_routeview->track()->has_external_redirects()) {
3539 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"
3540 "Freezing will only process the signal as far as the first send/insert/return."),
3541 clicked_routeview->track()->name()), true, MESSAGE_INFO, BUTTONS_NONE, true);
3543 d.add_button (_("Freeze anyway"), Gtk::RESPONSE_OK);
3544 d.add_button (_("Don't freeze"), Gtk::RESPONSE_CANCEL);
3545 d.set_title (_("Freeze Limits"));
3547 int response = d.run ();
3550 case Gtk::RESPONSE_CANCEL:
3557 InterThreadInfo itt;
3558 current_interthread_info = &itt;
3560 InterthreadProgressWindow ipw (current_interthread_info, _("Freeze"), _("Cancel Freeze"));
3562 pthread_create_and_store (X_("freezer"), &itt.thread, _freeze_thread, this);
3564 set_canvas_cursor (_cursors->wait);
3566 while (!itt.done && !itt.cancel) {
3567 gtk_main_iteration ();
3570 current_interthread_info = 0;
3571 set_canvas_cursor (current_canvas_cursor);
3575 Editor::bounce_range_selection (bool replace, bool enable_processing)
3577 if (selection->time.empty()) {
3581 TrackSelection views = selection->tracks;
3583 for (TrackViewList::iterator i = views.begin(); i != views.end(); ++i) {
3585 if (enable_processing) {
3587 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*i);
3589 if (rtv && rtv->track() && replace && enable_processing && !rtv->track()->bounceable (rtv->track()->main_outs(), false)) {
3591 _("You can't perform this operation because the processing of the signal "
3592 "will cause one or more of the tracks to end up with a region with more channels than this track has inputs.\n\n"
3593 "You can do this without processing, which is a different operation.")
3595 d.set_title (_("Cannot bounce"));
3602 framepos_t start = selection->time[clicked_selection].start;
3603 framepos_t end = selection->time[clicked_selection].end;
3604 framepos_t cnt = end - start + 1;
3606 begin_reversible_command (_("bounce range"));
3608 for (TrackViewList::iterator i = views.begin(); i != views.end(); ++i) {
3610 RouteTimeAxisView* rtv;
3612 if ((rtv = dynamic_cast<RouteTimeAxisView*> (*i)) == 0) {
3616 boost::shared_ptr<Playlist> playlist;
3618 if ((playlist = rtv->playlist()) == 0) {
3622 InterThreadInfo itt;
3624 playlist->clear_changes ();
3625 playlist->clear_owned_changes ();
3627 boost::shared_ptr<Region> r;
3629 if (enable_processing) {
3630 r = rtv->track()->bounce_range (start, start+cnt, itt, rtv->track()->main_outs(), false);
3632 r = rtv->track()->bounce_range (start, start+cnt, itt, boost::shared_ptr<Processor>(), false);
3640 list<AudioRange> ranges;
3641 ranges.push_back (AudioRange (start, start+cnt, 0));
3642 playlist->cut (ranges); // discard result
3643 playlist->add_region (r, start);
3646 vector<Command*> cmds;
3647 playlist->rdiff (cmds);
3648 _session->add_commands (cmds);
3650 _session->add_command (new StatefulDiffCommand (playlist));
3653 commit_reversible_command ();
3656 /** Delete selected regions, automation points or a time range */
3663 /** Cut selected regions, automation points or a time range */
3670 /** Copy selected regions, automation points or a time range */
3678 /** @return true if a Cut, Copy or Clear is possible */
3680 Editor::can_cut_copy () const
3682 switch (effective_mouse_mode()) {
3685 if (!selection->regions.empty() || !selection->points.empty()) {
3691 if (!selection->time.empty()) {
3704 /** Cut, copy or clear selected regions, automation points or a time range.
3705 * @param op Operation (Delete, Cut, Copy or Clear)
3708 Editor::cut_copy (CutCopyOp op)
3710 /* only cancel selection if cut/copy is successful.*/
3716 opname = _("delete");
3725 opname = _("clear");
3729 /* if we're deleting something, and the mouse is still pressed,
3730 the thing we started a drag for will be gone when we release
3731 the mouse button(s). avoid this. see part 2 at the end of
3735 if (op == Delete || op == Cut || op == Clear) {
3736 if (_drags->active ()) {
3741 if ( op != Delete ) //"Delete" doesn't change copy/paste buf
3742 cut_buffer->clear ();
3744 if (entered_marker) {
3746 /* cut/delete op while pointing at a marker */
3749 Location* loc = find_location_from_marker (entered_marker, ignored);
3751 if (_session && loc) {
3752 Glib::signal_idle().connect (sigc::bind (sigc::mem_fun(*this, &Editor::really_remove_marker), loc));
3759 if (internal_editing()) {
3761 switch (effective_mouse_mode()) {
3764 begin_reversible_command (opname + ' ' + X_("MIDI"));
3766 commit_reversible_command ();
3775 bool did_edit = false;
3777 switch (effective_mouse_mode()) {
3779 if (!selection->points.empty()) {
3780 begin_reversible_command (opname + _(" points"));
3782 cut_copy_points (op);
3783 if (op == Cut || op == Delete) {
3784 selection->clear_points ();
3791 if (!selection->regions.empty() || !selection->points.empty()) {
3795 if (selection->regions.empty()) {
3796 thing_name = _("points");
3797 } else if (selection->points.empty()) {
3798 thing_name = _("regions");
3800 thing_name = _("objects");
3803 begin_reversible_command (opname + ' ' + thing_name);
3806 if (!selection->regions.empty()) {
3807 cut_copy_regions (op, selection->regions);
3809 if (op == Cut || op == Delete) {
3810 selection->clear_regions ();
3814 if (!selection->points.empty()) {
3815 cut_copy_points (op);
3817 if (op == Cut || op == Delete) {
3818 selection->clear_points ();
3825 if (selection->time.empty()) {
3826 framepos_t start, end;
3827 /* no time selection, see if we can get an edit range
3830 if (get_edit_op_range (start, end)) {
3831 selection->set (start, end);
3834 if (!selection->time.empty()) {
3835 begin_reversible_command (opname + _(" range"));
3838 cut_copy_ranges (op);
3840 if (op == Cut || op == Delete) {
3841 selection->clear_time ();
3851 commit_reversible_command ();
3854 if (op == Delete || op == Cut || op == Clear) {
3859 struct AutomationRecord {
3860 AutomationRecord () : state (0) {}
3861 AutomationRecord (XMLNode* s) : state (s) {}
3863 XMLNode* state; ///< state before any operation
3864 boost::shared_ptr<Evoral::ControlList> copy; ///< copied events for the cut buffer
3867 /** Cut, copy or clear selected automation points.
3868 * @param op Operation (Cut, Copy or Clear)
3871 Editor::cut_copy_points (CutCopyOp op)
3873 if (selection->points.empty ()) {
3877 /* XXX: not ideal, as there may be more than one track involved in the point selection */
3878 _last_cut_copy_source_track = &selection->points.front()->line().trackview;
3880 /* Keep a record of the AutomationLists that we end up using in this operation */
3881 typedef std::map<boost::shared_ptr<AutomationList>, AutomationRecord> Lists;
3884 /* Go through all selected points, making an AutomationRecord for each distinct AutomationList */
3885 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
3886 boost::shared_ptr<AutomationList> al = (*i)->line().the_list();
3887 if (lists.find (al) == lists.end ()) {
3888 /* We haven't seen this list yet, so make a record for it. This includes
3889 taking a copy of its current state, in case this is needed for undo later.
3891 lists[al] = AutomationRecord (&al->get_state ());
3895 if (op == Cut || op == Copy) {
3896 /* This operation will involve putting things in the cut buffer, so create an empty
3897 ControlList for each of our source lists to put the cut buffer data in.
3899 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
3900 i->second.copy = i->first->create (i->first->parameter ());
3903 /* Add all selected points to the relevant copy ControlLists */
3904 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
3905 boost::shared_ptr<AutomationList> al = (*i)->line().the_list();
3906 AutomationList::const_iterator j = (*i)->model ();
3907 lists[al].copy->add ((*j)->when, (*j)->value);
3910 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
3911 /* Correct this copy list so that it starts at time 0 */
3912 double const start = i->second.copy->front()->when;
3913 for (AutomationList::iterator j = i->second.copy->begin(); j != i->second.copy->end(); ++j) {
3914 (*j)->when -= start;
3917 /* And add it to the cut buffer */
3918 cut_buffer->add (i->second.copy);
3922 if (op == Delete || op == Cut) {
3923 /* This operation needs to remove things from the main AutomationList, so do that now */
3925 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
3926 i->first->freeze ();
3929 /* Remove each selected point from its AutomationList */
3930 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
3931 boost::shared_ptr<AutomationList> al = (*i)->line().the_list();
3932 al->erase ((*i)->model ());
3935 /* Thaw the lists and add undo records for them */
3936 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
3937 boost::shared_ptr<AutomationList> al = i->first;
3939 _session->add_command (new MementoCommand<AutomationList> (*al.get(), i->second.state, &(al->get_state ())));
3944 /** Cut, copy or clear selected automation points.
3945 * @param op Operation (Cut, Copy or Clear)
3948 Editor::cut_copy_midi (CutCopyOp op)
3950 for (MidiRegionSelection::iterator i = selection->midi_regions.begin(); i != selection->midi_regions.end(); ++i) {
3951 MidiRegionView* mrv = *i;
3952 mrv->cut_copy_clear (op);
3958 struct lt_playlist {
3959 bool operator () (const PlaylistState& a, const PlaylistState& b) {
3960 return a.playlist < b.playlist;
3964 struct PlaylistMapping {
3966 boost::shared_ptr<Playlist> pl;
3968 PlaylistMapping (TimeAxisView* tvp) : tv (tvp) {}
3971 /** Remove `clicked_regionview' */
3973 Editor::remove_clicked_region ()
3975 if (clicked_routeview == 0 || clicked_regionview == 0) {
3979 boost::shared_ptr<Playlist> playlist = clicked_routeview->playlist();
3981 playlist->clear_changes ();
3982 playlist->clear_owned_changes ();
3983 playlist->remove_region (clicked_regionview->region());
3984 if (Config->get_edit_mode() == Ripple)
3985 playlist->ripple (clicked_regionview->region()->position(), -clicked_regionview->region()->length(), boost::shared_ptr<Region>());
3987 /* We might have removed regions, which alters other regions' layering_index,
3988 so we need to do a recursive diff here.
3990 vector<Command*> cmds;
3991 playlist->rdiff (cmds);
3992 _session->add_commands (cmds);
3994 _session->add_command(new StatefulDiffCommand (playlist));
3995 commit_reversible_command ();
3999 /** Remove the selected regions */
4001 Editor::remove_selected_regions ()
4003 RegionSelection rs = get_regions_from_selection_and_entered ();
4005 if (!_session || rs.empty()) {
4009 begin_reversible_command (_("remove region"));
4011 list<boost::shared_ptr<Region> > regions_to_remove;
4013 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
4014 // we can't just remove the region(s) in this loop because
4015 // this removes them from the RegionSelection, and they thus
4016 // disappear from underneath the iterator, and the ++i above
4017 // SEGVs in a puzzling fashion.
4019 // so, first iterate over the regions to be removed from rs and
4020 // add them to the regions_to_remove list, and then
4021 // iterate over the list to actually remove them.
4023 regions_to_remove.push_back ((*i)->region());
4026 vector<boost::shared_ptr<Playlist> > playlists;
4028 for (list<boost::shared_ptr<Region> >::iterator rl = regions_to_remove.begin(); rl != regions_to_remove.end(); ++rl) {
4030 boost::shared_ptr<Playlist> playlist = (*rl)->playlist();
4033 // is this check necessary?
4037 /* get_regions_from_selection_and_entered() guarantees that
4038 the playlists involved are unique, so there is no need
4042 playlists.push_back (playlist);
4044 playlist->clear_changes ();
4045 playlist->clear_owned_changes ();
4046 playlist->freeze ();
4047 playlist->remove_region (*rl);
4048 if (Config->get_edit_mode() == Ripple)
4049 playlist->ripple ((*rl)->position(), -(*rl)->length(), boost::shared_ptr<Region>());
4053 vector<boost::shared_ptr<Playlist> >::iterator pl;
4055 for (pl = playlists.begin(); pl != playlists.end(); ++pl) {
4058 /* We might have removed regions, which alters other regions' layering_index,
4059 so we need to do a recursive diff here.
4061 vector<Command*> cmds;
4062 (*pl)->rdiff (cmds);
4063 _session->add_commands (cmds);
4065 _session->add_command(new StatefulDiffCommand (*pl));
4068 commit_reversible_command ();
4071 /** Cut, copy or clear selected regions.
4072 * @param op Operation (Cut, Copy or Clear)
4075 Editor::cut_copy_regions (CutCopyOp op, RegionSelection& rs)
4077 /* we can't use a std::map here because the ordering is important, and we can't trivially sort
4078 a map when we want ordered access to both elements. i think.
4081 vector<PlaylistMapping> pmap;
4083 framepos_t first_position = max_framepos;
4085 typedef set<boost::shared_ptr<Playlist> > FreezeList;
4086 FreezeList freezelist;
4088 /* get ordering correct before we cut/copy */
4090 rs.sort_by_position_and_track ();
4092 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
4094 first_position = min ((framepos_t) (*x)->region()->position(), first_position);
4096 if (op == Cut || op == Clear || op == Delete) {
4097 boost::shared_ptr<Playlist> pl = (*x)->region()->playlist();
4100 FreezeList::iterator fl;
4102 // only take state if this is a new playlist.
4103 for (fl = freezelist.begin(); fl != freezelist.end(); ++fl) {
4109 if (fl == freezelist.end()) {
4110 pl->clear_changes();
4111 pl->clear_owned_changes ();
4113 freezelist.insert (pl);
4118 TimeAxisView* tv = &(*x)->get_time_axis_view();
4119 vector<PlaylistMapping>::iterator z;
4121 for (z = pmap.begin(); z != pmap.end(); ++z) {
4122 if ((*z).tv == tv) {
4127 if (z == pmap.end()) {
4128 pmap.push_back (PlaylistMapping (tv));
4132 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ) {
4134 boost::shared_ptr<Playlist> pl = (*x)->region()->playlist();
4137 /* region not yet associated with a playlist (e.g. unfinished
4144 TimeAxisView& tv = (*x)->get_time_axis_view();
4145 boost::shared_ptr<Playlist> npl;
4146 RegionSelection::iterator tmp;
4153 vector<PlaylistMapping>::iterator z;
4155 for (z = pmap.begin(); z != pmap.end(); ++z) {
4156 if ((*z).tv == &tv) {
4161 assert (z != pmap.end());
4164 npl = PlaylistFactory::create (pl->data_type(), *_session, "cutlist", true);
4172 boost::shared_ptr<Region> r = (*x)->region();
4173 boost::shared_ptr<Region> _xx;
4179 pl->remove_region (r);
4180 if (Config->get_edit_mode() == Ripple)
4181 pl->ripple (r->position(), -r->length(), boost::shared_ptr<Region>());
4185 _xx = RegionFactory::create (r);
4186 npl->add_region (_xx, r->position() - first_position);
4187 pl->remove_region (r);
4188 if (Config->get_edit_mode() == Ripple)
4189 pl->ripple (r->position(), -r->length(), boost::shared_ptr<Region>());
4193 /* copy region before adding, so we're not putting same object into two different playlists */
4194 npl->add_region (RegionFactory::create (r), r->position() - first_position);
4198 pl->remove_region (r);
4199 if (Config->get_edit_mode() == Ripple)
4200 pl->ripple (r->position(), -r->length(), boost::shared_ptr<Region>());
4209 list<boost::shared_ptr<Playlist> > foo;
4211 /* the pmap is in the same order as the tracks in which selected regions occured */
4213 for (vector<PlaylistMapping>::iterator i = pmap.begin(); i != pmap.end(); ++i) {
4216 foo.push_back ((*i).pl);
4221 cut_buffer->set (foo);
4225 _last_cut_copy_source_track = 0;
4227 _last_cut_copy_source_track = pmap.front().tv;
4231 for (FreezeList::iterator pl = freezelist.begin(); pl != freezelist.end(); ++pl) {
4234 /* We might have removed regions, which alters other regions' layering_index,
4235 so we need to do a recursive diff here.
4237 vector<Command*> cmds;
4238 (*pl)->rdiff (cmds);
4239 _session->add_commands (cmds);
4241 _session->add_command (new StatefulDiffCommand (*pl));
4246 Editor::cut_copy_ranges (CutCopyOp op)
4248 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4250 /* Sort the track selection now, so that it if is used, the playlists
4251 selected by the calls below to cut_copy_clear are in the order that
4252 their tracks appear in the editor. This makes things like paste
4253 of ranges work properly.
4256 sort_track_selection (ts);
4259 if (!entered_track) {
4262 ts.push_back (entered_track);
4265 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4266 (*i)->cut_copy_clear (*selection, op);
4271 Editor::paste (float times, bool from_context)
4273 DEBUG_TRACE (DEBUG::CutNPaste, "paste to preferred edit pos\n");
4275 paste_internal (get_preferred_edit_position (false, from_context), times);
4279 Editor::mouse_paste ()
4284 if (!mouse_frame (where, ignored)) {
4289 paste_internal (where, 1);
4293 Editor::paste_internal (framepos_t position, float times)
4295 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("apparent paste position is %1\n", position));
4297 if (internal_editing()) {
4298 if (cut_buffer->midi_notes.empty()) {
4302 if (cut_buffer->empty()) {
4307 if (position == max_framepos) {
4308 position = get_preferred_edit_position();
4309 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("preferred edit position is %1\n", position));
4313 TrackViewList::iterator i;
4316 /* get everything in the correct order */
4318 if (_edit_point == Editing::EditAtMouse && entered_track) {
4319 /* With the mouse edit point, paste onto the track under the mouse */
4320 ts.push_back (entered_track);
4321 } else if (!selection->tracks.empty()) {
4322 /* Otherwise, if there are some selected tracks, paste to them */
4323 ts = selection->tracks.filter_to_unique_playlists ();
4324 sort_track_selection (ts);
4325 } else if (_last_cut_copy_source_track) {
4326 /* Otherwise paste to the track that the cut/copy came from;
4327 see discussion in mantis #3333.
4329 ts.push_back (_last_cut_copy_source_track);
4332 if (internal_editing ()) {
4334 /* undo/redo is handled by individual tracks/regions */
4336 for (nth = 0, i = ts.begin(); i != ts.end(); ++i, ++nth) {
4339 RegionSelection::iterator r;
4340 MidiNoteSelection::iterator cb;
4342 get_regions_at (rs, position, ts);
4344 for (cb = cut_buffer->midi_notes.begin(), r = rs.begin();
4345 cb != cut_buffer->midi_notes.end() && r != rs.end(); ++r) {
4346 MidiRegionView* mrv = dynamic_cast<MidiRegionView*> (*r);
4348 mrv->paste (position, times, **cb);
4356 /* we do redo (do you do voodoo?) */
4358 begin_reversible_command (Operations::paste);
4360 for (nth = 0, i = ts.begin(); i != ts.end(); ++i, ++nth) {
4361 (*i)->paste (position, times, *cut_buffer, nth);
4364 commit_reversible_command ();
4369 Editor::duplicate_some_regions (RegionSelection& regions, float times)
4371 boost::shared_ptr<Playlist> playlist;
4372 RegionSelection sel = regions; // clear (below) may clear the argument list if its the current region selection
4373 RegionSelection foo;
4375 framepos_t const start_frame = regions.start ();
4376 framepos_t const end_frame = regions.end_frame ();
4378 begin_reversible_command (Operations::duplicate_region);
4380 selection->clear_regions ();
4382 for (RegionSelection::iterator i = sel.begin(); i != sel.end(); ++i) {
4384 boost::shared_ptr<Region> r ((*i)->region());
4386 TimeAxisView& tv = (*i)->get_time_axis_view();
4387 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (&tv);
4388 latest_regionviews.clear ();
4389 sigc::connection c = rtv->view()->RegionViewAdded.connect (sigc::mem_fun(*this, &Editor::collect_new_region_view));
4391 playlist = (*i)->region()->playlist();
4392 playlist->clear_changes ();
4393 playlist->duplicate (r, end_frame + (r->first_frame() - start_frame), times);
4394 _session->add_command(new StatefulDiffCommand (playlist));
4398 foo.insert (foo.end(), latest_regionviews.begin(), latest_regionviews.end());
4401 commit_reversible_command ();
4404 selection->set (foo);
4409 Editor::duplicate_selection (float times)
4411 if (selection->time.empty() || selection->tracks.empty()) {
4415 boost::shared_ptr<Playlist> playlist;
4416 vector<boost::shared_ptr<Region> > new_regions;
4417 vector<boost::shared_ptr<Region> >::iterator ri;
4419 create_region_from_selection (new_regions);
4421 if (new_regions.empty()) {
4425 begin_reversible_command (_("duplicate selection"));
4427 ri = new_regions.begin();
4429 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4431 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4432 if ((playlist = (*i)->playlist()) == 0) {
4435 playlist->clear_changes ();
4436 playlist->duplicate (*ri, selection->time[clicked_selection].end, times);
4437 _session->add_command (new StatefulDiffCommand (playlist));
4440 if (ri == new_regions.end()) {
4445 commit_reversible_command ();
4448 /** Reset all selected points to the relevant default value */
4450 Editor::reset_point_selection ()
4452 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
4453 ARDOUR::AutomationList::iterator j = (*i)->model ();
4454 (*j)->value = (*i)->line().the_list()->default_value ();
4459 Editor::center_playhead ()
4461 float const page = _visible_canvas_width * samples_per_pixel;
4462 center_screen_internal (playhead_cursor->current_frame (), page);
4466 Editor::center_edit_point ()
4468 float const page = _visible_canvas_width * samples_per_pixel;
4469 center_screen_internal (get_preferred_edit_position(), page);
4472 /** Caller must begin and commit a reversible command */
4474 Editor::clear_playlist (boost::shared_ptr<Playlist> playlist)
4476 playlist->clear_changes ();
4478 _session->add_command (new StatefulDiffCommand (playlist));
4482 Editor::nudge_track (bool use_edit, bool forwards)
4484 boost::shared_ptr<Playlist> playlist;
4485 framepos_t distance;
4486 framepos_t next_distance;
4490 start = get_preferred_edit_position();
4495 if ((distance = get_nudge_distance (start, next_distance)) == 0) {
4499 if (selection->tracks.empty()) {
4503 begin_reversible_command (_("nudge track"));
4505 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4507 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4509 if ((playlist = (*i)->playlist()) == 0) {
4513 playlist->clear_changes ();
4514 playlist->clear_owned_changes ();
4516 playlist->nudge_after (start, distance, forwards);
4518 vector<Command*> cmds;
4520 playlist->rdiff (cmds);
4521 _session->add_commands (cmds);
4523 _session->add_command (new StatefulDiffCommand (playlist));
4526 commit_reversible_command ();
4530 Editor::remove_last_capture ()
4532 vector<string> choices;
4539 if (Config->get_verify_remove_last_capture()) {
4540 prompt = _("Do you really want to destroy the last capture?"
4541 "\n(This is destructive and cannot be undone)");
4543 choices.push_back (_("No, do nothing."));
4544 choices.push_back (_("Yes, destroy it."));
4546 Gtkmm2ext::Choice prompter (_("Destroy last capture"), prompt, choices);
4548 if (prompter.run () == 1) {
4549 _session->remove_last_capture ();
4550 _regions->redisplay ();
4554 _session->remove_last_capture();
4555 _regions->redisplay ();
4560 Editor::normalize_region ()
4566 RegionSelection rs = get_regions_from_selection_and_entered ();
4572 NormalizeDialog dialog (rs.size() > 1);
4574 if (dialog.run () == RESPONSE_CANCEL) {
4578 set_canvas_cursor (_cursors->wait);
4581 /* XXX: should really only count audio regions here */
4582 int const regions = rs.size ();
4584 /* Make a list of the selected audio regions' maximum amplitudes, and also
4585 obtain the maximum amplitude of them all.
4587 list<double> max_amps;
4589 for (RegionSelection::const_iterator i = rs.begin(); i != rs.end(); ++i) {
4590 AudioRegionView const * arv = dynamic_cast<AudioRegionView const *> (*i);
4592 dialog.descend (1.0 / regions);
4593 double const a = arv->audio_region()->maximum_amplitude (&dialog);
4596 /* the user cancelled the operation */
4597 set_canvas_cursor (current_canvas_cursor);
4601 max_amps.push_back (a);
4602 max_amp = max (max_amp, a);
4607 begin_reversible_command (_("normalize"));
4609 list<double>::const_iterator a = max_amps.begin ();
4611 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
4612 AudioRegionView* const arv = dynamic_cast<AudioRegionView*> (*r);
4617 arv->region()->clear_changes ();
4619 double const amp = dialog.normalize_individually() ? *a : max_amp;
4621 arv->audio_region()->normalize (amp, dialog.target ());
4622 _session->add_command (new StatefulDiffCommand (arv->region()));
4627 commit_reversible_command ();
4628 set_canvas_cursor (current_canvas_cursor);
4633 Editor::reset_region_scale_amplitude ()
4639 RegionSelection rs = get_regions_from_selection_and_entered ();
4645 begin_reversible_command ("reset gain");
4647 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
4648 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
4651 arv->region()->clear_changes ();
4652 arv->audio_region()->set_scale_amplitude (1.0f);
4653 _session->add_command (new StatefulDiffCommand (arv->region()));
4656 commit_reversible_command ();
4660 Editor::adjust_region_gain (bool up)
4662 RegionSelection rs = get_regions_from_selection_and_entered ();
4664 if (!_session || rs.empty()) {
4668 begin_reversible_command ("adjust region gain");
4670 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
4671 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
4676 arv->region()->clear_changes ();
4678 double dB = accurate_coefficient_to_dB (arv->audio_region()->scale_amplitude ());
4686 arv->audio_region()->set_scale_amplitude (dB_to_coefficient (dB));
4687 _session->add_command (new StatefulDiffCommand (arv->region()));
4690 commit_reversible_command ();
4695 Editor::reverse_region ()
4701 Reverse rev (*_session);
4702 apply_filter (rev, _("reverse regions"));
4706 Editor::strip_region_silence ()
4712 RegionSelection rs = get_regions_from_selection_and_entered ();
4718 std::list<RegionView*> audio_only;
4720 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
4721 AudioRegionView* const arv = dynamic_cast<AudioRegionView*> (*i);
4723 audio_only.push_back (arv);
4727 StripSilenceDialog d (_session, audio_only);
4728 int const r = d.run ();
4732 if (r == Gtk::RESPONSE_OK) {
4733 ARDOUR::AudioIntervalMap silences;
4734 d.silences (silences);
4735 StripSilence s (*_session, silences, d.fade_length());
4736 apply_filter (s, _("strip silence"), &d);
4741 Editor::apply_midi_note_edit_op_to_region (MidiOperator& op, MidiRegionView& mrv)
4743 Evoral::Sequence<Evoral::MusicalTime>::Notes selected;
4744 mrv.selection_as_notelist (selected, true);
4746 vector<Evoral::Sequence<Evoral::MusicalTime>::Notes> v;
4747 v.push_back (selected);
4749 framepos_t pos_frames = mrv.midi_region()->position() - mrv.midi_region()->start();
4750 double pos_beats = _session->tempo_map().framewalk_to_beats(0, pos_frames);
4752 return op (mrv.midi_region()->model(), pos_beats, v);
4756 Editor::apply_midi_note_edit_op (MidiOperator& op)
4760 RegionSelection rs = get_regions_from_selection_and_entered ();
4766 begin_reversible_command (op.name ());
4768 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
4769 RegionSelection::iterator tmp = r;
4772 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*r);
4775 cmd = apply_midi_note_edit_op_to_region (op, *mrv);
4778 _session->add_command (cmd);
4785 commit_reversible_command ();
4789 Editor::fork_region ()
4791 RegionSelection rs = get_regions_from_selection_and_entered ();
4797 begin_reversible_command (_("Fork Region(s)"));
4799 set_canvas_cursor (_cursors->wait);
4802 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
4803 RegionSelection::iterator tmp = r;
4806 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*>(*r);
4810 boost::shared_ptr<Playlist> playlist = mrv->region()->playlist();
4811 boost::shared_ptr<MidiSource> new_source = _session->create_midi_source_by_stealing_name (mrv->midi_view()->track());
4812 boost::shared_ptr<MidiRegion> newregion = mrv->midi_region()->clone (new_source);
4814 playlist->clear_changes ();
4815 playlist->replace_region (mrv->region(), newregion, mrv->region()->position());
4816 _session->add_command(new StatefulDiffCommand (playlist));
4818 error << string_compose (_("Could not unlink %1"), mrv->region()->name()) << endmsg;
4825 commit_reversible_command ();
4827 set_canvas_cursor (current_canvas_cursor);
4831 Editor::quantize_region ()
4833 int selected_midi_region_cnt = 0;
4839 RegionSelection rs = get_regions_from_selection_and_entered ();
4845 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
4846 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*r);
4848 selected_midi_region_cnt++;
4852 if (selected_midi_region_cnt == 0) {
4856 QuantizeDialog* qd = new QuantizeDialog (*this);
4859 const int r = qd->run ();
4862 if (r == Gtk::RESPONSE_OK) {
4863 Quantize quant (*_session, qd->snap_start(), qd->snap_end(),
4864 qd->start_grid_size(), qd->end_grid_size(),
4865 qd->strength(), qd->swing(), qd->threshold());
4867 apply_midi_note_edit_op (quant);
4872 Editor::insert_patch_change (bool from_context)
4874 RegionSelection rs = get_regions_from_selection_and_entered ();
4880 const framepos_t p = get_preferred_edit_position (false, from_context);
4882 /* XXX: bit of a hack; use the MIDNAM from the first selected region;
4883 there may be more than one, but the PatchChangeDialog can only offer
4884 one set of patch menus.
4886 MidiRegionView* first = dynamic_cast<MidiRegionView*> (rs.front ());
4888 Evoral::PatchChange<Evoral::MusicalTime> empty (0, 0, 0, 0);
4889 PatchChangeDialog d (0, _session, empty, first->instrument_info(), Gtk::Stock::ADD);
4891 if (d.run() == RESPONSE_CANCEL) {
4895 for (RegionSelection::iterator i = rs.begin (); i != rs.end(); ++i) {
4896 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*i);
4898 if (p >= mrv->region()->first_frame() && p <= mrv->region()->last_frame()) {
4899 mrv->add_patch_change (p - mrv->region()->position(), d.patch ());
4906 Editor::apply_filter (Filter& filter, string command, ProgressReporter* progress)
4908 RegionSelection rs = get_regions_from_selection_and_entered ();
4914 begin_reversible_command (command);
4916 set_canvas_cursor (_cursors->wait);
4920 int const N = rs.size ();
4922 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
4923 RegionSelection::iterator tmp = r;
4926 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
4928 boost::shared_ptr<Playlist> playlist = arv->region()->playlist();
4931 progress->descend (1.0 / N);
4934 if (arv->audio_region()->apply (filter, progress) == 0) {
4936 playlist->clear_changes ();
4937 playlist->clear_owned_changes ();
4939 if (filter.results.empty ()) {
4941 /* no regions returned; remove the old one */
4942 playlist->remove_region (arv->region ());
4946 std::vector<boost::shared_ptr<Region> >::iterator res = filter.results.begin ();
4948 /* first region replaces the old one */
4949 playlist->replace_region (arv->region(), *res, (*res)->position());
4953 while (res != filter.results.end()) {
4954 playlist->add_region (*res, (*res)->position());
4960 /* We might have removed regions, which alters other regions' layering_index,
4961 so we need to do a recursive diff here.
4963 vector<Command*> cmds;
4964 playlist->rdiff (cmds);
4965 _session->add_commands (cmds);
4967 _session->add_command(new StatefulDiffCommand (playlist));
4973 progress->ascend ();
4981 commit_reversible_command ();
4984 set_canvas_cursor (current_canvas_cursor);
4988 Editor::external_edit_region ()
4994 Editor::reset_region_gain_envelopes ()
4996 RegionSelection rs = get_regions_from_selection_and_entered ();
4998 if (!_session || rs.empty()) {
5002 _session->begin_reversible_command (_("reset region gain"));
5004 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5005 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
5007 boost::shared_ptr<AutomationList> alist (arv->audio_region()->envelope());
5008 XMLNode& before (alist->get_state());
5010 arv->audio_region()->set_default_envelope ();
5011 _session->add_command (new MementoCommand<AutomationList>(*arv->audio_region()->envelope().get(), &before, &alist->get_state()));
5015 _session->commit_reversible_command ();
5019 Editor::set_region_gain_visibility (RegionView* rv)
5021 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (rv);
5023 arv->update_envelope_visibility();
5028 Editor::set_gain_envelope_visibility ()
5034 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5035 AudioTimeAxisView* v = dynamic_cast<AudioTimeAxisView*>(*i);
5037 v->audio_view()->foreach_regionview (sigc::mem_fun (this, &Editor::set_region_gain_visibility));
5043 Editor::toggle_gain_envelope_active ()
5045 if (_ignore_region_action) {
5049 RegionSelection rs = get_regions_from_selection_and_entered ();
5051 if (!_session || rs.empty()) {
5055 _session->begin_reversible_command (_("region gain envelope active"));
5057 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5058 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
5060 arv->region()->clear_changes ();
5061 arv->audio_region()->set_envelope_active (!arv->audio_region()->envelope_active());
5062 _session->add_command (new StatefulDiffCommand (arv->region()));
5066 _session->commit_reversible_command ();
5070 Editor::toggle_region_lock ()
5072 if (_ignore_region_action) {
5076 RegionSelection rs = get_regions_from_selection_and_entered ();
5078 if (!_session || rs.empty()) {
5082 _session->begin_reversible_command (_("toggle region lock"));
5084 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5085 (*i)->region()->clear_changes ();
5086 (*i)->region()->set_locked (!(*i)->region()->locked());
5087 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5090 _session->commit_reversible_command ();
5094 Editor::toggle_region_video_lock ()
5096 if (_ignore_region_action) {
5100 RegionSelection rs = get_regions_from_selection_and_entered ();
5102 if (!_session || rs.empty()) {
5106 _session->begin_reversible_command (_("Toggle Video Lock"));
5108 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5109 (*i)->region()->clear_changes ();
5110 (*i)->region()->set_video_locked (!(*i)->region()->video_locked());
5111 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5114 _session->commit_reversible_command ();
5118 Editor::toggle_region_lock_style ()
5120 if (_ignore_region_action) {
5124 RegionSelection rs = get_regions_from_selection_and_entered ();
5126 if (!_session || rs.empty()) {
5130 _session->begin_reversible_command (_("region lock style"));
5132 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5133 (*i)->region()->clear_changes ();
5134 PositionLockStyle const ns = (*i)->region()->position_lock_style() == AudioTime ? MusicTime : AudioTime;
5135 (*i)->region()->set_position_lock_style (ns);
5136 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5139 _session->commit_reversible_command ();
5143 Editor::toggle_opaque_region ()
5145 if (_ignore_region_action) {
5149 RegionSelection rs = get_regions_from_selection_and_entered ();
5151 if (!_session || rs.empty()) {
5155 _session->begin_reversible_command (_("change region opacity"));
5157 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5158 (*i)->region()->clear_changes ();
5159 (*i)->region()->set_opaque (!(*i)->region()->opaque());
5160 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5163 _session->commit_reversible_command ();
5167 Editor::toggle_record_enable ()
5169 bool new_state = false;
5171 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5172 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5175 if (!rtav->is_track())
5179 new_state = !rtav->track()->record_enabled();
5183 rtav->track()->set_record_enabled (new_state, this);
5188 Editor::toggle_solo ()
5190 bool new_state = false;
5192 boost::shared_ptr<RouteList> rl (new RouteList);
5194 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5195 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5202 new_state = !rtav->route()->soloed ();
5206 rl->push_back (rtav->route());
5209 _session->set_solo (rl, new_state, Session::rt_cleanup, true);
5213 Editor::toggle_mute ()
5215 bool new_state = false;
5217 boost::shared_ptr<RouteList> rl (new RouteList);
5219 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5220 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5227 new_state = !rtav->route()->muted();
5231 rl->push_back (rtav->route());
5234 _session->set_mute (rl, new_state, Session::rt_cleanup, true);
5238 Editor::toggle_solo_isolate ()
5243 Editor::set_fade_length (bool in)
5245 RegionSelection rs = get_regions_from_selection_and_entered ();
5251 /* we need a region to measure the offset from the start */
5253 RegionView* rv = rs.front ();
5255 framepos_t pos = get_preferred_edit_position();
5259 if (pos > rv->region()->last_frame() || pos < rv->region()->first_frame()) {
5260 /* edit point is outside the relevant region */
5265 if (pos <= rv->region()->position()) {
5269 len = pos - rv->region()->position();
5270 cmd = _("set fade in length");
5272 if (pos >= rv->region()->last_frame()) {
5276 len = rv->region()->last_frame() - pos;
5277 cmd = _("set fade out length");
5280 begin_reversible_command (cmd);
5282 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5283 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5289 boost::shared_ptr<AutomationList> alist;
5291 alist = tmp->audio_region()->fade_in();
5293 alist = tmp->audio_region()->fade_out();
5296 XMLNode &before = alist->get_state();
5299 tmp->audio_region()->set_fade_in_length (len);
5300 tmp->audio_region()->set_fade_in_active (true);
5302 tmp->audio_region()->set_fade_out_length (len);
5303 tmp->audio_region()->set_fade_out_active (true);
5306 XMLNode &after = alist->get_state();
5307 _session->add_command(new MementoCommand<AutomationList>(*alist, &before, &after));
5310 commit_reversible_command ();
5314 Editor::set_fade_in_shape (FadeShape shape)
5316 RegionSelection rs = get_regions_from_selection_and_entered ();
5322 begin_reversible_command (_("set fade in shape"));
5324 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5325 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5331 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_in();
5332 XMLNode &before = alist->get_state();
5334 tmp->audio_region()->set_fade_in_shape (shape);
5336 XMLNode &after = alist->get_state();
5337 _session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
5340 commit_reversible_command ();
5345 Editor::set_fade_out_shape (FadeShape shape)
5347 RegionSelection rs = get_regions_from_selection_and_entered ();
5353 begin_reversible_command (_("set fade out shape"));
5355 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5356 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5362 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_out();
5363 XMLNode &before = alist->get_state();
5365 tmp->audio_region()->set_fade_out_shape (shape);
5367 XMLNode &after = alist->get_state();
5368 _session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
5371 commit_reversible_command ();
5375 Editor::set_fade_in_active (bool yn)
5377 RegionSelection rs = get_regions_from_selection_and_entered ();
5383 begin_reversible_command (_("set fade in active"));
5385 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5386 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5393 boost::shared_ptr<AudioRegion> ar (tmp->audio_region());
5395 ar->clear_changes ();
5396 ar->set_fade_in_active (yn);
5397 _session->add_command (new StatefulDiffCommand (ar));
5400 commit_reversible_command ();
5404 Editor::set_fade_out_active (bool yn)
5406 RegionSelection rs = get_regions_from_selection_and_entered ();
5412 begin_reversible_command (_("set fade out active"));
5414 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5415 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5421 boost::shared_ptr<AudioRegion> ar (tmp->audio_region());
5423 ar->clear_changes ();
5424 ar->set_fade_out_active (yn);
5425 _session->add_command(new StatefulDiffCommand (ar));
5428 commit_reversible_command ();
5432 Editor::toggle_region_fades (int dir)
5434 if (_ignore_region_action) {
5438 boost::shared_ptr<AudioRegion> ar;
5441 RegionSelection rs = get_regions_from_selection_and_entered ();
5447 RegionSelection::iterator i;
5448 for (i = rs.begin(); i != rs.end(); ++i) {
5449 if ((ar = boost::dynamic_pointer_cast<AudioRegion>((*i)->region())) != 0) {
5451 yn = ar->fade_out_active ();
5453 yn = ar->fade_in_active ();
5459 if (i == rs.end()) {
5463 /* XXX should this undo-able? */
5465 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5466 if ((ar = boost::dynamic_pointer_cast<AudioRegion>((*i)->region())) == 0) {
5469 if (dir == 1 || dir == 0) {
5470 ar->set_fade_in_active (!yn);
5473 if (dir == -1 || dir == 0) {
5474 ar->set_fade_out_active (!yn);
5480 /** Update region fade visibility after its configuration has been changed */
5482 Editor::update_region_fade_visibility ()
5484 bool _fade_visibility = _session->config.get_show_region_fades ();
5486 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5487 AudioTimeAxisView* v = dynamic_cast<AudioTimeAxisView*>(*i);
5489 if (_fade_visibility) {
5490 v->audio_view()->show_all_fades ();
5492 v->audio_view()->hide_all_fades ();
5499 Editor::set_edit_point ()
5504 if (!mouse_frame (where, ignored)) {
5510 if (selection->markers.empty()) {
5512 mouse_add_new_marker (where);
5517 Location* loc = find_location_from_marker (selection->markers.front(), ignored);
5520 loc->move_to (where);
5526 Editor::set_playhead_cursor ()
5528 if (entered_marker) {
5529 _session->request_locate (entered_marker->position(), _session->transport_rolling());
5534 if (!mouse_frame (where, ignored)) {
5541 _session->request_locate (where, _session->transport_rolling());
5545 if ( Config->get_always_play_range() )
5546 cancel_time_selection();
5550 Editor::split_region ()
5552 if ( !selection->time.empty()) {
5553 separate_regions_between (selection->time);
5557 RegionSelection rs = get_regions_from_selection_and_edit_point ();
5559 framepos_t where = get_preferred_edit_position ();
5565 split_regions_at (where, rs);
5568 struct EditorOrderRouteSorter {
5569 bool operator() (boost::shared_ptr<Route> a, boost::shared_ptr<Route> b) {
5570 return a->order_key () < b->order_key ();
5575 Editor::select_next_route()
5577 if (selection->tracks.empty()) {
5578 selection->set (track_views.front());
5582 TimeAxisView* current = selection->tracks.front();
5586 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5587 if (*i == current) {
5589 if (i != track_views.end()) {
5592 current = (*(track_views.begin()));
5593 //selection->set (*(track_views.begin()));
5598 rui = dynamic_cast<RouteUI *>(current);
5599 } while ( current->hidden() || (rui != NULL && !rui->route()->active()));
5601 selection->set(current);
5603 ensure_track_visible(current);
5607 Editor::select_prev_route()
5609 if (selection->tracks.empty()) {
5610 selection->set (track_views.front());
5614 TimeAxisView* current = selection->tracks.front();
5618 for (TrackViewList::reverse_iterator i = track_views.rbegin(); i != track_views.rend(); ++i) {
5619 if (*i == current) {
5621 if (i != track_views.rend()) {
5624 current = *(track_views.rbegin());
5629 rui = dynamic_cast<RouteUI *>(current);
5630 } while ( current->hidden() || (rui != NULL && !rui->route()->active()));
5632 selection->set (current);
5634 ensure_track_visible(current);
5638 Editor::ensure_track_visible(TimeAxisView *track)
5640 if (track->hidden())
5643 double const current_view_min_y = vertical_adjustment.get_value();
5644 double const current_view_max_y = vertical_adjustment.get_value() + vertical_adjustment.get_page_size();
5646 double const track_min_y = track->y_position ();
5647 double const track_max_y = track->y_position () + track->effective_height ();
5649 if (track_min_y >= current_view_min_y &&
5650 track_max_y <= current_view_max_y) {
5656 if (track_min_y < current_view_min_y) {
5657 // Track is above the current view
5658 new_value = track_min_y;
5660 // Track is below the current view
5661 new_value = track->y_position () + track->effective_height() - vertical_adjustment.get_page_size();
5664 vertical_adjustment.set_value(new_value);
5668 Editor::set_loop_from_selection (bool play)
5670 if (_session == 0 || selection->time.empty()) {
5674 framepos_t start = selection->time[clicked_selection].start;
5675 framepos_t end = selection->time[clicked_selection].end;
5677 set_loop_range (start, end, _("set loop range from selection"));
5680 _session->request_play_loop (true);
5681 _session->request_locate (start, true);
5686 Editor::set_loop_from_edit_range (bool play)
5688 if (_session == 0) {
5695 if (!get_edit_op_range (start, end)) {
5699 set_loop_range (start, end, _("set loop range from edit range"));
5702 _session->request_play_loop (true);
5703 _session->request_locate (start, true);
5708 Editor::set_loop_from_region (bool play)
5710 framepos_t start = max_framepos;
5713 RegionSelection rs = get_regions_from_selection_and_entered ();
5719 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5720 if ((*i)->region()->position() < start) {
5721 start = (*i)->region()->position();
5723 if ((*i)->region()->last_frame() + 1 > end) {
5724 end = (*i)->region()->last_frame() + 1;
5728 set_loop_range (start, end, _("set loop range from region"));
5731 _session->request_play_loop (true);
5732 _session->request_locate (start, true);
5737 Editor::set_punch_from_selection ()
5739 if (_session == 0 || selection->time.empty()) {
5743 framepos_t start = selection->time[clicked_selection].start;
5744 framepos_t end = selection->time[clicked_selection].end;
5746 set_punch_range (start, end, _("set punch range from selection"));
5750 Editor::set_punch_from_edit_range ()
5752 if (_session == 0) {
5759 if (!get_edit_op_range (start, end)) {
5763 set_punch_range (start, end, _("set punch range from edit range"));
5767 Editor::set_punch_from_region ()
5769 framepos_t start = max_framepos;
5772 RegionSelection rs = get_regions_from_selection_and_entered ();
5778 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5779 if ((*i)->region()->position() < start) {
5780 start = (*i)->region()->position();
5782 if ((*i)->region()->last_frame() + 1 > end) {
5783 end = (*i)->region()->last_frame() + 1;
5787 set_punch_range (start, end, _("set punch range from region"));
5791 Editor::pitch_shift_region ()
5793 RegionSelection rs = get_regions_from_selection_and_entered ();
5795 RegionSelection audio_rs;
5796 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5797 if (dynamic_cast<AudioRegionView*> (*i)) {
5798 audio_rs.push_back (*i);
5802 if (audio_rs.empty()) {
5806 pitch_shift (audio_rs, 1.2);
5810 Editor::transpose_region ()
5812 RegionSelection rs = get_regions_from_selection_and_entered ();
5814 list<MidiRegionView*> midi_region_views;
5815 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5816 MidiRegionView* mrv = dynamic_cast<MidiRegionView*> (*i);
5818 midi_region_views.push_back (mrv);
5823 int const r = d.run ();
5824 if (r != RESPONSE_ACCEPT) {
5828 for (list<MidiRegionView*>::iterator i = midi_region_views.begin(); i != midi_region_views.end(); ++i) {
5829 (*i)->midi_region()->transpose (d.semitones ());
5834 Editor::set_tempo_from_region ()
5836 RegionSelection rs = get_regions_from_selection_and_entered ();
5838 if (!_session || rs.empty()) {
5842 RegionView* rv = rs.front();
5844 define_one_bar (rv->region()->position(), rv->region()->last_frame() + 1);
5848 Editor::use_range_as_bar ()
5850 framepos_t start, end;
5851 if (get_edit_op_range (start, end)) {
5852 define_one_bar (start, end);
5857 Editor::define_one_bar (framepos_t start, framepos_t end)
5859 framepos_t length = end - start;
5861 const Meter& m (_session->tempo_map().meter_at (start));
5863 /* length = 1 bar */
5865 /* now we want frames per beat.
5866 we have frames per bar, and beats per bar, so ...
5869 /* XXXX METER MATH */
5871 double frames_per_beat = length / m.divisions_per_bar();
5873 /* beats per minute = */
5875 double beats_per_minute = (_session->frame_rate() * 60.0) / frames_per_beat;
5877 /* now decide whether to:
5879 (a) set global tempo
5880 (b) add a new tempo marker
5884 const TempoSection& t (_session->tempo_map().tempo_section_at (start));
5886 bool do_global = false;
5888 if ((_session->tempo_map().n_tempos() == 1) && (_session->tempo_map().n_meters() == 1)) {
5890 /* only 1 tempo & 1 meter: ask if the user wants to set the tempo
5891 at the start, or create a new marker
5894 vector<string> options;
5895 options.push_back (_("Cancel"));
5896 options.push_back (_("Add new marker"));
5897 options.push_back (_("Set global tempo"));
5900 _("Define one bar"),
5901 _("Do you want to set the global tempo or add a new tempo marker?"),
5905 c.set_default_response (2);
5921 /* more than 1 tempo and/or meter section already, go ahead do the "usual":
5922 if the marker is at the region starter, change it, otherwise add
5927 begin_reversible_command (_("set tempo from region"));
5928 XMLNode& before (_session->tempo_map().get_state());
5931 _session->tempo_map().change_initial_tempo (beats_per_minute, t.note_type());
5932 } else if (t.frame() == start) {
5933 _session->tempo_map().change_existing_tempo_at (start, beats_per_minute, t.note_type());
5935 Timecode::BBT_Time bbt;
5936 _session->tempo_map().bbt_time (start, bbt);
5937 _session->tempo_map().add_tempo (Tempo (beats_per_minute, t.note_type()), bbt);
5940 XMLNode& after (_session->tempo_map().get_state());
5942 _session->add_command (new MementoCommand<TempoMap>(_session->tempo_map(), &before, &after));
5943 commit_reversible_command ();
5947 Editor::split_region_at_transients ()
5949 AnalysisFeatureList positions;
5951 RegionSelection rs = get_regions_from_selection_and_entered ();
5953 if (!_session || rs.empty()) {
5957 _session->begin_reversible_command (_("split regions"));
5959 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ) {
5961 RegionSelection::iterator tmp;
5966 boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion> ((*i)->region());
5968 if (ar && (ar->get_transients (positions) == 0)) {
5969 split_region_at_points ((*i)->region(), positions, true);
5976 _session->commit_reversible_command ();
5981 Editor::split_region_at_points (boost::shared_ptr<Region> r, AnalysisFeatureList& positions, bool can_ferret, bool select_new)
5983 bool use_rhythmic_rodent = false;
5985 boost::shared_ptr<Playlist> pl = r->playlist();
5987 list<boost::shared_ptr<Region> > new_regions;
5993 if (positions.empty()) {
5998 if (positions.size() > 20 && can_ferret) {
5999 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);
6000 MessageDialog msg (msgstr,
6003 Gtk::BUTTONS_OK_CANCEL);
6006 msg.add_button (_("Call for the Ferret!"), RESPONSE_APPLY);
6007 msg.set_secondary_text (_("Press OK to continue with this split operation\nor ask the Ferret dialog to tune the analysis"));
6009 msg.set_secondary_text (_("Press OK to continue with this split operation"));
6012 msg.set_title (_("Excessive split?"));
6015 int response = msg.run();
6021 case RESPONSE_APPLY:
6022 use_rhythmic_rodent = true;
6029 if (use_rhythmic_rodent) {
6030 show_rhythm_ferret ();
6034 AnalysisFeatureList::const_iterator x;
6036 pl->clear_changes ();
6037 pl->clear_owned_changes ();
6039 x = positions.begin();
6041 if (x == positions.end()) {
6046 pl->remove_region (r);
6050 while (x != positions.end()) {
6052 /* deal with positons that are out of scope of present region bounds */
6053 if (*x <= 0 || *x > r->length()) {
6058 /* file start = original start + how far we from the initial position ?
6061 framepos_t file_start = r->start() + pos;
6063 /* length = next position - current position
6066 framepos_t len = (*x) - pos;
6068 /* XXX we do we really want to allow even single-sample regions?
6069 shouldn't we have some kind of lower limit on region size?
6078 if (RegionFactory::region_name (new_name, r->name())) {
6082 /* do NOT announce new regions 1 by one, just wait till they are all done */
6086 plist.add (ARDOUR::Properties::start, file_start);
6087 plist.add (ARDOUR::Properties::length, len);
6088 plist.add (ARDOUR::Properties::name, new_name);
6089 plist.add (ARDOUR::Properties::layer, 0);
6091 boost::shared_ptr<Region> nr = RegionFactory::create (r->sources(), plist, false);
6092 /* because we set annouce to false, manually add the new region to the
6095 RegionFactory::map_add (nr);
6097 pl->add_region (nr, r->position() + pos);
6100 new_regions.push_front(nr);
6109 RegionFactory::region_name (new_name, r->name());
6111 /* Add the final region */
6114 plist.add (ARDOUR::Properties::start, r->start() + pos);
6115 plist.add (ARDOUR::Properties::length, r->last_frame() - (r->position() + pos) + 1);
6116 plist.add (ARDOUR::Properties::name, new_name);
6117 plist.add (ARDOUR::Properties::layer, 0);
6119 boost::shared_ptr<Region> nr = RegionFactory::create (r->sources(), plist, false);
6120 /* because we set annouce to false, manually add the new region to the
6123 RegionFactory::map_add (nr);
6124 pl->add_region (nr, r->position() + pos);
6127 new_regions.push_front(nr);
6132 /* We might have removed regions, which alters other regions' layering_index,
6133 so we need to do a recursive diff here.
6135 vector<Command*> cmds;
6137 _session->add_commands (cmds);
6139 _session->add_command (new StatefulDiffCommand (pl));
6143 for (list<boost::shared_ptr<Region> >::iterator i = new_regions.begin(); i != new_regions.end(); ++i){
6144 set_selected_regionview_from_region_list ((*i), Selection::Add);
6150 Editor::place_transient()
6156 RegionSelection rs = get_regions_from_selection_and_edit_point ();
6162 framepos_t where = get_preferred_edit_position();
6164 _session->begin_reversible_command (_("place transient"));
6166 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6167 framepos_t position = (*r)->region()->position();
6168 (*r)->region()->add_transient(where - position);
6171 _session->commit_reversible_command ();
6175 Editor::remove_transient(ArdourCanvas::Item* item)
6181 ArdourCanvas::Line* _line = reinterpret_cast<ArdourCanvas::Line*> (item);
6184 AudioRegionView* _arv = reinterpret_cast<AudioRegionView*> (item->get_data ("regionview"));
6185 _arv->remove_transient (*(float*) _line->get_data ("position"));
6189 Editor::snap_regions_to_grid ()
6191 list <boost::shared_ptr<Playlist > > used_playlists;
6193 RegionSelection rs = get_regions_from_selection_and_entered ();
6195 if (!_session || rs.empty()) {
6199 _session->begin_reversible_command (_("snap regions to grid"));
6201 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6203 boost::shared_ptr<Playlist> pl = (*r)->region()->playlist();
6205 if (!pl->frozen()) {
6206 /* we haven't seen this playlist before */
6208 /* remember used playlists so we can thaw them later */
6209 used_playlists.push_back(pl);
6213 framepos_t start_frame = (*r)->region()->first_frame ();
6214 snap_to (start_frame);
6215 (*r)->region()->set_position (start_frame);
6218 while (used_playlists.size() > 0) {
6219 list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
6221 used_playlists.pop_front();
6224 _session->commit_reversible_command ();
6228 Editor::close_region_gaps ()
6230 list <boost::shared_ptr<Playlist > > used_playlists;
6232 RegionSelection rs = get_regions_from_selection_and_entered ();
6234 if (!_session || rs.empty()) {
6238 Dialog dialog (_("Close Region Gaps"));
6241 table.set_spacings (12);
6242 table.set_border_width (12);
6243 Label* l = manage (left_aligned_label (_("Crossfade length")));
6244 table.attach (*l, 0, 1, 0, 1);
6246 SpinButton spin_crossfade (1, 0);
6247 spin_crossfade.set_range (0, 15);
6248 spin_crossfade.set_increments (1, 1);
6249 spin_crossfade.set_value (5);
6250 table.attach (spin_crossfade, 1, 2, 0, 1);
6252 table.attach (*manage (new Label (_("ms"))), 2, 3, 0, 1);
6254 l = manage (left_aligned_label (_("Pull-back length")));
6255 table.attach (*l, 0, 1, 1, 2);
6257 SpinButton spin_pullback (1, 0);
6258 spin_pullback.set_range (0, 100);
6259 spin_pullback.set_increments (1, 1);
6260 spin_pullback.set_value(30);
6261 table.attach (spin_pullback, 1, 2, 1, 2);
6263 table.attach (*manage (new Label (_("ms"))), 2, 3, 1, 2);
6265 dialog.get_vbox()->pack_start (table);
6266 dialog.add_button (Stock::CANCEL, RESPONSE_CANCEL);
6267 dialog.add_button (_("Ok"), RESPONSE_ACCEPT);
6270 if (dialog.run () == RESPONSE_CANCEL) {
6274 framepos_t crossfade_len = spin_crossfade.get_value();
6275 framepos_t pull_back_frames = spin_pullback.get_value();
6277 crossfade_len = lrintf (crossfade_len * _session->frame_rate()/1000);
6278 pull_back_frames = lrintf (pull_back_frames * _session->frame_rate()/1000);
6280 /* Iterate over the region list and make adjacent regions overlap by crossfade_len_ms */
6282 _session->begin_reversible_command (_("close region gaps"));
6285 boost::shared_ptr<Region> last_region;
6287 rs.sort_by_position_and_track();
6289 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6291 boost::shared_ptr<Playlist> pl = (*r)->region()->playlist();
6293 if (!pl->frozen()) {
6294 /* we haven't seen this playlist before */
6296 /* remember used playlists so we can thaw them later */
6297 used_playlists.push_back(pl);
6301 framepos_t position = (*r)->region()->position();
6303 if (idx == 0 || position < last_region->position()){
6304 last_region = (*r)->region();
6309 (*r)->region()->trim_front( (position - pull_back_frames));
6310 last_region->trim_end( (position - pull_back_frames + crossfade_len));
6312 last_region = (*r)->region();
6317 while (used_playlists.size() > 0) {
6318 list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
6320 used_playlists.pop_front();
6323 _session->commit_reversible_command ();
6327 Editor::tab_to_transient (bool forward)
6329 AnalysisFeatureList positions;
6331 RegionSelection rs = get_regions_from_selection_and_entered ();
6337 framepos_t pos = _session->audible_frame ();
6339 if (!selection->tracks.empty()) {
6341 /* don't waste time searching for transients in duplicate playlists.
6344 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
6346 for (TrackViewList::iterator t = ts.begin(); t != ts.end(); ++t) {
6348 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*t);
6351 boost::shared_ptr<Track> tr = rtv->track();
6353 boost::shared_ptr<Playlist> pl = tr->playlist ();
6355 framepos_t result = pl->find_next_transient (pos, forward ? 1 : -1);
6358 positions.push_back (result);
6371 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6372 (*r)->region()->get_transients (positions);
6376 TransientDetector::cleanup_transients (positions, _session->frame_rate(), 3.0);
6379 AnalysisFeatureList::iterator x;
6381 for (x = positions.begin(); x != positions.end(); ++x) {
6387 if (x != positions.end ()) {
6388 _session->request_locate (*x);
6392 AnalysisFeatureList::reverse_iterator x;
6394 for (x = positions.rbegin(); x != positions.rend(); ++x) {
6400 if (x != positions.rend ()) {
6401 _session->request_locate (*x);
6407 Editor::playhead_forward_to_grid ()
6413 framepos_t pos = playhead_cursor->current_frame ();
6414 if (pos < max_framepos - 1) {
6416 snap_to_internal (pos, 1, false);
6417 _session->request_locate (pos);
6423 Editor::playhead_backward_to_grid ()
6429 framepos_t pos = playhead_cursor->current_frame ();
6432 snap_to_internal (pos, -1, false);
6433 _session->request_locate (pos);
6438 Editor::set_track_height (Height h)
6440 TrackSelection& ts (selection->tracks);
6442 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
6443 (*x)->set_height_enum (h);
6448 Editor::toggle_tracks_active ()
6450 TrackSelection& ts (selection->tracks);
6452 bool target = false;
6458 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
6459 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*x);
6463 target = !rtv->_route->active();
6466 rtv->_route->set_active (target, this);
6472 Editor::remove_tracks ()
6474 TrackSelection& ts (selection->tracks);
6480 vector<string> choices;
6484 const char* trackstr;
6486 vector<boost::shared_ptr<Route> > routes;
6487 bool special_bus = false;
6489 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
6490 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*x);
6494 if (rtv->is_track()) {
6499 routes.push_back (rtv->_route);
6501 if (rtv->route()->is_master() || rtv->route()->is_monitor()) {
6506 if (special_bus && !Config->get_allow_special_bus_removal()) {
6507 MessageDialog msg (_("That would be bad news ...."),
6511 msg.set_secondary_text (string_compose (_(
6512 "Removing the master or monitor bus is such a bad idea\n\
6513 that %1 is not going to allow it.\n\
6515 If you really want to do this sort of thing\n\
6516 edit your ardour.rc file to set the\n\
6517 \"allow-special-bus-removal\" option to be \"yes\""), PROGRAM_NAME));
6524 if (ntracks + nbusses == 0) {
6529 trackstr = _("tracks");
6531 trackstr = _("track");
6535 busstr = _("busses");
6542 prompt = string_compose (_("Do you really want to remove %1 %2 and %3 %4?\n"
6543 "(You may also lose the playlists associated with the %2)\n\n"
6544 "This action cannot be undone, and the session file will be overwritten!"),
6545 ntracks, trackstr, nbusses, busstr);
6547 prompt = string_compose (_("Do you really want to remove %1 %2?\n"
6548 "(You may also lose the playlists associated with the %2)\n\n"
6549 "This action cannot be undone, and the session file will be overwritten!"),
6552 } else if (nbusses) {
6553 prompt = string_compose (_("Do you really want to remove %1 %2?\n\n"
6554 "This action cannot be undon, and the session file will be overwritten"),
6558 choices.push_back (_("No, do nothing."));
6559 if (ntracks + nbusses > 1) {
6560 choices.push_back (_("Yes, remove them."));
6562 choices.push_back (_("Yes, remove it."));
6567 title = string_compose (_("Remove %1"), trackstr);
6569 title = string_compose (_("Remove %1"), busstr);
6572 Choice prompter (title, prompt, choices);
6574 if (prompter.run () != 1) {
6578 for (vector<boost::shared_ptr<Route> >::iterator x = routes.begin(); x != routes.end(); ++x) {
6579 _session->remove_route (*x);
6584 Editor::do_insert_time ()
6586 if (selection->tracks.empty()) {
6590 InsertTimeDialog d (*this);
6591 int response = d.run ();
6593 if (response != RESPONSE_OK) {
6597 if (d.distance() == 0) {
6601 InsertTimeOption opt = d.intersected_region_action ();
6604 get_preferred_edit_position(),
6610 d.move_glued_markers(),
6611 d.move_locked_markers(),
6617 Editor::insert_time (
6618 framepos_t pos, framecnt_t frames, InsertTimeOption opt,
6619 bool all_playlists, bool ignore_music_glue, bool markers_too, bool glued_markers_too, bool locked_markers_too, bool tempo_too
6622 bool commit = false;
6624 if (Config->get_edit_mode() == Lock) {
6628 begin_reversible_command (_("insert time"));
6630 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
6632 for (TrackViewList::iterator x = ts.begin(); x != ts.end(); ++x) {
6636 /* don't operate on any playlist more than once, which could
6637 * happen if "all playlists" is enabled, but there is more
6638 * than 1 track using playlists "from" a given track.
6641 set<boost::shared_ptr<Playlist> > pl;
6643 if (all_playlists) {
6644 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*x);
6646 vector<boost::shared_ptr<Playlist> > all = _session->playlists->playlists_for_track (rtav->track ());
6647 for (vector<boost::shared_ptr<Playlist> >::iterator p = all.begin(); p != all.end(); ++p) {
6652 if ((*x)->playlist ()) {
6653 pl.insert ((*x)->playlist ());
6657 for (set<boost::shared_ptr<Playlist> >::iterator i = pl.begin(); i != pl.end(); ++i) {
6659 (*i)->clear_changes ();
6660 (*i)->clear_owned_changes ();
6662 if (opt == SplitIntersected) {
6666 (*i)->shift (pos, frames, (opt == MoveIntersected), ignore_music_glue);
6668 vector<Command*> cmds;
6670 _session->add_commands (cmds);
6672 _session->add_command (new StatefulDiffCommand (*i));
6677 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*x);
6679 rtav->route ()->shift (pos, frames);
6687 XMLNode& before (_session->locations()->get_state());
6688 Locations::LocationList copy (_session->locations()->list());
6690 for (Locations::LocationList::iterator i = copy.begin(); i != copy.end(); ++i) {
6692 Locations::LocationList::const_iterator tmp;
6694 bool const was_locked = (*i)->locked ();
6695 if (locked_markers_too) {
6699 if ((*i)->position_lock_style() == AudioTime || glued_markers_too) {
6701 if ((*i)->start() >= pos) {
6702 (*i)->set_start ((*i)->start() + frames);
6703 if (!(*i)->is_mark()) {
6704 (*i)->set_end ((*i)->end() + frames);
6717 XMLNode& after (_session->locations()->get_state());
6718 _session->add_command (new MementoCommand<Locations>(*_session->locations(), &before, &after));
6723 _session->tempo_map().insert_time (pos, frames);
6727 commit_reversible_command ();
6732 Editor::fit_selected_tracks ()
6734 if (!selection->tracks.empty()) {
6735 fit_tracks (selection->tracks);
6739 /* no selected tracks - use tracks with selected regions */
6741 if (!selection->regions.empty()) {
6742 for (RegionSelection::iterator r = selection->regions.begin(); r != selection->regions.end(); ++r) {
6743 tvl.push_back (&(*r)->get_time_axis_view ());
6749 } else if (internal_editing()) {
6750 /* no selected tracks, or regions, but in internal edit mode, so follow the mouse and use
6753 if (entered_track) {
6754 tvl.push_back (entered_track);
6762 Editor::fit_tracks (TrackViewList & tracks)
6764 if (tracks.empty()) {
6768 uint32_t child_heights = 0;
6769 int visible_tracks = 0;
6771 for (TrackSelection::iterator t = tracks.begin(); t != tracks.end(); ++t) {
6773 if (!(*t)->marked_for_display()) {
6777 child_heights += (*t)->effective_height() - (*t)->current_height();
6781 uint32_t h = (uint32_t) floor ((_visible_canvas_height - child_heights) / visible_tracks);
6782 double first_y_pos = DBL_MAX;
6784 if (h < TimeAxisView::preset_height (HeightSmall)) {
6785 MessageDialog msg (*this, _("There are too many tracks to fit in the current window"));
6786 /* too small to be displayed */
6790 undo_visual_stack.push_back (current_visual_state (true));
6791 no_save_visual = true;
6793 /* build a list of all tracks, including children */
6796 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
6798 TimeAxisView::Children c = (*i)->get_child_list ();
6799 for (TimeAxisView::Children::iterator j = c.begin(); j != c.end(); ++j) {
6800 all.push_back (j->get());
6804 /* operate on all tracks, hide unselected ones that are in the middle of selected ones */
6806 bool prev_was_selected = false;
6807 bool is_selected = tracks.contains (all.front());
6808 bool next_is_selected;
6810 for (TrackViewList::iterator t = all.begin(); t != all.end(); ++t) {
6812 TrackViewList::iterator next;
6817 if (next != all.end()) {
6818 next_is_selected = tracks.contains (*next);
6820 next_is_selected = false;
6823 if ((*t)->marked_for_display ()) {
6825 (*t)->set_height (h);
6826 first_y_pos = std::min ((*t)->y_position (), first_y_pos);
6828 if (prev_was_selected && next_is_selected) {
6829 hide_track_in_display (*t);
6834 prev_was_selected = is_selected;
6835 is_selected = next_is_selected;
6839 set the controls_layout height now, because waiting for its size
6840 request signal handler will cause the vertical adjustment setting to fail
6843 controls_layout.property_height () = _full_canvas_height;
6844 vertical_adjustment.set_value (first_y_pos);
6846 redo_visual_stack.push_back (current_visual_state (true));
6850 Editor::save_visual_state (uint32_t n)
6852 while (visual_states.size() <= n) {
6853 visual_states.push_back (0);
6856 if (visual_states[n] != 0) {
6857 delete visual_states[n];
6860 visual_states[n] = current_visual_state (true);
6865 Editor::goto_visual_state (uint32_t n)
6867 if (visual_states.size() <= n) {
6871 if (visual_states[n] == 0) {
6875 use_visual_state (*visual_states[n]);
6879 Editor::start_visual_state_op (uint32_t n)
6881 save_visual_state (n);
6883 PopUp* pup = new PopUp (WIN_POS_MOUSE, 1000, true);
6885 snprintf (buf, sizeof (buf), _("Saved view %u"), n+1);
6886 pup->set_text (buf);
6891 Editor::cancel_visual_state_op (uint32_t n)
6893 goto_visual_state (n);
6897 Editor::toggle_region_mute ()
6899 if (_ignore_region_action) {
6903 RegionSelection rs = get_regions_from_selection_and_entered ();
6909 if (rs.size() > 1) {
6910 begin_reversible_command (_("mute regions"));
6912 begin_reversible_command (_("mute region"));
6915 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
6917 (*i)->region()->playlist()->clear_changes ();
6918 (*i)->region()->set_muted (!(*i)->region()->muted ());
6919 _session->add_command (new StatefulDiffCommand ((*i)->region()->playlist()));
6923 commit_reversible_command ();
6927 Editor::combine_regions ()
6929 /* foreach track with selected regions, take all selected regions
6930 and join them into a new region containing the subregions (as a
6934 typedef set<RouteTimeAxisView*> RTVS;
6937 if (selection->regions.empty()) {
6941 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
6942 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(&(*i)->get_time_axis_view());
6945 tracks.insert (rtv);
6949 begin_reversible_command (_("combine regions"));
6951 vector<RegionView*> new_selection;
6953 for (RTVS::iterator i = tracks.begin(); i != tracks.end(); ++i) {
6956 if ((rv = (*i)->combine_regions ()) != 0) {
6957 new_selection.push_back (rv);
6961 selection->clear_regions ();
6962 for (vector<RegionView*>::iterator i = new_selection.begin(); i != new_selection.end(); ++i) {
6963 selection->add (*i);
6966 commit_reversible_command ();
6970 Editor::uncombine_regions ()
6972 typedef set<RouteTimeAxisView*> RTVS;
6975 if (selection->regions.empty()) {
6979 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
6980 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(&(*i)->get_time_axis_view());
6983 tracks.insert (rtv);
6987 begin_reversible_command (_("uncombine regions"));
6989 for (RTVS::iterator i = tracks.begin(); i != tracks.end(); ++i) {
6990 (*i)->uncombine_regions ();
6993 commit_reversible_command ();
6997 Editor::toggle_midi_input_active (bool flip_others)
7000 boost::shared_ptr<RouteList> rl (new RouteList);
7002 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
7003 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
7009 boost::shared_ptr<MidiTrack> mt = rtav->midi_track();
7012 rl->push_back (rtav->route());
7013 onoff = !mt->input_active();
7017 _session->set_exclusive_input_active (rl, onoff, flip_others);