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_drag (boost::shared_ptr<Region> region, int x, int y)
2089 RouteTimeAxisView *rtv = 0;
2090 boost::shared_ptr<Playlist> playlist;
2093 event.type = GDK_BUTTON_RELEASE;
2097 where = window_event_sample (&event, &cx, &cy);
2099 if (where < leftmost_frame || where > leftmost_frame + current_page_samples()) {
2100 /* clearly outside canvas area */
2104 std::pair<TimeAxisView*, int> tv = trackview_by_y_position (cy);
2105 if (tv.first == 0) {
2109 if ((rtv = dynamic_cast<RouteTimeAxisView*> (tv.first)) == 0) {
2113 if ((playlist = rtv->playlist()) == 0) {
2119 begin_reversible_command (_("insert dragged region"));
2120 playlist->clear_changes ();
2121 playlist->add_region (RegionFactory::create (region, true), where, 1.0);
2122 if (Config->get_edit_mode() == Ripple)
2123 playlist->ripple (where, region->length(), boost::shared_ptr<Region>());
2125 _session->add_command(new StatefulDiffCommand (playlist));
2126 commit_reversible_command ();
2130 Editor::insert_route_list_drag (boost::shared_ptr<Route> route, int x, int y)
2133 RouteTimeAxisView *dest_rtv = 0;
2134 RouteTimeAxisView *source_rtv = 0;
2137 event.type = GDK_BUTTON_RELEASE;
2141 window_event_sample (&event, &cx, &cy);
2143 std::pair<TimeAxisView*, int> const tv = trackview_by_y_position (cy);
2144 if (tv.first == 0) {
2148 if ((dest_rtv = dynamic_cast<RouteTimeAxisView*> (tv.first)) == 0) {
2152 /* use this drag source to add underlay to a track. But we really don't care
2153 about the Route, only the view of the route, so find it first */
2154 for(TrackViewList::iterator it = track_views.begin(); it != track_views.end(); ++it) {
2155 if((source_rtv = dynamic_cast<RouteTimeAxisView*>(*it)) == 0) {
2159 if(source_rtv->route() == route && source_rtv != dest_rtv) {
2160 dest_rtv->add_underlay(source_rtv->view());
2167 Editor::insert_region_list_selection (float times)
2169 RouteTimeAxisView *tv = 0;
2170 boost::shared_ptr<Playlist> playlist;
2172 if (clicked_routeview != 0) {
2173 tv = clicked_routeview;
2174 } else if (!selection->tracks.empty()) {
2175 if ((tv = dynamic_cast<RouteTimeAxisView*>(selection->tracks.front())) == 0) {
2178 } else if (entered_track != 0) {
2179 if ((tv = dynamic_cast<RouteTimeAxisView*>(entered_track)) == 0) {
2186 if ((playlist = tv->playlist()) == 0) {
2190 boost::shared_ptr<Region> region = _regions->get_single_selection ();
2195 begin_reversible_command (_("insert region"));
2196 playlist->clear_changes ();
2197 playlist->add_region ((RegionFactory::create (region, true)), get_preferred_edit_position(), times);
2198 if (Config->get_edit_mode() == Ripple)
2199 playlist->ripple (get_preferred_edit_position(), region->length() * times, boost::shared_ptr<Region>());
2201 _session->add_command(new StatefulDiffCommand (playlist));
2202 commit_reversible_command ();
2205 /* BUILT-IN EFFECTS */
2208 Editor::reverse_selection ()
2213 /* GAIN ENVELOPE EDITING */
2216 Editor::edit_envelope ()
2223 Editor::transition_to_rolling (bool fwd)
2229 if (_session->config.get_external_sync()) {
2230 switch (Config->get_sync_source()) {
2234 /* transport controlled by the master */
2239 if (_session->is_auditioning()) {
2240 _session->cancel_audition ();
2244 _session->request_transport_speed (fwd ? 1.0f : -1.0f);
2248 Editor::play_from_start ()
2250 _session->request_locate (_session->current_start_frame(), true);
2254 Editor::play_from_edit_point ()
2256 _session->request_locate (get_preferred_edit_position(), true);
2260 Editor::play_from_edit_point_and_return ()
2262 framepos_t start_frame;
2263 framepos_t return_frame;
2265 start_frame = get_preferred_edit_position (true);
2267 if (_session->transport_rolling()) {
2268 _session->request_locate (start_frame, false);
2272 /* don't reset the return frame if its already set */
2274 if ((return_frame = _session->requested_return_frame()) < 0) {
2275 return_frame = _session->audible_frame();
2278 if (start_frame >= 0) {
2279 _session->request_roll_at_and_return (start_frame, return_frame);
2284 Editor::play_selection ()
2286 if (selection->time.empty()) {
2290 _session->request_play_range (&selection->time, true);
2294 Editor::get_preroll ()
2296 return 1.0 /*Config->get_edit_preroll_seconds()*/ * _session->frame_rate();
2301 Editor::maybe_locate_with_edit_preroll ( framepos_t location )
2303 if ( _session->transport_rolling() || !Config->get_always_play_range() )
2306 location -= get_preroll();
2308 //don't try to locate before the beginning of time
2312 //if follow_playhead is on, keep the playhead on the screen
2313 if ( _follow_playhead )
2314 if ( location < leftmost_frame )
2315 location = leftmost_frame;
2317 _session->request_locate( location );
2321 Editor::play_with_preroll ()
2323 if (selection->time.empty()) {
2326 framepos_t preroll = get_preroll();
2328 framepos_t start = 0;
2329 if (selection->time[clicked_selection].start > preroll)
2330 start = selection->time[clicked_selection].start - preroll;
2332 framepos_t end = selection->time[clicked_selection].end + preroll;
2334 AudioRange ar (start, end, 0);
2335 list<AudioRange> lar;
2338 _session->request_play_range (&lar, true);
2343 Editor::play_location (Location& location)
2345 if (location.start() <= location.end()) {
2349 _session->request_bounded_roll (location.start(), location.end());
2353 Editor::loop_location (Location& location)
2355 if (location.start() <= location.end()) {
2361 if ((tll = transport_loop_location()) != 0) {
2362 tll->set (location.start(), location.end());
2364 // enable looping, reposition and start rolling
2365 _session->request_play_loop (true);
2366 _session->request_locate (tll->start(), true);
2371 Editor::do_layer_operation (LayerOperation op)
2373 if (selection->regions.empty ()) {
2377 bool const multiple = selection->regions.size() > 1;
2381 begin_reversible_command (_("raise regions"));
2383 begin_reversible_command (_("raise region"));
2389 begin_reversible_command (_("raise regions to top"));
2391 begin_reversible_command (_("raise region to top"));
2397 begin_reversible_command (_("lower regions"));
2399 begin_reversible_command (_("lower region"));
2405 begin_reversible_command (_("lower regions to bottom"));
2407 begin_reversible_command (_("lower region"));
2412 set<boost::shared_ptr<Playlist> > playlists = selection->regions.playlists ();
2413 for (set<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
2414 (*i)->clear_owned_changes ();
2417 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
2418 boost::shared_ptr<Region> r = (*i)->region ();
2430 r->lower_to_bottom ();
2434 for (set<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
2435 vector<Command*> cmds;
2437 _session->add_commands (cmds);
2440 commit_reversible_command ();
2444 Editor::raise_region ()
2446 do_layer_operation (Raise);
2450 Editor::raise_region_to_top ()
2452 do_layer_operation (RaiseToTop);
2456 Editor::lower_region ()
2458 do_layer_operation (Lower);
2462 Editor::lower_region_to_bottom ()
2464 do_layer_operation (LowerToBottom);
2467 /** Show the region editor for the selected regions */
2469 Editor::show_region_properties ()
2471 selection->foreach_regionview (&RegionView::show_region_editor);
2474 /** Show the midi list editor for the selected MIDI regions */
2476 Editor::show_midi_list_editor ()
2478 selection->foreach_midi_regionview (&MidiRegionView::show_list_editor);
2482 Editor::rename_region ()
2484 RegionSelection rs = get_regions_from_selection_and_entered ();
2490 ArdourDialog d (*this, _("Rename Region"), true, false);
2492 Label label (_("New name:"));
2495 hbox.set_spacing (6);
2496 hbox.pack_start (label, false, false);
2497 hbox.pack_start (entry, true, true);
2499 d.get_vbox()->set_border_width (12);
2500 d.get_vbox()->pack_start (hbox, false, false);
2502 d.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
2503 d.add_button(Gtk::Stock::OK, Gtk::RESPONSE_OK);
2505 d.set_size_request (300, -1);
2507 entry.set_text (rs.front()->region()->name());
2508 entry.select_region (0, -1);
2510 entry.signal_activate().connect (sigc::bind (sigc::mem_fun (d, &Dialog::response), RESPONSE_OK));
2516 int const ret = d.run();
2520 if (ret != RESPONSE_OK) {
2524 std::string str = entry.get_text();
2525 strip_whitespace_edges (str);
2527 rs.front()->region()->set_name (str);
2528 _regions->redisplay ();
2533 Editor::audition_playlist_region_via_route (boost::shared_ptr<Region> region, Route& route)
2535 if (_session->is_auditioning()) {
2536 _session->cancel_audition ();
2539 // note: some potential for creativity here, because region doesn't
2540 // have to belong to the playlist that Route is handling
2542 // bool was_soloed = route.soloed();
2544 route.set_solo (true, this);
2546 _session->request_bounded_roll (region->position(), region->position() + region->length());
2548 /* XXX how to unset the solo state ? */
2551 /** Start an audition of the first selected region */
2553 Editor::play_edit_range ()
2555 framepos_t start, end;
2557 if (get_edit_op_range (start, end)) {
2558 _session->request_bounded_roll (start, end);
2563 Editor::play_selected_region ()
2565 framepos_t start = max_framepos;
2568 RegionSelection rs = get_regions_from_selection_and_entered ();
2574 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
2575 if ((*i)->region()->position() < start) {
2576 start = (*i)->region()->position();
2578 if ((*i)->region()->last_frame() + 1 > end) {
2579 end = (*i)->region()->last_frame() + 1;
2583 _session->request_bounded_roll (start, end);
2587 Editor::audition_playlist_region_standalone (boost::shared_ptr<Region> region)
2589 _session->audition_region (region);
2593 Editor::region_from_selection ()
2595 if (clicked_axisview == 0) {
2599 if (selection->time.empty()) {
2603 framepos_t start = selection->time[clicked_selection].start;
2604 framepos_t end = selection->time[clicked_selection].end;
2606 TrackViewList tracks = get_tracks_for_range_action ();
2608 framepos_t selection_cnt = end - start + 1;
2610 for (TrackSelection::iterator i = tracks.begin(); i != tracks.end(); ++i) {
2611 boost::shared_ptr<Region> current;
2612 boost::shared_ptr<Playlist> pl;
2613 framepos_t internal_start;
2616 if ((pl = (*i)->playlist()) == 0) {
2620 if ((current = pl->top_region_at (start)) == 0) {
2624 internal_start = start - current->position();
2625 RegionFactory::region_name (new_name, current->name(), true);
2629 plist.add (ARDOUR::Properties::start, current->start() + internal_start);
2630 plist.add (ARDOUR::Properties::length, selection_cnt);
2631 plist.add (ARDOUR::Properties::name, new_name);
2632 plist.add (ARDOUR::Properties::layer, 0);
2634 boost::shared_ptr<Region> region (RegionFactory::create (current, plist));
2639 Editor::create_region_from_selection (vector<boost::shared_ptr<Region> >& new_regions)
2641 if (selection->time.empty() || selection->tracks.empty()) {
2645 framepos_t start = selection->time[clicked_selection].start;
2646 framepos_t end = selection->time[clicked_selection].end;
2648 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
2649 sort_track_selection (ts);
2651 for (TrackSelection::iterator i = ts.begin(); i != ts.end(); ++i) {
2652 boost::shared_ptr<Region> current;
2653 boost::shared_ptr<Playlist> playlist;
2654 framepos_t internal_start;
2657 if ((playlist = (*i)->playlist()) == 0) {
2661 if ((current = playlist->top_region_at(start)) == 0) {
2665 internal_start = start - current->position();
2666 RegionFactory::region_name (new_name, current->name(), true);
2670 plist.add (ARDOUR::Properties::start, current->start() + internal_start);
2671 plist.add (ARDOUR::Properties::length, end - start + 1);
2672 plist.add (ARDOUR::Properties::name, new_name);
2674 new_regions.push_back (RegionFactory::create (current, plist));
2679 Editor::split_multichannel_region ()
2681 RegionSelection rs = get_regions_from_selection_and_entered ();
2687 vector< boost::shared_ptr<Region> > v;
2689 for (list<RegionView*>::iterator x = rs.begin(); x != rs.end(); ++x) {
2690 (*x)->region()->separate_by_channel (*_session, v);
2695 Editor::new_region_from_selection ()
2697 region_from_selection ();
2698 cancel_selection ();
2702 add_if_covered (RegionView* rv, const AudioRange* ar, RegionSelection* rs)
2704 switch (rv->region()->coverage (ar->start, ar->end - 1)) {
2705 case Evoral::OverlapNone:
2713 * - selected tracks, or if there are none...
2714 * - tracks containing selected regions, or if there are none...
2719 Editor::get_tracks_for_range_action () const
2723 if (selection->tracks.empty()) {
2725 /* use tracks with selected regions */
2727 RegionSelection rs = selection->regions;
2729 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
2730 TimeAxisView* tv = &(*i)->get_time_axis_view();
2732 if (!t.contains (tv)) {
2738 /* no regions and no tracks: use all tracks */
2744 t = selection->tracks;
2747 return t.filter_to_unique_playlists();
2751 Editor::separate_regions_between (const TimeSelection& ts)
2753 bool in_command = false;
2754 boost::shared_ptr<Playlist> playlist;
2755 RegionSelection new_selection;
2757 TrackViewList tmptracks = get_tracks_for_range_action ();
2758 sort_track_selection (tmptracks);
2760 for (TrackSelection::iterator i = tmptracks.begin(); i != tmptracks.end(); ++i) {
2762 RouteTimeAxisView* rtv;
2764 if ((rtv = dynamic_cast<RouteTimeAxisView*> ((*i))) != 0) {
2766 if (rtv->is_track()) {
2768 /* no edits to destructive tracks */
2770 if (rtv->track()->destructive()) {
2774 if ((playlist = rtv->playlist()) != 0) {
2776 playlist->clear_changes ();
2778 /* XXX need to consider musical time selections here at some point */
2780 double speed = rtv->track()->speed();
2783 for (list<AudioRange>::const_iterator t = ts.begin(); t != ts.end(); ++t) {
2785 sigc::connection c = rtv->view()->RegionViewAdded.connect (
2786 sigc::mem_fun(*this, &Editor::collect_new_region_view));
2788 latest_regionviews.clear ();
2790 playlist->partition ((framepos_t)((*t).start * speed),
2791 (framepos_t)((*t).end * speed), false);
2795 if (!latest_regionviews.empty()) {
2797 rtv->view()->foreach_regionview (sigc::bind (
2798 sigc::ptr_fun (add_if_covered),
2799 &(*t), &new_selection));
2802 begin_reversible_command (_("separate"));
2806 /* pick up changes to existing regions */
2808 vector<Command*> cmds;
2809 playlist->rdiff (cmds);
2810 _session->add_commands (cmds);
2812 /* pick up changes to the playlist itself (adds/removes)
2815 _session->add_command(new StatefulDiffCommand (playlist));
2824 selection->set (new_selection);
2825 set_mouse_mode (MouseObject);
2827 commit_reversible_command ();
2831 struct PlaylistState {
2832 boost::shared_ptr<Playlist> playlist;
2836 /** Take tracks from get_tracks_for_range_action and cut any regions
2837 * on those tracks so that the tracks are empty over the time
2841 Editor::separate_region_from_selection ()
2843 /* preferentially use *all* ranges in the time selection if we're in range mode
2844 to allow discontiguous operation, since get_edit_op_range() currently
2845 returns a single range.
2848 if (!selection->time.empty()) {
2850 separate_regions_between (selection->time);
2857 if (get_edit_op_range (start, end)) {
2859 AudioRange ar (start, end, 1);
2863 separate_regions_between (ts);
2869 Editor::separate_region_from_punch ()
2871 Location* loc = _session->locations()->auto_punch_location();
2873 separate_regions_using_location (*loc);
2878 Editor::separate_region_from_loop ()
2880 Location* loc = _session->locations()->auto_loop_location();
2882 separate_regions_using_location (*loc);
2887 Editor::separate_regions_using_location (Location& loc)
2889 if (loc.is_mark()) {
2893 AudioRange ar (loc.start(), loc.end(), 1);
2898 separate_regions_between (ts);
2901 /** Separate regions under the selected region */
2903 Editor::separate_under_selected_regions ()
2905 vector<PlaylistState> playlists;
2909 rs = get_regions_from_selection_and_entered();
2911 if (!_session || rs.empty()) {
2915 begin_reversible_command (_("separate region under"));
2917 list<boost::shared_ptr<Region> > regions_to_remove;
2919 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
2920 // we can't just remove the region(s) in this loop because
2921 // this removes them from the RegionSelection, and they thus
2922 // disappear from underneath the iterator, and the ++i above
2923 // SEGVs in a puzzling fashion.
2925 // so, first iterate over the regions to be removed from rs and
2926 // add them to the regions_to_remove list, and then
2927 // iterate over the list to actually remove them.
2929 regions_to_remove.push_back ((*i)->region());
2932 for (list<boost::shared_ptr<Region> >::iterator rl = regions_to_remove.begin(); rl != regions_to_remove.end(); ++rl) {
2934 boost::shared_ptr<Playlist> playlist = (*rl)->playlist();
2937 // is this check necessary?
2941 vector<PlaylistState>::iterator i;
2943 //only take state if this is a new playlist.
2944 for (i = playlists.begin(); i != playlists.end(); ++i) {
2945 if ((*i).playlist == playlist) {
2950 if (i == playlists.end()) {
2952 PlaylistState before;
2953 before.playlist = playlist;
2954 before.before = &playlist->get_state();
2956 playlist->freeze ();
2957 playlists.push_back(before);
2960 //Partition on the region bounds
2961 playlist->partition ((*rl)->first_frame() - 1, (*rl)->last_frame() + 1, true);
2963 //Re-add region that was just removed due to the partition operation
2964 playlist->add_region( (*rl), (*rl)->first_frame() );
2967 vector<PlaylistState>::iterator pl;
2969 for (pl = playlists.begin(); pl != playlists.end(); ++pl) {
2970 (*pl).playlist->thaw ();
2971 _session->add_command(new MementoCommand<Playlist>(*(*pl).playlist, (*pl).before, &(*pl).playlist->get_state()));
2974 commit_reversible_command ();
2978 Editor::crop_region_to_selection ()
2980 if (!selection->time.empty()) {
2982 crop_region_to (selection->time.start(), selection->time.end_frame());
2989 if (get_edit_op_range (start, end)) {
2990 crop_region_to (start, end);
2997 Editor::crop_region_to (framepos_t start, framepos_t end)
2999 vector<boost::shared_ptr<Playlist> > playlists;
3000 boost::shared_ptr<Playlist> playlist;
3003 if (selection->tracks.empty()) {
3004 ts = track_views.filter_to_unique_playlists();
3006 ts = selection->tracks.filter_to_unique_playlists ();
3009 sort_track_selection (ts);
3011 for (TrackSelection::iterator i = ts.begin(); i != ts.end(); ++i) {
3013 RouteTimeAxisView* rtv;
3015 if ((rtv = dynamic_cast<RouteTimeAxisView*> ((*i))) != 0) {
3017 boost::shared_ptr<Track> t = rtv->track();
3019 if (t != 0 && ! t->destructive()) {
3021 if ((playlist = rtv->playlist()) != 0) {
3022 playlists.push_back (playlist);
3028 if (playlists.empty()) {
3032 framepos_t the_start;
3036 begin_reversible_command (_("trim to selection"));
3038 for (vector<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
3040 boost::shared_ptr<Region> region;
3044 if ((region = (*i)->top_region_at(the_start)) == 0) {
3048 /* now adjust lengths to that we do the right thing
3049 if the selection extends beyond the region
3052 the_start = max (the_start, (framepos_t) region->position());
3053 if (max_framepos - the_start < region->length()) {
3054 the_end = the_start + region->length() - 1;
3056 the_end = max_framepos;
3058 the_end = min (end, the_end);
3059 cnt = the_end - the_start + 1;
3061 region->clear_changes ();
3062 region->trim_to (the_start, cnt);
3063 _session->add_command (new StatefulDiffCommand (region));
3066 commit_reversible_command ();
3070 Editor::region_fill_track ()
3072 RegionSelection rs = get_regions_from_selection_and_entered ();
3074 if (!_session || rs.empty()) {
3078 framepos_t const end = _session->current_end_frame ();
3080 begin_reversible_command (Operations::region_fill);
3082 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3084 boost::shared_ptr<Region> region ((*i)->region());
3086 boost::shared_ptr<Playlist> pl = region->playlist();
3088 if (end <= region->last_frame()) {
3092 double times = (double) (end - region->last_frame()) / (double) region->length();
3098 pl->clear_changes ();
3099 pl->add_region (RegionFactory::create (region, true), region->last_frame(), times);
3100 _session->add_command (new StatefulDiffCommand (pl));
3103 commit_reversible_command ();
3107 Editor::region_fill_selection ()
3109 if (clicked_routeview == 0 || !clicked_routeview->is_audio_track()) {
3113 if (selection->time.empty()) {
3117 boost::shared_ptr<Region> region = _regions->get_single_selection ();
3122 framepos_t start = selection->time[clicked_selection].start;
3123 framepos_t end = selection->time[clicked_selection].end;
3125 boost::shared_ptr<Playlist> playlist;
3127 if (selection->tracks.empty()) {
3131 framepos_t selection_length = end - start;
3132 float times = (float)selection_length / region->length();
3134 begin_reversible_command (Operations::fill_selection);
3136 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
3138 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
3140 if ((playlist = (*i)->playlist()) == 0) {
3144 playlist->clear_changes ();
3145 playlist->add_region (RegionFactory::create (region, true), start, times);
3146 _session->add_command (new StatefulDiffCommand (playlist));
3149 commit_reversible_command ();
3153 Editor::set_region_sync_position ()
3155 set_sync_point (get_preferred_edit_position (), get_regions_from_selection_and_edit_point ());
3159 Editor::set_sync_point (framepos_t where, const RegionSelection& rs)
3161 bool in_command = false;
3163 for (RegionSelection::const_iterator r = rs.begin(); r != rs.end(); ++r) {
3165 if (!(*r)->region()->covers (where)) {
3169 boost::shared_ptr<Region> region ((*r)->region());
3172 begin_reversible_command (_("set sync point"));
3176 region->clear_changes ();
3177 region->set_sync_position (where);
3178 _session->add_command(new StatefulDiffCommand (region));
3182 commit_reversible_command ();
3186 /** Remove the sync positions of the selection */
3188 Editor::remove_region_sync ()
3190 RegionSelection rs = get_regions_from_selection_and_entered ();
3196 begin_reversible_command (_("remove region sync"));
3198 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3200 (*i)->region()->clear_changes ();
3201 (*i)->region()->clear_sync_position ();
3202 _session->add_command(new StatefulDiffCommand ((*i)->region()));
3205 commit_reversible_command ();
3209 Editor::naturalize_region ()
3211 RegionSelection rs = get_regions_from_selection_and_entered ();
3217 if (rs.size() > 1) {
3218 begin_reversible_command (_("move regions to original position"));
3220 begin_reversible_command (_("move region to original position"));
3223 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3224 (*i)->region()->clear_changes ();
3225 (*i)->region()->move_to_natural_position ();
3226 _session->add_command (new StatefulDiffCommand ((*i)->region()));
3229 commit_reversible_command ();
3233 Editor::align_regions (RegionPoint what)
3235 RegionSelection const rs = get_regions_from_selection_and_edit_point ();
3241 begin_reversible_command (_("align selection"));
3243 framepos_t const position = get_preferred_edit_position ();
3245 for (RegionSelection::const_iterator i = rs.begin(); i != rs.end(); ++i) {
3246 align_region_internal ((*i)->region(), what, position);
3249 commit_reversible_command ();
3252 struct RegionSortByTime {
3253 bool operator() (const RegionView* a, const RegionView* b) {
3254 return a->region()->position() < b->region()->position();
3259 Editor::align_regions_relative (RegionPoint point)
3261 RegionSelection const rs = get_regions_from_selection_and_edit_point ();
3267 framepos_t const position = get_preferred_edit_position ();
3269 framepos_t distance = 0;
3273 list<RegionView*> sorted;
3274 rs.by_position (sorted);
3276 boost::shared_ptr<Region> r ((*sorted.begin())->region());
3281 if (position > r->position()) {
3282 distance = position - r->position();
3284 distance = r->position() - position;
3290 if (position > r->last_frame()) {
3291 distance = position - r->last_frame();
3292 pos = r->position() + distance;
3294 distance = r->last_frame() - position;
3295 pos = r->position() - distance;
3301 pos = r->adjust_to_sync (position);
3302 if (pos > r->position()) {
3303 distance = pos - r->position();
3305 distance = r->position() - pos;
3311 if (pos == r->position()) {
3315 begin_reversible_command (_("align selection (relative)"));
3317 /* move first one specially */
3319 r->clear_changes ();
3320 r->set_position (pos);
3321 _session->add_command(new StatefulDiffCommand (r));
3323 /* move rest by the same amount */
3327 for (list<RegionView*>::iterator i = sorted.begin(); i != sorted.end(); ++i) {
3329 boost::shared_ptr<Region> region ((*i)->region());
3331 region->clear_changes ();
3334 region->set_position (region->position() + distance);
3336 region->set_position (region->position() - distance);
3339 _session->add_command(new StatefulDiffCommand (region));
3343 commit_reversible_command ();
3347 Editor::align_region (boost::shared_ptr<Region> region, RegionPoint point, framepos_t position)
3349 begin_reversible_command (_("align region"));
3350 align_region_internal (region, point, position);
3351 commit_reversible_command ();
3355 Editor::align_region_internal (boost::shared_ptr<Region> region, RegionPoint point, framepos_t position)
3357 region->clear_changes ();
3361 region->set_position (region->adjust_to_sync (position));
3365 if (position > region->length()) {
3366 region->set_position (position - region->length());
3371 region->set_position (position);
3375 _session->add_command(new StatefulDiffCommand (region));
3379 Editor::trim_region_front ()
3385 Editor::trim_region_back ()
3387 trim_region (false);
3391 Editor::trim_region (bool front)
3393 framepos_t where = get_preferred_edit_position();
3394 RegionSelection rs = get_regions_from_selection_and_edit_point ();
3400 begin_reversible_command (front ? _("trim front") : _("trim back"));
3402 for (list<RegionView*>::const_iterator i = rs.by_layer().begin(); i != rs.by_layer().end(); ++i) {
3403 if (!(*i)->region()->locked()) {
3405 (*i)->region()->clear_changes ();
3408 (*i)->region()->trim_front (where);
3409 maybe_locate_with_edit_preroll ( where );
3411 (*i)->region()->trim_end (where);
3412 maybe_locate_with_edit_preroll ( where );
3415 _session->add_command (new StatefulDiffCommand ((*i)->region()));
3419 commit_reversible_command ();
3422 /** Trim the end of the selected regions to the position of the edit cursor */
3424 Editor::trim_region_to_loop ()
3426 Location* loc = _session->locations()->auto_loop_location();
3430 trim_region_to_location (*loc, _("trim to loop"));
3434 Editor::trim_region_to_punch ()
3436 Location* loc = _session->locations()->auto_punch_location();
3440 trim_region_to_location (*loc, _("trim to punch"));
3444 Editor::trim_region_to_location (const Location& loc, const char* str)
3446 RegionSelection rs = get_regions_from_selection_and_entered ();
3448 begin_reversible_command (str);
3450 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
3451 RegionView* rv = (*x);
3453 /* require region to span proposed trim */
3454 switch (rv->region()->coverage (loc.start(), loc.end())) {
3455 case Evoral::OverlapInternal:
3461 RouteTimeAxisView* tav = dynamic_cast<RouteTimeAxisView*> (&rv->get_time_axis_view());
3470 if (tav->track() != 0) {
3471 speed = tav->track()->speed();
3474 start = session_frame_to_track_frame (loc.start(), speed);
3475 end = session_frame_to_track_frame (loc.end(), speed);
3477 rv->region()->clear_changes ();
3478 rv->region()->trim_to (start, (end - start));
3479 _session->add_command(new StatefulDiffCommand (rv->region()));
3482 commit_reversible_command ();
3486 Editor::trim_region_to_previous_region_end ()
3488 return trim_to_region(false);
3492 Editor::trim_region_to_next_region_start ()
3494 return trim_to_region(true);
3498 Editor::trim_to_region(bool forward)
3500 RegionSelection rs = get_regions_from_selection_and_entered ();
3502 begin_reversible_command (_("trim to region"));
3504 boost::shared_ptr<Region> next_region;
3506 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
3508 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*x);
3514 AudioTimeAxisView* atav = dynamic_cast<AudioTimeAxisView*> (&arv->get_time_axis_view());
3522 if (atav->track() != 0) {
3523 speed = atav->track()->speed();
3527 boost::shared_ptr<Region> region = arv->region();
3528 boost::shared_ptr<Playlist> playlist (region->playlist());
3530 region->clear_changes ();
3534 next_region = playlist->find_next_region (region->first_frame(), Start, 1);
3540 region->trim_end((framepos_t) ( (next_region->first_frame() - 1) * speed));
3541 arv->region_changed (PropertyChange (ARDOUR::Properties::length));
3545 next_region = playlist->find_next_region (region->first_frame(), Start, 0);
3551 region->trim_front((framepos_t) ((next_region->last_frame() + 1) * speed));
3553 arv->region_changed (ARDOUR::bounds_change);
3556 _session->add_command(new StatefulDiffCommand (region));
3559 commit_reversible_command ();
3563 Editor::unfreeze_route ()
3565 if (clicked_routeview == 0 || !clicked_routeview->is_track()) {
3569 clicked_routeview->track()->unfreeze ();
3573 Editor::_freeze_thread (void* arg)
3575 return static_cast<Editor*>(arg)->freeze_thread ();
3579 Editor::freeze_thread ()
3581 /* create event pool because we may need to talk to the session */
3582 SessionEvent::create_per_thread_pool ("freeze events", 64);
3583 /* create per-thread buffers for process() tree to use */
3584 current_interthread_info->process_thread.get_buffers ();
3585 clicked_routeview->audio_track()->freeze_me (*current_interthread_info);
3586 current_interthread_info->done = true;
3587 current_interthread_info->process_thread.drop_buffers();
3592 Editor::freeze_route ()
3598 /* stop transport before we start. this is important */
3600 _session->request_transport_speed (0.0);
3602 /* wait for just a little while, because the above call is asynchronous */
3604 Glib::usleep (250000);
3606 if (clicked_routeview == 0 || !clicked_routeview->is_audio_track()) {
3610 if (!clicked_routeview->track()->bounceable (clicked_routeview->track()->main_outs(), true)) {
3612 _("This track/bus cannot be frozen because the signal adds or loses channels before reaching the outputs.\n"
3613 "This is typically caused by plugins that generate stereo output from mono input or vice versa.")
3615 d.set_title (_("Cannot freeze"));
3620 if (clicked_routeview->track()->has_external_redirects()) {
3621 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"
3622 "Freezing will only process the signal as far as the first send/insert/return."),
3623 clicked_routeview->track()->name()), true, MESSAGE_INFO, BUTTONS_NONE, true);
3625 d.add_button (_("Freeze anyway"), Gtk::RESPONSE_OK);
3626 d.add_button (_("Don't freeze"), Gtk::RESPONSE_CANCEL);
3627 d.set_title (_("Freeze Limits"));
3629 int response = d.run ();
3632 case Gtk::RESPONSE_CANCEL:
3639 InterThreadInfo itt;
3640 current_interthread_info = &itt;
3642 InterthreadProgressWindow ipw (current_interthread_info, _("Freeze"), _("Cancel Freeze"));
3644 pthread_create_and_store (X_("freezer"), &itt.thread, _freeze_thread, this);
3646 set_canvas_cursor (_cursors->wait);
3648 while (!itt.done && !itt.cancel) {
3649 gtk_main_iteration ();
3652 current_interthread_info = 0;
3653 set_canvas_cursor (current_canvas_cursor);
3657 Editor::bounce_range_selection (bool replace, bool enable_processing)
3659 if (selection->time.empty()) {
3663 TrackSelection views = selection->tracks;
3665 for (TrackViewList::iterator i = views.begin(); i != views.end(); ++i) {
3667 if (enable_processing) {
3669 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*i);
3671 if (rtv && rtv->track() && replace && enable_processing && !rtv->track()->bounceable (rtv->track()->main_outs(), false)) {
3673 _("You can't perform this operation because the processing of the signal "
3674 "will cause one or more of the tracks to end up with a region with more channels than this track has inputs.\n\n"
3675 "You can do this without processing, which is a different operation.")
3677 d.set_title (_("Cannot bounce"));
3684 framepos_t start = selection->time[clicked_selection].start;
3685 framepos_t end = selection->time[clicked_selection].end;
3686 framepos_t cnt = end - start + 1;
3688 begin_reversible_command (_("bounce range"));
3690 for (TrackViewList::iterator i = views.begin(); i != views.end(); ++i) {
3692 RouteTimeAxisView* rtv;
3694 if ((rtv = dynamic_cast<RouteTimeAxisView*> (*i)) == 0) {
3698 boost::shared_ptr<Playlist> playlist;
3700 if ((playlist = rtv->playlist()) == 0) {
3704 InterThreadInfo itt;
3706 playlist->clear_changes ();
3707 playlist->clear_owned_changes ();
3709 boost::shared_ptr<Region> r;
3711 if (enable_processing) {
3712 r = rtv->track()->bounce_range (start, start+cnt, itt, rtv->track()->main_outs(), false);
3714 r = rtv->track()->bounce_range (start, start+cnt, itt, boost::shared_ptr<Processor>(), false);
3722 list<AudioRange> ranges;
3723 ranges.push_back (AudioRange (start, start+cnt, 0));
3724 playlist->cut (ranges); // discard result
3725 playlist->add_region (r, start);
3728 vector<Command*> cmds;
3729 playlist->rdiff (cmds);
3730 _session->add_commands (cmds);
3732 _session->add_command (new StatefulDiffCommand (playlist));
3735 commit_reversible_command ();
3738 /** Delete selected regions, automation points or a time range */
3745 /** Cut selected regions, automation points or a time range */
3752 /** Copy selected regions, automation points or a time range */
3760 /** @return true if a Cut, Copy or Clear is possible */
3762 Editor::can_cut_copy () const
3764 switch (effective_mouse_mode()) {
3767 if (!selection->regions.empty() || !selection->points.empty()) {
3773 if (!selection->time.empty()) {
3786 /** Cut, copy or clear selected regions, automation points or a time range.
3787 * @param op Operation (Cut, Copy or Clear)
3790 Editor::cut_copy (CutCopyOp op)
3792 /* only cancel selection if cut/copy is successful.*/
3798 opname = _("delete");
3807 opname = _("clear");
3811 /* if we're deleting something, and the mouse is still pressed,
3812 the thing we started a drag for will be gone when we release
3813 the mouse button(s). avoid this. see part 2 at the end of
3817 if (op == Delete || op == Cut || op == Clear) {
3818 if (_drags->active ()) {
3823 if ( op != Clear ) //"Delete" doesn't change copy/paste buf
3824 cut_buffer->clear ();
3826 if (entered_marker) {
3828 /* cut/delete op while pointing at a marker */
3831 Location* loc = find_location_from_marker (entered_marker, ignored);
3833 if (_session && loc) {
3834 Glib::signal_idle().connect (sigc::bind (sigc::mem_fun(*this, &Editor::really_remove_marker), loc));
3841 if (internal_editing()) {
3843 switch (effective_mouse_mode()) {
3846 begin_reversible_command (opname + ' ' + X_("MIDI"));
3848 commit_reversible_command ();
3857 bool did_edit = false;
3859 switch (effective_mouse_mode()) {
3861 if (!selection->points.empty()) {
3862 begin_reversible_command (opname + _(" points"));
3864 cut_copy_points (op);
3865 if (op == Cut || op == Delete) {
3866 selection->clear_points ();
3873 if (!selection->regions.empty() || !selection->points.empty()) {
3877 if (selection->regions.empty()) {
3878 thing_name = _("points");
3879 } else if (selection->points.empty()) {
3880 thing_name = _("regions");
3882 thing_name = _("objects");
3885 begin_reversible_command (opname + ' ' + thing_name);
3888 if (!selection->regions.empty()) {
3889 cut_copy_regions (op, selection->regions);
3891 if (op == Cut || op == Delete) {
3892 selection->clear_regions ();
3896 if (!selection->points.empty()) {
3897 cut_copy_points (op);
3899 if (op == Cut || op == Delete) {
3900 selection->clear_points ();
3907 if (selection->time.empty()) {
3908 framepos_t start, end;
3909 /* no time selection, see if we can get an edit range
3912 if (get_edit_op_range (start, end)) {
3913 selection->set (start, end);
3916 if (!selection->time.empty()) {
3917 begin_reversible_command (opname + _(" range"));
3920 cut_copy_ranges (op);
3922 if (op == Cut || op == Delete) {
3923 selection->clear_time ();
3933 commit_reversible_command ();
3936 if (op == Delete || op == Cut || op == Clear) {
3941 struct AutomationRecord {
3942 AutomationRecord () : state (0) {}
3943 AutomationRecord (XMLNode* s) : state (s) {}
3945 XMLNode* state; ///< state before any operation
3946 boost::shared_ptr<Evoral::ControlList> copy; ///< copied events for the cut buffer
3949 /** Cut, copy or clear selected automation points.
3950 * @param op Operation (Cut, Copy or Clear)
3953 Editor::cut_copy_points (CutCopyOp op)
3955 if (selection->points.empty ()) {
3959 /* XXX: not ideal, as there may be more than one track involved in the point selection */
3960 _last_cut_copy_source_track = &selection->points.front()->line().trackview;
3962 /* Keep a record of the AutomationLists that we end up using in this operation */
3963 typedef std::map<boost::shared_ptr<AutomationList>, AutomationRecord> Lists;
3966 /* Go through all selected points, making an AutomationRecord for each distinct AutomationList */
3967 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
3968 boost::shared_ptr<AutomationList> al = (*i)->line().the_list();
3969 if (lists.find (al) == lists.end ()) {
3970 /* We haven't seen this list yet, so make a record for it. This includes
3971 taking a copy of its current state, in case this is needed for undo later.
3973 lists[al] = AutomationRecord (&al->get_state ());
3977 if (op == Cut || op == Copy) {
3978 /* This operation will involve putting things in the cut buffer, so create an empty
3979 ControlList for each of our source lists to put the cut buffer data in.
3981 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
3982 i->second.copy = i->first->create (i->first->parameter ());
3985 /* Add all selected points to the relevant copy ControlLists */
3986 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
3987 boost::shared_ptr<AutomationList> al = (*i)->line().the_list();
3988 AutomationList::const_iterator j = (*i)->model ();
3989 lists[al].copy->add ((*j)->when, (*j)->value);
3992 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
3993 /* Correct this copy list so that it starts at time 0 */
3994 double const start = i->second.copy->front()->when;
3995 for (AutomationList::iterator j = i->second.copy->begin(); j != i->second.copy->end(); ++j) {
3996 (*j)->when -= start;
3999 /* And add it to the cut buffer */
4000 cut_buffer->add (i->second.copy);
4004 if (op == Delete || op == Cut) {
4005 /* This operation needs to remove things from the main AutomationList, so do that now */
4007 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
4008 i->first->freeze ();
4011 /* Remove each selected point from its AutomationList */
4012 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
4013 boost::shared_ptr<AutomationList> al = (*i)->line().the_list();
4014 al->erase ((*i)->model ());
4017 /* Thaw the lists and add undo records for them */
4018 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
4019 boost::shared_ptr<AutomationList> al = i->first;
4021 _session->add_command (new MementoCommand<AutomationList> (*al.get(), i->second.state, &(al->get_state ())));
4026 /** Cut, copy or clear selected automation points.
4027 * @param op Operation (Cut, Copy or Clear)
4030 Editor::cut_copy_midi (CutCopyOp op)
4032 for (MidiRegionSelection::iterator i = selection->midi_regions.begin(); i != selection->midi_regions.end(); ++i) {
4033 MidiRegionView* mrv = *i;
4034 mrv->cut_copy_clear (op);
4040 struct lt_playlist {
4041 bool operator () (const PlaylistState& a, const PlaylistState& b) {
4042 return a.playlist < b.playlist;
4046 struct PlaylistMapping {
4048 boost::shared_ptr<Playlist> pl;
4050 PlaylistMapping (TimeAxisView* tvp) : tv (tvp) {}
4053 /** Remove `clicked_regionview' */
4055 Editor::remove_clicked_region ()
4057 if (clicked_routeview == 0 || clicked_regionview == 0) {
4061 boost::shared_ptr<Playlist> playlist = clicked_routeview->playlist();
4063 playlist->clear_changes ();
4064 playlist->clear_owned_changes ();
4065 playlist->remove_region (clicked_regionview->region());
4066 if (Config->get_edit_mode() == Ripple)
4067 playlist->ripple (clicked_regionview->region()->position(), -clicked_regionview->region()->length(), boost::shared_ptr<Region>());
4069 /* We might have removed regions, which alters other regions' layering_index,
4070 so we need to do a recursive diff here.
4072 vector<Command*> cmds;
4073 playlist->rdiff (cmds);
4074 _session->add_commands (cmds);
4076 _session->add_command(new StatefulDiffCommand (playlist));
4077 commit_reversible_command ();
4081 /** Remove the selected regions */
4083 Editor::remove_selected_regions ()
4085 RegionSelection rs = get_regions_from_selection_and_entered ();
4087 if (!_session || rs.empty()) {
4091 begin_reversible_command (_("remove region"));
4093 list<boost::shared_ptr<Region> > regions_to_remove;
4095 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
4096 // we can't just remove the region(s) in this loop because
4097 // this removes them from the RegionSelection, and they thus
4098 // disappear from underneath the iterator, and the ++i above
4099 // SEGVs in a puzzling fashion.
4101 // so, first iterate over the regions to be removed from rs and
4102 // add them to the regions_to_remove list, and then
4103 // iterate over the list to actually remove them.
4105 regions_to_remove.push_back ((*i)->region());
4108 vector<boost::shared_ptr<Playlist> > playlists;
4110 for (list<boost::shared_ptr<Region> >::iterator rl = regions_to_remove.begin(); rl != regions_to_remove.end(); ++rl) {
4112 boost::shared_ptr<Playlist> playlist = (*rl)->playlist();
4115 // is this check necessary?
4119 /* get_regions_from_selection_and_entered() guarantees that
4120 the playlists involved are unique, so there is no need
4124 playlists.push_back (playlist);
4126 playlist->clear_changes ();
4127 playlist->clear_owned_changes ();
4128 playlist->freeze ();
4129 playlist->remove_region (*rl);
4130 if (Config->get_edit_mode() == Ripple)
4131 playlist->ripple ((*rl)->position(), -(*rl)->length(), boost::shared_ptr<Region>());
4135 vector<boost::shared_ptr<Playlist> >::iterator pl;
4137 for (pl = playlists.begin(); pl != playlists.end(); ++pl) {
4140 /* We might have removed regions, which alters other regions' layering_index,
4141 so we need to do a recursive diff here.
4143 vector<Command*> cmds;
4144 (*pl)->rdiff (cmds);
4145 _session->add_commands (cmds);
4147 _session->add_command(new StatefulDiffCommand (*pl));
4150 commit_reversible_command ();
4153 /** Cut, copy or clear selected regions.
4154 * @param op Operation (Cut, Copy or Clear)
4157 Editor::cut_copy_regions (CutCopyOp op, RegionSelection& rs)
4159 /* we can't use a std::map here because the ordering is important, and we can't trivially sort
4160 a map when we want ordered access to both elements. i think.
4163 vector<PlaylistMapping> pmap;
4165 framepos_t first_position = max_framepos;
4167 typedef set<boost::shared_ptr<Playlist> > FreezeList;
4168 FreezeList freezelist;
4170 /* get ordering correct before we cut/copy */
4172 rs.sort_by_position_and_track ();
4174 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
4176 first_position = min ((framepos_t) (*x)->region()->position(), first_position);
4178 if (op == Cut || op == Clear || op == Delete) {
4179 boost::shared_ptr<Playlist> pl = (*x)->region()->playlist();
4182 FreezeList::iterator fl;
4184 // only take state if this is a new playlist.
4185 for (fl = freezelist.begin(); fl != freezelist.end(); ++fl) {
4191 if (fl == freezelist.end()) {
4192 pl->clear_changes();
4193 pl->clear_owned_changes ();
4195 freezelist.insert (pl);
4200 TimeAxisView* tv = &(*x)->get_time_axis_view();
4201 vector<PlaylistMapping>::iterator z;
4203 for (z = pmap.begin(); z != pmap.end(); ++z) {
4204 if ((*z).tv == tv) {
4209 if (z == pmap.end()) {
4210 pmap.push_back (PlaylistMapping (tv));
4214 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ) {
4216 boost::shared_ptr<Playlist> pl = (*x)->region()->playlist();
4219 /* region not yet associated with a playlist (e.g. unfinished
4226 TimeAxisView& tv = (*x)->get_time_axis_view();
4227 boost::shared_ptr<Playlist> npl;
4228 RegionSelection::iterator tmp;
4235 vector<PlaylistMapping>::iterator z;
4237 for (z = pmap.begin(); z != pmap.end(); ++z) {
4238 if ((*z).tv == &tv) {
4243 assert (z != pmap.end());
4246 npl = PlaylistFactory::create (pl->data_type(), *_session, "cutlist", true);
4254 boost::shared_ptr<Region> r = (*x)->region();
4255 boost::shared_ptr<Region> _xx;
4261 pl->remove_region (r);
4262 if (Config->get_edit_mode() == Ripple)
4263 pl->ripple (r->position(), -r->length(), boost::shared_ptr<Region>());
4267 _xx = RegionFactory::create (r);
4268 npl->add_region (_xx, r->position() - first_position);
4269 pl->remove_region (r);
4270 if (Config->get_edit_mode() == Ripple)
4271 pl->ripple (r->position(), -r->length(), boost::shared_ptr<Region>());
4275 /* copy region before adding, so we're not putting same object into two different playlists */
4276 npl->add_region (RegionFactory::create (r), r->position() - first_position);
4280 pl->remove_region (r);
4281 if (Config->get_edit_mode() == Ripple)
4282 pl->ripple (r->position(), -r->length(), boost::shared_ptr<Region>());
4291 list<boost::shared_ptr<Playlist> > foo;
4293 /* the pmap is in the same order as the tracks in which selected regions occured */
4295 for (vector<PlaylistMapping>::iterator i = pmap.begin(); i != pmap.end(); ++i) {
4298 foo.push_back ((*i).pl);
4303 cut_buffer->set (foo);
4307 _last_cut_copy_source_track = 0;
4309 _last_cut_copy_source_track = pmap.front().tv;
4313 for (FreezeList::iterator pl = freezelist.begin(); pl != freezelist.end(); ++pl) {
4316 /* We might have removed regions, which alters other regions' layering_index,
4317 so we need to do a recursive diff here.
4319 vector<Command*> cmds;
4320 (*pl)->rdiff (cmds);
4321 _session->add_commands (cmds);
4323 _session->add_command (new StatefulDiffCommand (*pl));
4328 Editor::cut_copy_ranges (CutCopyOp op)
4330 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4332 /* Sort the track selection now, so that it if is used, the playlists
4333 selected by the calls below to cut_copy_clear are in the order that
4334 their tracks appear in the editor. This makes things like paste
4335 of ranges work properly.
4338 sort_track_selection (ts);
4341 if (!entered_track) {
4344 ts.push_back (entered_track);
4347 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4348 (*i)->cut_copy_clear (*selection, op);
4353 Editor::paste (float times, bool from_context)
4355 DEBUG_TRACE (DEBUG::CutNPaste, "paste to preferred edit pos\n");
4357 paste_internal (get_preferred_edit_position (false, from_context), times);
4361 Editor::mouse_paste ()
4366 if (!mouse_frame (where, ignored)) {
4371 paste_internal (where, 1);
4375 Editor::paste_internal (framepos_t position, float times)
4377 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("apparent paste position is %1\n", position));
4379 if (internal_editing()) {
4380 if (cut_buffer->midi_notes.empty()) {
4384 if (cut_buffer->empty()) {
4389 if (position == max_framepos) {
4390 position = get_preferred_edit_position();
4391 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("preferred edit position is %1\n", position));
4395 TrackViewList::iterator i;
4398 /* get everything in the correct order */
4400 if (_edit_point == Editing::EditAtMouse && entered_track) {
4401 /* With the mouse edit point, paste onto the track under the mouse */
4402 ts.push_back (entered_track);
4403 } else if (!selection->tracks.empty()) {
4404 /* Otherwise, if there are some selected tracks, paste to them */
4405 ts = selection->tracks.filter_to_unique_playlists ();
4406 sort_track_selection (ts);
4407 } else if (_last_cut_copy_source_track) {
4408 /* Otherwise paste to the track that the cut/copy came from;
4409 see discussion in mantis #3333.
4411 ts.push_back (_last_cut_copy_source_track);
4414 if (internal_editing ()) {
4416 /* undo/redo is handled by individual tracks/regions */
4418 for (nth = 0, i = ts.begin(); i != ts.end(); ++i, ++nth) {
4421 RegionSelection::iterator r;
4422 MidiNoteSelection::iterator cb;
4424 get_regions_at (rs, position, ts);
4426 for (cb = cut_buffer->midi_notes.begin(), r = rs.begin();
4427 cb != cut_buffer->midi_notes.end() && r != rs.end(); ++r) {
4428 MidiRegionView* mrv = dynamic_cast<MidiRegionView*> (*r);
4430 mrv->paste (position, times, **cb);
4438 /* we do redo (do you do voodoo?) */
4440 begin_reversible_command (Operations::paste);
4442 for (nth = 0, i = ts.begin(); i != ts.end(); ++i, ++nth) {
4443 (*i)->paste (position, times, *cut_buffer, nth);
4446 commit_reversible_command ();
4451 Editor::duplicate_some_regions (RegionSelection& regions, float times)
4453 boost::shared_ptr<Playlist> playlist;
4454 RegionSelection sel = regions; // clear (below) may clear the argument list if its the current region selection
4455 RegionSelection foo;
4457 framepos_t const start_frame = regions.start ();
4458 framepos_t const end_frame = regions.end_frame ();
4460 begin_reversible_command (Operations::duplicate_region);
4462 selection->clear_regions ();
4464 for (RegionSelection::iterator i = sel.begin(); i != sel.end(); ++i) {
4466 boost::shared_ptr<Region> r ((*i)->region());
4468 TimeAxisView& tv = (*i)->get_time_axis_view();
4469 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (&tv);
4470 latest_regionviews.clear ();
4471 sigc::connection c = rtv->view()->RegionViewAdded.connect (sigc::mem_fun(*this, &Editor::collect_new_region_view));
4473 playlist = (*i)->region()->playlist();
4474 playlist->clear_changes ();
4475 playlist->duplicate (r, end_frame + (r->first_frame() - start_frame), times);
4476 _session->add_command(new StatefulDiffCommand (playlist));
4480 foo.insert (foo.end(), latest_regionviews.begin(), latest_regionviews.end());
4483 commit_reversible_command ();
4486 selection->set (foo);
4491 Editor::duplicate_selection (float times)
4493 if (selection->time.empty() || selection->tracks.empty()) {
4497 boost::shared_ptr<Playlist> playlist;
4498 vector<boost::shared_ptr<Region> > new_regions;
4499 vector<boost::shared_ptr<Region> >::iterator ri;
4501 create_region_from_selection (new_regions);
4503 if (new_regions.empty()) {
4507 begin_reversible_command (_("duplicate selection"));
4509 ri = new_regions.begin();
4511 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4513 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4514 if ((playlist = (*i)->playlist()) == 0) {
4517 playlist->clear_changes ();
4518 playlist->duplicate (*ri, selection->time[clicked_selection].end, times);
4519 _session->add_command (new StatefulDiffCommand (playlist));
4522 if (ri == new_regions.end()) {
4527 commit_reversible_command ();
4530 /** Reset all selected points to the relevant default value */
4532 Editor::reset_point_selection ()
4534 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
4535 ARDOUR::AutomationList::iterator j = (*i)->model ();
4536 (*j)->value = (*i)->line().the_list()->default_value ();
4541 Editor::center_playhead ()
4543 float const page = _visible_canvas_width * samples_per_pixel;
4544 center_screen_internal (playhead_cursor->current_frame (), page);
4548 Editor::center_edit_point ()
4550 float const page = _visible_canvas_width * samples_per_pixel;
4551 center_screen_internal (get_preferred_edit_position(), page);
4554 /** Caller must begin and commit a reversible command */
4556 Editor::clear_playlist (boost::shared_ptr<Playlist> playlist)
4558 playlist->clear_changes ();
4560 _session->add_command (new StatefulDiffCommand (playlist));
4564 Editor::nudge_track (bool use_edit, bool forwards)
4566 boost::shared_ptr<Playlist> playlist;
4567 framepos_t distance;
4568 framepos_t next_distance;
4572 start = get_preferred_edit_position();
4577 if ((distance = get_nudge_distance (start, next_distance)) == 0) {
4581 if (selection->tracks.empty()) {
4585 begin_reversible_command (_("nudge track"));
4587 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4589 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4591 if ((playlist = (*i)->playlist()) == 0) {
4595 playlist->clear_changes ();
4596 playlist->clear_owned_changes ();
4598 playlist->nudge_after (start, distance, forwards);
4600 vector<Command*> cmds;
4602 playlist->rdiff (cmds);
4603 _session->add_commands (cmds);
4605 _session->add_command (new StatefulDiffCommand (playlist));
4608 commit_reversible_command ();
4612 Editor::remove_last_capture ()
4614 vector<string> choices;
4621 if (Config->get_verify_remove_last_capture()) {
4622 prompt = _("Do you really want to destroy the last capture?"
4623 "\n(This is destructive and cannot be undone)");
4625 choices.push_back (_("No, do nothing."));
4626 choices.push_back (_("Yes, destroy it."));
4628 Gtkmm2ext::Choice prompter (_("Destroy last capture"), prompt, choices);
4630 if (prompter.run () == 1) {
4631 _session->remove_last_capture ();
4632 _regions->redisplay ();
4636 _session->remove_last_capture();
4637 _regions->redisplay ();
4642 Editor::normalize_region ()
4648 RegionSelection rs = get_regions_from_selection_and_entered ();
4654 NormalizeDialog dialog (rs.size() > 1);
4656 if (dialog.run () == RESPONSE_CANCEL) {
4660 set_canvas_cursor (_cursors->wait);
4663 /* XXX: should really only count audio regions here */
4664 int const regions = rs.size ();
4666 /* Make a list of the selected audio regions' maximum amplitudes, and also
4667 obtain the maximum amplitude of them all.
4669 list<double> max_amps;
4671 for (RegionSelection::const_iterator i = rs.begin(); i != rs.end(); ++i) {
4672 AudioRegionView const * arv = dynamic_cast<AudioRegionView const *> (*i);
4674 dialog.descend (1.0 / regions);
4675 double const a = arv->audio_region()->maximum_amplitude (&dialog);
4678 /* the user cancelled the operation */
4679 set_canvas_cursor (current_canvas_cursor);
4683 max_amps.push_back (a);
4684 max_amp = max (max_amp, a);
4689 begin_reversible_command (_("normalize"));
4691 list<double>::const_iterator a = max_amps.begin ();
4693 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
4694 AudioRegionView* const arv = dynamic_cast<AudioRegionView*> (*r);
4699 arv->region()->clear_changes ();
4701 double const amp = dialog.normalize_individually() ? *a : max_amp;
4703 arv->audio_region()->normalize (amp, dialog.target ());
4704 _session->add_command (new StatefulDiffCommand (arv->region()));
4709 commit_reversible_command ();
4710 set_canvas_cursor (current_canvas_cursor);
4715 Editor::reset_region_scale_amplitude ()
4721 RegionSelection rs = get_regions_from_selection_and_entered ();
4727 begin_reversible_command ("reset gain");
4729 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
4730 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
4733 arv->region()->clear_changes ();
4734 arv->audio_region()->set_scale_amplitude (1.0f);
4735 _session->add_command (new StatefulDiffCommand (arv->region()));
4738 commit_reversible_command ();
4742 Editor::adjust_region_gain (bool up)
4744 RegionSelection rs = get_regions_from_selection_and_entered ();
4746 if (!_session || rs.empty()) {
4750 begin_reversible_command ("adjust region gain");
4752 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
4753 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
4758 arv->region()->clear_changes ();
4760 double dB = accurate_coefficient_to_dB (arv->audio_region()->scale_amplitude ());
4768 arv->audio_region()->set_scale_amplitude (dB_to_coefficient (dB));
4769 _session->add_command (new StatefulDiffCommand (arv->region()));
4772 commit_reversible_command ();
4777 Editor::reverse_region ()
4783 Reverse rev (*_session);
4784 apply_filter (rev, _("reverse regions"));
4788 Editor::strip_region_silence ()
4794 RegionSelection rs = get_regions_from_selection_and_entered ();
4800 std::list<RegionView*> audio_only;
4802 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
4803 AudioRegionView* const arv = dynamic_cast<AudioRegionView*> (*i);
4805 audio_only.push_back (arv);
4809 StripSilenceDialog d (_session, audio_only);
4810 int const r = d.run ();
4814 if (r == Gtk::RESPONSE_OK) {
4815 ARDOUR::AudioIntervalMap silences;
4816 d.silences (silences);
4817 StripSilence s (*_session, silences, d.fade_length());
4818 apply_filter (s, _("strip silence"), &d);
4823 Editor::apply_midi_note_edit_op_to_region (MidiOperator& op, MidiRegionView& mrv)
4825 Evoral::Sequence<Evoral::MusicalTime>::Notes selected;
4826 mrv.selection_as_notelist (selected, true);
4828 vector<Evoral::Sequence<Evoral::MusicalTime>::Notes> v;
4829 v.push_back (selected);
4831 framepos_t pos_frames = mrv.midi_region()->position() - mrv.midi_region()->start();
4832 double pos_beats = _session->tempo_map().framewalk_to_beats(0, pos_frames);
4834 return op (mrv.midi_region()->model(), pos_beats, v);
4838 Editor::apply_midi_note_edit_op (MidiOperator& op)
4842 RegionSelection rs = get_regions_from_selection_and_entered ();
4848 begin_reversible_command (op.name ());
4850 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
4851 RegionSelection::iterator tmp = r;
4854 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*r);
4857 cmd = apply_midi_note_edit_op_to_region (op, *mrv);
4860 _session->add_command (cmd);
4867 commit_reversible_command ();
4871 Editor::fork_region ()
4873 RegionSelection rs = get_regions_from_selection_and_entered ();
4879 begin_reversible_command (_("Fork Region(s)"));
4881 set_canvas_cursor (_cursors->wait);
4884 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
4885 RegionSelection::iterator tmp = r;
4888 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*>(*r);
4892 boost::shared_ptr<Playlist> playlist = mrv->region()->playlist();
4893 boost::shared_ptr<MidiSource> new_source = _session->create_midi_source_by_stealing_name (mrv->midi_view()->track());
4894 boost::shared_ptr<MidiRegion> newregion = mrv->midi_region()->clone (new_source);
4896 playlist->clear_changes ();
4897 playlist->replace_region (mrv->region(), newregion, mrv->region()->position());
4898 _session->add_command(new StatefulDiffCommand (playlist));
4900 error << string_compose (_("Could not unlink %1"), mrv->region()->name()) << endmsg;
4907 commit_reversible_command ();
4909 set_canvas_cursor (current_canvas_cursor);
4913 Editor::quantize_region ()
4915 int selected_midi_region_cnt = 0;
4921 RegionSelection rs = get_regions_from_selection_and_entered ();
4927 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
4928 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*r);
4930 selected_midi_region_cnt++;
4934 if (selected_midi_region_cnt == 0) {
4938 QuantizeDialog* qd = new QuantizeDialog (*this);
4941 const int r = qd->run ();
4944 if (r == Gtk::RESPONSE_OK) {
4945 Quantize quant (*_session, qd->snap_start(), qd->snap_end(),
4946 qd->start_grid_size(), qd->end_grid_size(),
4947 qd->strength(), qd->swing(), qd->threshold());
4949 apply_midi_note_edit_op (quant);
4954 Editor::insert_patch_change (bool from_context)
4956 RegionSelection rs = get_regions_from_selection_and_entered ();
4962 const framepos_t p = get_preferred_edit_position (false, from_context);
4964 /* XXX: bit of a hack; use the MIDNAM from the first selected region;
4965 there may be more than one, but the PatchChangeDialog can only offer
4966 one set of patch menus.
4968 MidiRegionView* first = dynamic_cast<MidiRegionView*> (rs.front ());
4970 Evoral::PatchChange<Evoral::MusicalTime> empty (0, 0, 0, 0);
4971 PatchChangeDialog d (0, _session, empty, first->instrument_info(), Gtk::Stock::ADD);
4973 if (d.run() == RESPONSE_CANCEL) {
4977 for (RegionSelection::iterator i = rs.begin (); i != rs.end(); ++i) {
4978 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*i);
4980 if (p >= mrv->region()->first_frame() && p <= mrv->region()->last_frame()) {
4981 mrv->add_patch_change (p - mrv->region()->position(), d.patch ());
4988 Editor::apply_filter (Filter& filter, string command, ProgressReporter* progress)
4990 RegionSelection rs = get_regions_from_selection_and_entered ();
4996 begin_reversible_command (command);
4998 set_canvas_cursor (_cursors->wait);
5002 int const N = rs.size ();
5004 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
5005 RegionSelection::iterator tmp = r;
5008 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
5010 boost::shared_ptr<Playlist> playlist = arv->region()->playlist();
5013 progress->descend (1.0 / N);
5016 if (arv->audio_region()->apply (filter, progress) == 0) {
5018 playlist->clear_changes ();
5019 playlist->clear_owned_changes ();
5021 if (filter.results.empty ()) {
5023 /* no regions returned; remove the old one */
5024 playlist->remove_region (arv->region ());
5028 std::vector<boost::shared_ptr<Region> >::iterator res = filter.results.begin ();
5030 /* first region replaces the old one */
5031 playlist->replace_region (arv->region(), *res, (*res)->position());
5035 while (res != filter.results.end()) {
5036 playlist->add_region (*res, (*res)->position());
5042 /* We might have removed regions, which alters other regions' layering_index,
5043 so we need to do a recursive diff here.
5045 vector<Command*> cmds;
5046 playlist->rdiff (cmds);
5047 _session->add_commands (cmds);
5049 _session->add_command(new StatefulDiffCommand (playlist));
5055 progress->ascend ();
5063 commit_reversible_command ();
5066 set_canvas_cursor (current_canvas_cursor);
5070 Editor::external_edit_region ()
5076 Editor::reset_region_gain_envelopes ()
5078 RegionSelection rs = get_regions_from_selection_and_entered ();
5080 if (!_session || rs.empty()) {
5084 _session->begin_reversible_command (_("reset region gain"));
5086 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5087 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
5089 boost::shared_ptr<AutomationList> alist (arv->audio_region()->envelope());
5090 XMLNode& before (alist->get_state());
5092 arv->audio_region()->set_default_envelope ();
5093 _session->add_command (new MementoCommand<AutomationList>(*arv->audio_region()->envelope().get(), &before, &alist->get_state()));
5097 _session->commit_reversible_command ();
5101 Editor::set_region_gain_visibility (RegionView* rv)
5103 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (rv);
5105 arv->update_envelope_visibility();
5110 Editor::set_gain_envelope_visibility ()
5116 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5117 AudioTimeAxisView* v = dynamic_cast<AudioTimeAxisView*>(*i);
5119 v->audio_view()->foreach_regionview (sigc::mem_fun (this, &Editor::set_region_gain_visibility));
5125 Editor::toggle_gain_envelope_active ()
5127 if (_ignore_region_action) {
5131 RegionSelection rs = get_regions_from_selection_and_entered ();
5133 if (!_session || rs.empty()) {
5137 _session->begin_reversible_command (_("region gain envelope active"));
5139 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5140 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
5142 arv->region()->clear_changes ();
5143 arv->audio_region()->set_envelope_active (!arv->audio_region()->envelope_active());
5144 _session->add_command (new StatefulDiffCommand (arv->region()));
5148 _session->commit_reversible_command ();
5152 Editor::toggle_region_lock ()
5154 if (_ignore_region_action) {
5158 RegionSelection rs = get_regions_from_selection_and_entered ();
5160 if (!_session || rs.empty()) {
5164 _session->begin_reversible_command (_("toggle region lock"));
5166 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5167 (*i)->region()->clear_changes ();
5168 (*i)->region()->set_locked (!(*i)->region()->locked());
5169 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5172 _session->commit_reversible_command ();
5176 Editor::toggle_region_video_lock ()
5178 if (_ignore_region_action) {
5182 RegionSelection rs = get_regions_from_selection_and_entered ();
5184 if (!_session || rs.empty()) {
5188 _session->begin_reversible_command (_("Toggle Video Lock"));
5190 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5191 (*i)->region()->clear_changes ();
5192 (*i)->region()->set_video_locked (!(*i)->region()->video_locked());
5193 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5196 _session->commit_reversible_command ();
5200 Editor::toggle_region_lock_style ()
5202 if (_ignore_region_action) {
5206 RegionSelection rs = get_regions_from_selection_and_entered ();
5208 if (!_session || rs.empty()) {
5212 _session->begin_reversible_command (_("region lock style"));
5214 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5215 (*i)->region()->clear_changes ();
5216 PositionLockStyle const ns = (*i)->region()->position_lock_style() == AudioTime ? MusicTime : AudioTime;
5217 (*i)->region()->set_position_lock_style (ns);
5218 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5221 _session->commit_reversible_command ();
5225 Editor::toggle_opaque_region ()
5227 if (_ignore_region_action) {
5231 RegionSelection rs = get_regions_from_selection_and_entered ();
5233 if (!_session || rs.empty()) {
5237 _session->begin_reversible_command (_("change region opacity"));
5239 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5240 (*i)->region()->clear_changes ();
5241 (*i)->region()->set_opaque (!(*i)->region()->opaque());
5242 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5245 _session->commit_reversible_command ();
5249 Editor::toggle_record_enable ()
5251 bool new_state = false;
5253 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5254 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5257 if (!rtav->is_track())
5261 new_state = !rtav->track()->record_enabled();
5265 rtav->track()->set_record_enabled (new_state, this);
5270 Editor::toggle_solo ()
5272 bool new_state = false;
5274 boost::shared_ptr<RouteList> rl (new RouteList);
5276 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5277 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5284 new_state = !rtav->route()->soloed ();
5288 rl->push_back (rtav->route());
5291 _session->set_solo (rl, new_state, Session::rt_cleanup, true);
5295 Editor::toggle_mute ()
5297 bool new_state = false;
5299 boost::shared_ptr<RouteList> rl (new RouteList);
5301 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5302 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5309 new_state = !rtav->route()->muted();
5313 rl->push_back (rtav->route());
5316 _session->set_mute (rl, new_state, Session::rt_cleanup, true);
5320 Editor::toggle_solo_isolate ()
5325 Editor::set_fade_length (bool in)
5327 RegionSelection rs = get_regions_from_selection_and_entered ();
5333 /* we need a region to measure the offset from the start */
5335 RegionView* rv = rs.front ();
5337 framepos_t pos = get_preferred_edit_position();
5341 if (pos > rv->region()->last_frame() || pos < rv->region()->first_frame()) {
5342 /* edit point is outside the relevant region */
5347 if (pos <= rv->region()->position()) {
5351 len = pos - rv->region()->position();
5352 cmd = _("set fade in length");
5354 if (pos >= rv->region()->last_frame()) {
5358 len = rv->region()->last_frame() - pos;
5359 cmd = _("set fade out length");
5362 begin_reversible_command (cmd);
5364 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5365 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5371 boost::shared_ptr<AutomationList> alist;
5373 alist = tmp->audio_region()->fade_in();
5375 alist = tmp->audio_region()->fade_out();
5378 XMLNode &before = alist->get_state();
5381 tmp->audio_region()->set_fade_in_length (len);
5382 tmp->audio_region()->set_fade_in_active (true);
5384 tmp->audio_region()->set_fade_out_length (len);
5385 tmp->audio_region()->set_fade_out_active (true);
5388 XMLNode &after = alist->get_state();
5389 _session->add_command(new MementoCommand<AutomationList>(*alist, &before, &after));
5392 commit_reversible_command ();
5396 Editor::set_fade_in_shape (FadeShape shape)
5398 RegionSelection rs = get_regions_from_selection_and_entered ();
5404 begin_reversible_command (_("set fade in shape"));
5406 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5407 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5413 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_in();
5414 XMLNode &before = alist->get_state();
5416 tmp->audio_region()->set_fade_in_shape (shape);
5418 XMLNode &after = alist->get_state();
5419 _session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
5422 commit_reversible_command ();
5427 Editor::set_fade_out_shape (FadeShape shape)
5429 RegionSelection rs = get_regions_from_selection_and_entered ();
5435 begin_reversible_command (_("set fade out shape"));
5437 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5438 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5444 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_out();
5445 XMLNode &before = alist->get_state();
5447 tmp->audio_region()->set_fade_out_shape (shape);
5449 XMLNode &after = alist->get_state();
5450 _session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
5453 commit_reversible_command ();
5457 Editor::set_fade_in_active (bool yn)
5459 RegionSelection rs = get_regions_from_selection_and_entered ();
5465 begin_reversible_command (_("set fade in active"));
5467 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5468 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5475 boost::shared_ptr<AudioRegion> ar (tmp->audio_region());
5477 ar->clear_changes ();
5478 ar->set_fade_in_active (yn);
5479 _session->add_command (new StatefulDiffCommand (ar));
5482 commit_reversible_command ();
5486 Editor::set_fade_out_active (bool yn)
5488 RegionSelection rs = get_regions_from_selection_and_entered ();
5494 begin_reversible_command (_("set fade out active"));
5496 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5497 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5503 boost::shared_ptr<AudioRegion> ar (tmp->audio_region());
5505 ar->clear_changes ();
5506 ar->set_fade_out_active (yn);
5507 _session->add_command(new StatefulDiffCommand (ar));
5510 commit_reversible_command ();
5514 Editor::toggle_region_fades (int dir)
5516 if (_ignore_region_action) {
5520 boost::shared_ptr<AudioRegion> ar;
5523 RegionSelection rs = get_regions_from_selection_and_entered ();
5529 RegionSelection::iterator i;
5530 for (i = rs.begin(); i != rs.end(); ++i) {
5531 if ((ar = boost::dynamic_pointer_cast<AudioRegion>((*i)->region())) != 0) {
5533 yn = ar->fade_out_active ();
5535 yn = ar->fade_in_active ();
5541 if (i == rs.end()) {
5545 /* XXX should this undo-able? */
5547 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5548 if ((ar = boost::dynamic_pointer_cast<AudioRegion>((*i)->region())) == 0) {
5551 if (dir == 1 || dir == 0) {
5552 ar->set_fade_in_active (!yn);
5555 if (dir == -1 || dir == 0) {
5556 ar->set_fade_out_active (!yn);
5562 /** Update region fade visibility after its configuration has been changed */
5564 Editor::update_region_fade_visibility ()
5566 bool _fade_visibility = _session->config.get_show_region_fades ();
5568 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5569 AudioTimeAxisView* v = dynamic_cast<AudioTimeAxisView*>(*i);
5571 if (_fade_visibility) {
5572 v->audio_view()->show_all_fades ();
5574 v->audio_view()->hide_all_fades ();
5581 Editor::set_edit_point ()
5586 if (!mouse_frame (where, ignored)) {
5592 if (selection->markers.empty()) {
5594 mouse_add_new_marker (where);
5599 Location* loc = find_location_from_marker (selection->markers.front(), ignored);
5602 loc->move_to (where);
5608 Editor::set_playhead_cursor ()
5610 if (entered_marker) {
5611 _session->request_locate (entered_marker->position(), _session->transport_rolling());
5616 if (!mouse_frame (where, ignored)) {
5623 _session->request_locate (where, _session->transport_rolling());
5627 if ( Config->get_always_play_range() )
5628 cancel_time_selection();
5632 Editor::split_region ()
5634 if ( !selection->time.empty()) {
5635 separate_regions_between (selection->time);
5639 RegionSelection rs = get_regions_from_selection_and_edit_point ();
5641 framepos_t where = get_preferred_edit_position ();
5647 split_regions_at (where, rs);
5650 struct EditorOrderRouteSorter {
5651 bool operator() (boost::shared_ptr<Route> a, boost::shared_ptr<Route> b) {
5652 return a->order_key () < b->order_key ();
5657 Editor::select_next_route()
5659 if (selection->tracks.empty()) {
5660 selection->set (track_views.front());
5664 TimeAxisView* current = selection->tracks.front();
5668 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5669 if (*i == current) {
5671 if (i != track_views.end()) {
5674 current = (*(track_views.begin()));
5675 //selection->set (*(track_views.begin()));
5680 rui = dynamic_cast<RouteUI *>(current);
5681 } while ( current->hidden() || (rui != NULL && !rui->route()->active()));
5683 selection->set(current);
5685 ensure_track_visible(current);
5689 Editor::select_prev_route()
5691 if (selection->tracks.empty()) {
5692 selection->set (track_views.front());
5696 TimeAxisView* current = selection->tracks.front();
5700 for (TrackViewList::reverse_iterator i = track_views.rbegin(); i != track_views.rend(); ++i) {
5701 if (*i == current) {
5703 if (i != track_views.rend()) {
5706 current = *(track_views.rbegin());
5711 rui = dynamic_cast<RouteUI *>(current);
5712 } while ( current->hidden() || (rui != NULL && !rui->route()->active()));
5714 selection->set (current);
5716 ensure_track_visible(current);
5720 Editor::ensure_track_visible(TimeAxisView *track)
5722 if (track->hidden())
5725 double const current_view_min_y = vertical_adjustment.get_value();
5726 double const current_view_max_y = vertical_adjustment.get_value() + vertical_adjustment.get_page_size();
5728 double const track_min_y = track->y_position ();
5729 double const track_max_y = track->y_position () + track->effective_height ();
5731 if (track_min_y >= current_view_min_y &&
5732 track_max_y <= current_view_max_y) {
5738 if (track_min_y < current_view_min_y) {
5739 // Track is above the current view
5740 new_value = track_min_y;
5742 // Track is below the current view
5743 new_value = track->y_position () + track->effective_height() - vertical_adjustment.get_page_size();
5746 vertical_adjustment.set_value(new_value);
5750 Editor::set_loop_from_selection (bool play)
5752 if (_session == 0 || selection->time.empty()) {
5756 framepos_t start = selection->time[clicked_selection].start;
5757 framepos_t end = selection->time[clicked_selection].end;
5759 set_loop_range (start, end, _("set loop range from selection"));
5762 _session->request_play_loop (true);
5763 _session->request_locate (start, true);
5768 Editor::set_loop_from_edit_range (bool play)
5770 if (_session == 0) {
5777 if (!get_edit_op_range (start, end)) {
5781 set_loop_range (start, end, _("set loop range from edit range"));
5784 _session->request_play_loop (true);
5785 _session->request_locate (start, true);
5790 Editor::set_loop_from_region (bool play)
5792 framepos_t start = max_framepos;
5795 RegionSelection rs = get_regions_from_selection_and_entered ();
5801 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5802 if ((*i)->region()->position() < start) {
5803 start = (*i)->region()->position();
5805 if ((*i)->region()->last_frame() + 1 > end) {
5806 end = (*i)->region()->last_frame() + 1;
5810 set_loop_range (start, end, _("set loop range from region"));
5813 _session->request_play_loop (true);
5814 _session->request_locate (start, true);
5819 Editor::set_punch_from_selection ()
5821 if (_session == 0 || selection->time.empty()) {
5825 framepos_t start = selection->time[clicked_selection].start;
5826 framepos_t end = selection->time[clicked_selection].end;
5828 set_punch_range (start, end, _("set punch range from selection"));
5832 Editor::set_punch_from_edit_range ()
5834 if (_session == 0) {
5841 if (!get_edit_op_range (start, end)) {
5845 set_punch_range (start, end, _("set punch range from edit range"));
5849 Editor::set_punch_from_region ()
5851 framepos_t start = max_framepos;
5854 RegionSelection rs = get_regions_from_selection_and_entered ();
5860 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5861 if ((*i)->region()->position() < start) {
5862 start = (*i)->region()->position();
5864 if ((*i)->region()->last_frame() + 1 > end) {
5865 end = (*i)->region()->last_frame() + 1;
5869 set_punch_range (start, end, _("set punch range from region"));
5873 Editor::pitch_shift_region ()
5875 RegionSelection rs = get_regions_from_selection_and_entered ();
5877 RegionSelection audio_rs;
5878 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5879 if (dynamic_cast<AudioRegionView*> (*i)) {
5880 audio_rs.push_back (*i);
5884 if (audio_rs.empty()) {
5888 pitch_shift (audio_rs, 1.2);
5892 Editor::transpose_region ()
5894 RegionSelection rs = get_regions_from_selection_and_entered ();
5896 list<MidiRegionView*> midi_region_views;
5897 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5898 MidiRegionView* mrv = dynamic_cast<MidiRegionView*> (*i);
5900 midi_region_views.push_back (mrv);
5905 int const r = d.run ();
5906 if (r != RESPONSE_ACCEPT) {
5910 for (list<MidiRegionView*>::iterator i = midi_region_views.begin(); i != midi_region_views.end(); ++i) {
5911 (*i)->midi_region()->transpose (d.semitones ());
5916 Editor::set_tempo_from_region ()
5918 RegionSelection rs = get_regions_from_selection_and_entered ();
5920 if (!_session || rs.empty()) {
5924 RegionView* rv = rs.front();
5926 define_one_bar (rv->region()->position(), rv->region()->last_frame() + 1);
5930 Editor::use_range_as_bar ()
5932 framepos_t start, end;
5933 if (get_edit_op_range (start, end)) {
5934 define_one_bar (start, end);
5939 Editor::define_one_bar (framepos_t start, framepos_t end)
5941 framepos_t length = end - start;
5943 const Meter& m (_session->tempo_map().meter_at (start));
5945 /* length = 1 bar */
5947 /* now we want frames per beat.
5948 we have frames per bar, and beats per bar, so ...
5951 /* XXXX METER MATH */
5953 double frames_per_beat = length / m.divisions_per_bar();
5955 /* beats per minute = */
5957 double beats_per_minute = (_session->frame_rate() * 60.0) / frames_per_beat;
5959 /* now decide whether to:
5961 (a) set global tempo
5962 (b) add a new tempo marker
5966 const TempoSection& t (_session->tempo_map().tempo_section_at (start));
5968 bool do_global = false;
5970 if ((_session->tempo_map().n_tempos() == 1) && (_session->tempo_map().n_meters() == 1)) {
5972 /* only 1 tempo & 1 meter: ask if the user wants to set the tempo
5973 at the start, or create a new marker
5976 vector<string> options;
5977 options.push_back (_("Cancel"));
5978 options.push_back (_("Add new marker"));
5979 options.push_back (_("Set global tempo"));
5982 _("Define one bar"),
5983 _("Do you want to set the global tempo or add a new tempo marker?"),
5987 c.set_default_response (2);
6003 /* more than 1 tempo and/or meter section already, go ahead do the "usual":
6004 if the marker is at the region starter, change it, otherwise add
6009 begin_reversible_command (_("set tempo from region"));
6010 XMLNode& before (_session->tempo_map().get_state());
6013 _session->tempo_map().change_initial_tempo (beats_per_minute, t.note_type());
6014 } else if (t.frame() == start) {
6015 _session->tempo_map().change_existing_tempo_at (start, beats_per_minute, t.note_type());
6017 Timecode::BBT_Time bbt;
6018 _session->tempo_map().bbt_time (start, bbt);
6019 _session->tempo_map().add_tempo (Tempo (beats_per_minute, t.note_type()), bbt);
6022 XMLNode& after (_session->tempo_map().get_state());
6024 _session->add_command (new MementoCommand<TempoMap>(_session->tempo_map(), &before, &after));
6025 commit_reversible_command ();
6029 Editor::split_region_at_transients ()
6031 AnalysisFeatureList positions;
6033 RegionSelection rs = get_regions_from_selection_and_entered ();
6035 if (!_session || rs.empty()) {
6039 _session->begin_reversible_command (_("split regions"));
6041 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ) {
6043 RegionSelection::iterator tmp;
6048 boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion> ((*i)->region());
6050 if (ar && (ar->get_transients (positions) == 0)) {
6051 split_region_at_points ((*i)->region(), positions, true);
6058 _session->commit_reversible_command ();
6063 Editor::split_region_at_points (boost::shared_ptr<Region> r, AnalysisFeatureList& positions, bool can_ferret, bool select_new)
6065 bool use_rhythmic_rodent = false;
6067 boost::shared_ptr<Playlist> pl = r->playlist();
6069 list<boost::shared_ptr<Region> > new_regions;
6075 if (positions.empty()) {
6080 if (positions.size() > 20 && can_ferret) {
6081 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);
6082 MessageDialog msg (msgstr,
6085 Gtk::BUTTONS_OK_CANCEL);
6088 msg.add_button (_("Call for the Ferret!"), RESPONSE_APPLY);
6089 msg.set_secondary_text (_("Press OK to continue with this split operation\nor ask the Ferret dialog to tune the analysis"));
6091 msg.set_secondary_text (_("Press OK to continue with this split operation"));
6094 msg.set_title (_("Excessive split?"));
6097 int response = msg.run();
6103 case RESPONSE_APPLY:
6104 use_rhythmic_rodent = true;
6111 if (use_rhythmic_rodent) {
6112 show_rhythm_ferret ();
6116 AnalysisFeatureList::const_iterator x;
6118 pl->clear_changes ();
6119 pl->clear_owned_changes ();
6121 x = positions.begin();
6123 if (x == positions.end()) {
6128 pl->remove_region (r);
6132 while (x != positions.end()) {
6134 /* deal with positons that are out of scope of present region bounds */
6135 if (*x <= 0 || *x > r->length()) {
6140 /* file start = original start + how far we from the initial position ?
6143 framepos_t file_start = r->start() + pos;
6145 /* length = next position - current position
6148 framepos_t len = (*x) - pos;
6150 /* XXX we do we really want to allow even single-sample regions?
6151 shouldn't we have some kind of lower limit on region size?
6160 if (RegionFactory::region_name (new_name, r->name())) {
6164 /* do NOT announce new regions 1 by one, just wait till they are all done */
6168 plist.add (ARDOUR::Properties::start, file_start);
6169 plist.add (ARDOUR::Properties::length, len);
6170 plist.add (ARDOUR::Properties::name, new_name);
6171 plist.add (ARDOUR::Properties::layer, 0);
6173 boost::shared_ptr<Region> nr = RegionFactory::create (r->sources(), plist, false);
6174 /* because we set annouce to false, manually add the new region to the
6177 RegionFactory::map_add (nr);
6179 pl->add_region (nr, r->position() + pos);
6182 new_regions.push_front(nr);
6191 RegionFactory::region_name (new_name, r->name());
6193 /* Add the final region */
6196 plist.add (ARDOUR::Properties::start, r->start() + pos);
6197 plist.add (ARDOUR::Properties::length, r->last_frame() - (r->position() + pos) + 1);
6198 plist.add (ARDOUR::Properties::name, new_name);
6199 plist.add (ARDOUR::Properties::layer, 0);
6201 boost::shared_ptr<Region> nr = RegionFactory::create (r->sources(), plist, false);
6202 /* because we set annouce to false, manually add the new region to the
6205 RegionFactory::map_add (nr);
6206 pl->add_region (nr, r->position() + pos);
6209 new_regions.push_front(nr);
6214 /* We might have removed regions, which alters other regions' layering_index,
6215 so we need to do a recursive diff here.
6217 vector<Command*> cmds;
6219 _session->add_commands (cmds);
6221 _session->add_command (new StatefulDiffCommand (pl));
6225 for (list<boost::shared_ptr<Region> >::iterator i = new_regions.begin(); i != new_regions.end(); ++i){
6226 set_selected_regionview_from_region_list ((*i), Selection::Add);
6232 Editor::place_transient()
6238 RegionSelection rs = get_regions_from_selection_and_edit_point ();
6244 framepos_t where = get_preferred_edit_position();
6246 _session->begin_reversible_command (_("place transient"));
6248 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6249 framepos_t position = (*r)->region()->position();
6250 (*r)->region()->add_transient(where - position);
6253 _session->commit_reversible_command ();
6257 Editor::remove_transient(ArdourCanvas::Item* item)
6263 ArdourCanvas::Line* _line = reinterpret_cast<ArdourCanvas::Line*> (item);
6266 AudioRegionView* _arv = reinterpret_cast<AudioRegionView*> (item->get_data ("regionview"));
6267 _arv->remove_transient (*(float*) _line->get_data ("position"));
6271 Editor::snap_regions_to_grid ()
6273 list <boost::shared_ptr<Playlist > > used_playlists;
6275 RegionSelection rs = get_regions_from_selection_and_entered ();
6277 if (!_session || rs.empty()) {
6281 _session->begin_reversible_command (_("snap regions to grid"));
6283 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6285 boost::shared_ptr<Playlist> pl = (*r)->region()->playlist();
6287 if (!pl->frozen()) {
6288 /* we haven't seen this playlist before */
6290 /* remember used playlists so we can thaw them later */
6291 used_playlists.push_back(pl);
6295 framepos_t start_frame = (*r)->region()->first_frame ();
6296 snap_to (start_frame);
6297 (*r)->region()->set_position (start_frame);
6300 while (used_playlists.size() > 0) {
6301 list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
6303 used_playlists.pop_front();
6306 _session->commit_reversible_command ();
6310 Editor::close_region_gaps ()
6312 list <boost::shared_ptr<Playlist > > used_playlists;
6314 RegionSelection rs = get_regions_from_selection_and_entered ();
6316 if (!_session || rs.empty()) {
6320 Dialog dialog (_("Close Region Gaps"));
6323 table.set_spacings (12);
6324 table.set_border_width (12);
6325 Label* l = manage (left_aligned_label (_("Crossfade length")));
6326 table.attach (*l, 0, 1, 0, 1);
6328 SpinButton spin_crossfade (1, 0);
6329 spin_crossfade.set_range (0, 15);
6330 spin_crossfade.set_increments (1, 1);
6331 spin_crossfade.set_value (5);
6332 table.attach (spin_crossfade, 1, 2, 0, 1);
6334 table.attach (*manage (new Label (_("ms"))), 2, 3, 0, 1);
6336 l = manage (left_aligned_label (_("Pull-back length")));
6337 table.attach (*l, 0, 1, 1, 2);
6339 SpinButton spin_pullback (1, 0);
6340 spin_pullback.set_range (0, 100);
6341 spin_pullback.set_increments (1, 1);
6342 spin_pullback.set_value(30);
6343 table.attach (spin_pullback, 1, 2, 1, 2);
6345 table.attach (*manage (new Label (_("ms"))), 2, 3, 1, 2);
6347 dialog.get_vbox()->pack_start (table);
6348 dialog.add_button (Stock::CANCEL, RESPONSE_CANCEL);
6349 dialog.add_button (_("Ok"), RESPONSE_ACCEPT);
6352 if (dialog.run () == RESPONSE_CANCEL) {
6356 framepos_t crossfade_len = spin_crossfade.get_value();
6357 framepos_t pull_back_frames = spin_pullback.get_value();
6359 crossfade_len = lrintf (crossfade_len * _session->frame_rate()/1000);
6360 pull_back_frames = lrintf (pull_back_frames * _session->frame_rate()/1000);
6362 /* Iterate over the region list and make adjacent regions overlap by crossfade_len_ms */
6364 _session->begin_reversible_command (_("close region gaps"));
6367 boost::shared_ptr<Region> last_region;
6369 rs.sort_by_position_and_track();
6371 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6373 boost::shared_ptr<Playlist> pl = (*r)->region()->playlist();
6375 if (!pl->frozen()) {
6376 /* we haven't seen this playlist before */
6378 /* remember used playlists so we can thaw them later */
6379 used_playlists.push_back(pl);
6383 framepos_t position = (*r)->region()->position();
6385 if (idx == 0 || position < last_region->position()){
6386 last_region = (*r)->region();
6391 (*r)->region()->trim_front( (position - pull_back_frames));
6392 last_region->trim_end( (position - pull_back_frames + crossfade_len));
6394 last_region = (*r)->region();
6399 while (used_playlists.size() > 0) {
6400 list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
6402 used_playlists.pop_front();
6405 _session->commit_reversible_command ();
6409 Editor::tab_to_transient (bool forward)
6411 AnalysisFeatureList positions;
6413 RegionSelection rs = get_regions_from_selection_and_entered ();
6419 framepos_t pos = _session->audible_frame ();
6421 if (!selection->tracks.empty()) {
6423 /* don't waste time searching for transients in duplicate playlists.
6426 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
6428 for (TrackViewList::iterator t = ts.begin(); t != ts.end(); ++t) {
6430 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*t);
6433 boost::shared_ptr<Track> tr = rtv->track();
6435 boost::shared_ptr<Playlist> pl = tr->playlist ();
6437 framepos_t result = pl->find_next_transient (pos, forward ? 1 : -1);
6440 positions.push_back (result);
6453 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6454 (*r)->region()->get_transients (positions);
6458 TransientDetector::cleanup_transients (positions, _session->frame_rate(), 3.0);
6461 AnalysisFeatureList::iterator x;
6463 for (x = positions.begin(); x != positions.end(); ++x) {
6469 if (x != positions.end ()) {
6470 _session->request_locate (*x);
6474 AnalysisFeatureList::reverse_iterator x;
6476 for (x = positions.rbegin(); x != positions.rend(); ++x) {
6482 if (x != positions.rend ()) {
6483 _session->request_locate (*x);
6489 Editor::playhead_forward_to_grid ()
6495 framepos_t pos = playhead_cursor->current_frame ();
6496 if (pos < max_framepos - 1) {
6498 snap_to_internal (pos, 1, false);
6499 _session->request_locate (pos);
6505 Editor::playhead_backward_to_grid ()
6511 framepos_t pos = playhead_cursor->current_frame ();
6514 snap_to_internal (pos, -1, false);
6515 _session->request_locate (pos);
6520 Editor::set_track_height (Height h)
6522 TrackSelection& ts (selection->tracks);
6524 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
6525 (*x)->set_height_enum (h);
6530 Editor::toggle_tracks_active ()
6532 TrackSelection& ts (selection->tracks);
6534 bool target = false;
6540 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
6541 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*x);
6545 target = !rtv->_route->active();
6548 rtv->_route->set_active (target, this);
6554 Editor::remove_tracks ()
6556 TrackSelection& ts (selection->tracks);
6562 vector<string> choices;
6566 const char* trackstr;
6568 vector<boost::shared_ptr<Route> > routes;
6569 bool special_bus = false;
6571 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
6572 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*x);
6576 if (rtv->is_track()) {
6581 routes.push_back (rtv->_route);
6583 if (rtv->route()->is_master() || rtv->route()->is_monitor()) {
6588 if (special_bus && !Config->get_allow_special_bus_removal()) {
6589 MessageDialog msg (_("That would be bad news ...."),
6593 msg.set_secondary_text (string_compose (_(
6594 "Removing the master or monitor bus is such a bad idea\n\
6595 that %1 is not going to allow it.\n\
6597 If you really want to do this sort of thing\n\
6598 edit your ardour.rc file to set the\n\
6599 \"allow-special-bus-removal\" option to be \"yes\""), PROGRAM_NAME));
6606 if (ntracks + nbusses == 0) {
6611 trackstr = _("tracks");
6613 trackstr = _("track");
6617 busstr = _("busses");
6624 prompt = string_compose (_("Do you really want to remove %1 %2 and %3 %4?\n"
6625 "(You may also lose the playlists associated with the %2)\n\n"
6626 "This action cannot be undone, and the session file will be overwritten!"),
6627 ntracks, trackstr, nbusses, busstr);
6629 prompt = string_compose (_("Do you really want to remove %1 %2?\n"
6630 "(You may also lose the playlists associated with the %2)\n\n"
6631 "This action cannot be undone, and the session file will be overwritten!"),
6634 } else if (nbusses) {
6635 prompt = string_compose (_("Do you really want to remove %1 %2?\n\n"
6636 "This action cannot be undon, and the session file will be overwritten"),
6640 choices.push_back (_("No, do nothing."));
6641 if (ntracks + nbusses > 1) {
6642 choices.push_back (_("Yes, remove them."));
6644 choices.push_back (_("Yes, remove it."));
6649 title = string_compose (_("Remove %1"), trackstr);
6651 title = string_compose (_("Remove %1"), busstr);
6654 Choice prompter (title, prompt, choices);
6656 if (prompter.run () != 1) {
6660 for (vector<boost::shared_ptr<Route> >::iterator x = routes.begin(); x != routes.end(); ++x) {
6661 _session->remove_route (*x);
6666 Editor::do_insert_time ()
6668 if (selection->tracks.empty()) {
6672 InsertTimeDialog d (*this);
6673 int response = d.run ();
6675 if (response != RESPONSE_OK) {
6679 if (d.distance() == 0) {
6683 InsertTimeOption opt = d.intersected_region_action ();
6686 get_preferred_edit_position(),
6692 d.move_glued_markers(),
6693 d.move_locked_markers(),
6699 Editor::insert_time (
6700 framepos_t pos, framecnt_t frames, InsertTimeOption opt,
6701 bool all_playlists, bool ignore_music_glue, bool markers_too, bool glued_markers_too, bool locked_markers_too, bool tempo_too
6704 bool commit = false;
6706 if (Config->get_edit_mode() == Lock) {
6710 begin_reversible_command (_("insert time"));
6712 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
6714 for (TrackViewList::iterator x = ts.begin(); x != ts.end(); ++x) {
6718 /* don't operate on any playlist more than once, which could
6719 * happen if "all playlists" is enabled, but there is more
6720 * than 1 track using playlists "from" a given track.
6723 set<boost::shared_ptr<Playlist> > pl;
6725 if (all_playlists) {
6726 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*x);
6728 vector<boost::shared_ptr<Playlist> > all = _session->playlists->playlists_for_track (rtav->track ());
6729 for (vector<boost::shared_ptr<Playlist> >::iterator p = all.begin(); p != all.end(); ++p) {
6734 if ((*x)->playlist ()) {
6735 pl.insert ((*x)->playlist ());
6739 for (set<boost::shared_ptr<Playlist> >::iterator i = pl.begin(); i != pl.end(); ++i) {
6741 (*i)->clear_changes ();
6742 (*i)->clear_owned_changes ();
6744 if (opt == SplitIntersected) {
6748 (*i)->shift (pos, frames, (opt == MoveIntersected), ignore_music_glue);
6750 vector<Command*> cmds;
6752 _session->add_commands (cmds);
6754 _session->add_command (new StatefulDiffCommand (*i));
6759 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*x);
6761 rtav->route ()->shift (pos, frames);
6769 XMLNode& before (_session->locations()->get_state());
6770 Locations::LocationList copy (_session->locations()->list());
6772 for (Locations::LocationList::iterator i = copy.begin(); i != copy.end(); ++i) {
6774 Locations::LocationList::const_iterator tmp;
6776 bool const was_locked = (*i)->locked ();
6777 if (locked_markers_too) {
6781 if ((*i)->position_lock_style() == AudioTime || glued_markers_too) {
6783 if ((*i)->start() >= pos) {
6784 (*i)->set_start ((*i)->start() + frames);
6785 if (!(*i)->is_mark()) {
6786 (*i)->set_end ((*i)->end() + frames);
6799 XMLNode& after (_session->locations()->get_state());
6800 _session->add_command (new MementoCommand<Locations>(*_session->locations(), &before, &after));
6805 _session->tempo_map().insert_time (pos, frames);
6809 commit_reversible_command ();
6814 Editor::fit_selected_tracks ()
6816 if (!selection->tracks.empty()) {
6817 fit_tracks (selection->tracks);
6821 /* no selected tracks - use tracks with selected regions */
6823 if (!selection->regions.empty()) {
6824 for (RegionSelection::iterator r = selection->regions.begin(); r != selection->regions.end(); ++r) {
6825 tvl.push_back (&(*r)->get_time_axis_view ());
6831 } else if (internal_editing()) {
6832 /* no selected tracks, or regions, but in internal edit mode, so follow the mouse and use
6835 if (entered_track) {
6836 tvl.push_back (entered_track);
6844 Editor::fit_tracks (TrackViewList & tracks)
6846 if (tracks.empty()) {
6850 uint32_t child_heights = 0;
6851 int visible_tracks = 0;
6853 for (TrackSelection::iterator t = tracks.begin(); t != tracks.end(); ++t) {
6855 if (!(*t)->marked_for_display()) {
6859 child_heights += (*t)->effective_height() - (*t)->current_height();
6863 uint32_t h = (uint32_t) floor ((_visible_canvas_height - child_heights) / visible_tracks);
6864 double first_y_pos = DBL_MAX;
6866 if (h < TimeAxisView::preset_height (HeightSmall)) {
6867 MessageDialog msg (*this, _("There are too many tracks to fit in the current window"));
6868 /* too small to be displayed */
6872 undo_visual_stack.push_back (current_visual_state (true));
6873 no_save_visual = true;
6875 /* build a list of all tracks, including children */
6878 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
6880 TimeAxisView::Children c = (*i)->get_child_list ();
6881 for (TimeAxisView::Children::iterator j = c.begin(); j != c.end(); ++j) {
6882 all.push_back (j->get());
6886 /* operate on all tracks, hide unselected ones that are in the middle of selected ones */
6888 bool prev_was_selected = false;
6889 bool is_selected = tracks.contains (all.front());
6890 bool next_is_selected;
6892 for (TrackViewList::iterator t = all.begin(); t != all.end(); ++t) {
6894 TrackViewList::iterator next;
6899 if (next != all.end()) {
6900 next_is_selected = tracks.contains (*next);
6902 next_is_selected = false;
6905 if ((*t)->marked_for_display ()) {
6907 (*t)->set_height (h);
6908 first_y_pos = std::min ((*t)->y_position (), first_y_pos);
6910 if (prev_was_selected && next_is_selected) {
6911 hide_track_in_display (*t);
6916 prev_was_selected = is_selected;
6917 is_selected = next_is_selected;
6921 set the controls_layout height now, because waiting for its size
6922 request signal handler will cause the vertical adjustment setting to fail
6925 controls_layout.property_height () = _full_canvas_height;
6926 vertical_adjustment.set_value (first_y_pos);
6928 redo_visual_stack.push_back (current_visual_state (true));
6932 Editor::save_visual_state (uint32_t n)
6934 while (visual_states.size() <= n) {
6935 visual_states.push_back (0);
6938 if (visual_states[n] != 0) {
6939 delete visual_states[n];
6942 visual_states[n] = current_visual_state (true);
6947 Editor::goto_visual_state (uint32_t n)
6949 if (visual_states.size() <= n) {
6953 if (visual_states[n] == 0) {
6957 use_visual_state (*visual_states[n]);
6961 Editor::start_visual_state_op (uint32_t n)
6963 save_visual_state (n);
6965 PopUp* pup = new PopUp (WIN_POS_MOUSE, 1000, true);
6967 snprintf (buf, sizeof (buf), _("Saved view %u"), n+1);
6968 pup->set_text (buf);
6973 Editor::cancel_visual_state_op (uint32_t n)
6975 goto_visual_state (n);
6979 Editor::toggle_region_mute ()
6981 if (_ignore_region_action) {
6985 RegionSelection rs = get_regions_from_selection_and_entered ();
6991 if (rs.size() > 1) {
6992 begin_reversible_command (_("mute regions"));
6994 begin_reversible_command (_("mute region"));
6997 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
6999 (*i)->region()->playlist()->clear_changes ();
7000 (*i)->region()->set_muted (!(*i)->region()->muted ());
7001 _session->add_command (new StatefulDiffCommand ((*i)->region()->playlist()));
7005 commit_reversible_command ();
7009 Editor::combine_regions ()
7011 /* foreach track with selected regions, take all selected regions
7012 and join them into a new region containing the subregions (as a
7016 typedef set<RouteTimeAxisView*> RTVS;
7019 if (selection->regions.empty()) {
7023 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
7024 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(&(*i)->get_time_axis_view());
7027 tracks.insert (rtv);
7031 begin_reversible_command (_("combine regions"));
7033 vector<RegionView*> new_selection;
7035 for (RTVS::iterator i = tracks.begin(); i != tracks.end(); ++i) {
7038 if ((rv = (*i)->combine_regions ()) != 0) {
7039 new_selection.push_back (rv);
7043 selection->clear_regions ();
7044 for (vector<RegionView*>::iterator i = new_selection.begin(); i != new_selection.end(); ++i) {
7045 selection->add (*i);
7048 commit_reversible_command ();
7052 Editor::uncombine_regions ()
7054 typedef set<RouteTimeAxisView*> RTVS;
7057 if (selection->regions.empty()) {
7061 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
7062 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(&(*i)->get_time_axis_view());
7065 tracks.insert (rtv);
7069 begin_reversible_command (_("uncombine regions"));
7071 for (RTVS::iterator i = tracks.begin(); i != tracks.end(); ++i) {
7072 (*i)->uncombine_regions ();
7075 commit_reversible_command ();
7079 Editor::toggle_midi_input_active (bool flip_others)
7082 boost::shared_ptr<RouteList> rl (new RouteList);
7084 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
7085 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
7091 boost::shared_ptr<MidiTrack> mt = rtav->midi_track();
7094 rl->push_back (rtav->route());
7095 onoff = !mt->input_active();
7099 _session->set_exclusive_input_active (rl, onoff, flip_others);