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 _session->add_command(new StatefulDiffCommand (playlist));
2123 commit_reversible_command ();
2127 Editor::insert_route_list_drag (boost::shared_ptr<Route> route, int x, int y)
2130 RouteTimeAxisView *dest_rtv = 0;
2131 RouteTimeAxisView *source_rtv = 0;
2134 event.type = GDK_BUTTON_RELEASE;
2138 window_event_sample (&event, &cx, &cy);
2140 std::pair<TimeAxisView*, int> const tv = trackview_by_y_position (cy);
2141 if (tv.first == 0) {
2145 if ((dest_rtv = dynamic_cast<RouteTimeAxisView*> (tv.first)) == 0) {
2149 /* use this drag source to add underlay to a track. But we really don't care
2150 about the Route, only the view of the route, so find it first */
2151 for(TrackViewList::iterator it = track_views.begin(); it != track_views.end(); ++it) {
2152 if((source_rtv = dynamic_cast<RouteTimeAxisView*>(*it)) == 0) {
2156 if(source_rtv->route() == route && source_rtv != dest_rtv) {
2157 dest_rtv->add_underlay(source_rtv->view());
2164 Editor::insert_region_list_selection (float times)
2166 RouteTimeAxisView *tv = 0;
2167 boost::shared_ptr<Playlist> playlist;
2169 if (clicked_routeview != 0) {
2170 tv = clicked_routeview;
2171 } else if (!selection->tracks.empty()) {
2172 if ((tv = dynamic_cast<RouteTimeAxisView*>(selection->tracks.front())) == 0) {
2175 } else if (entered_track != 0) {
2176 if ((tv = dynamic_cast<RouteTimeAxisView*>(entered_track)) == 0) {
2183 if ((playlist = tv->playlist()) == 0) {
2187 boost::shared_ptr<Region> region = _regions->get_single_selection ();
2192 begin_reversible_command (_("insert region"));
2193 playlist->clear_changes ();
2194 playlist->add_region ((RegionFactory::create (region, true)), get_preferred_edit_position(), times);
2195 _session->add_command(new StatefulDiffCommand (playlist));
2196 commit_reversible_command ();
2199 /* BUILT-IN EFFECTS */
2202 Editor::reverse_selection ()
2207 /* GAIN ENVELOPE EDITING */
2210 Editor::edit_envelope ()
2217 Editor::transition_to_rolling (bool fwd)
2223 if (_session->config.get_external_sync()) {
2224 switch (Config->get_sync_source()) {
2228 /* transport controlled by the master */
2233 if (_session->is_auditioning()) {
2234 _session->cancel_audition ();
2238 _session->request_transport_speed (fwd ? 1.0f : -1.0f);
2242 Editor::play_from_start ()
2244 _session->request_locate (_session->current_start_frame(), true);
2248 Editor::play_from_edit_point ()
2250 _session->request_locate (get_preferred_edit_position(), true);
2254 Editor::play_from_edit_point_and_return ()
2256 framepos_t start_frame;
2257 framepos_t return_frame;
2259 start_frame = get_preferred_edit_position (true);
2261 if (_session->transport_rolling()) {
2262 _session->request_locate (start_frame, false);
2266 /* don't reset the return frame if its already set */
2268 if ((return_frame = _session->requested_return_frame()) < 0) {
2269 return_frame = _session->audible_frame();
2272 if (start_frame >= 0) {
2273 _session->request_roll_at_and_return (start_frame, return_frame);
2278 Editor::play_selection ()
2280 if (selection->time.empty()) {
2284 _session->request_play_range (&selection->time, true);
2288 Editor::get_preroll ()
2290 return 1.0 /*Config->get_edit_preroll_seconds()*/ * _session->frame_rate();
2295 Editor::maybe_locate_with_edit_preroll ( framepos_t location )
2297 if ( _session->transport_rolling() || !Config->get_always_play_range() )
2300 location -= get_preroll();
2302 //don't try to locate before the beginning of time
2306 //if follow_playhead is on, keep the playhead on the screen
2307 if ( _follow_playhead )
2308 if ( location < leftmost_frame )
2309 location = leftmost_frame;
2311 _session->request_locate( location );
2315 Editor::play_with_preroll ()
2317 if (selection->time.empty()) {
2320 framepos_t preroll = get_preroll();
2322 framepos_t start = 0;
2323 if (selection->time[clicked_selection].start > preroll)
2324 start = selection->time[clicked_selection].start - preroll;
2326 framepos_t end = selection->time[clicked_selection].end + preroll;
2328 AudioRange ar (start, end, 0);
2329 list<AudioRange> lar;
2332 _session->request_play_range (&lar, true);
2337 Editor::play_location (Location& location)
2339 if (location.start() <= location.end()) {
2343 _session->request_bounded_roll (location.start(), location.end());
2347 Editor::loop_location (Location& location)
2349 if (location.start() <= location.end()) {
2355 if ((tll = transport_loop_location()) != 0) {
2356 tll->set (location.start(), location.end());
2358 // enable looping, reposition and start rolling
2359 _session->request_play_loop (true);
2360 _session->request_locate (tll->start(), true);
2365 Editor::do_layer_operation (LayerOperation op)
2367 if (selection->regions.empty ()) {
2371 bool const multiple = selection->regions.size() > 1;
2375 begin_reversible_command (_("raise regions"));
2377 begin_reversible_command (_("raise region"));
2383 begin_reversible_command (_("raise regions to top"));
2385 begin_reversible_command (_("raise region to top"));
2391 begin_reversible_command (_("lower regions"));
2393 begin_reversible_command (_("lower region"));
2399 begin_reversible_command (_("lower regions to bottom"));
2401 begin_reversible_command (_("lower region"));
2406 set<boost::shared_ptr<Playlist> > playlists = selection->regions.playlists ();
2407 for (set<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
2408 (*i)->clear_owned_changes ();
2411 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
2412 boost::shared_ptr<Region> r = (*i)->region ();
2424 r->lower_to_bottom ();
2428 for (set<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
2429 vector<Command*> cmds;
2431 _session->add_commands (cmds);
2434 commit_reversible_command ();
2438 Editor::raise_region ()
2440 do_layer_operation (Raise);
2444 Editor::raise_region_to_top ()
2446 do_layer_operation (RaiseToTop);
2450 Editor::lower_region ()
2452 do_layer_operation (Lower);
2456 Editor::lower_region_to_bottom ()
2458 do_layer_operation (LowerToBottom);
2461 /** Show the region editor for the selected regions */
2463 Editor::show_region_properties ()
2465 selection->foreach_regionview (&RegionView::show_region_editor);
2468 /** Show the midi list editor for the selected MIDI regions */
2470 Editor::show_midi_list_editor ()
2472 selection->foreach_midi_regionview (&MidiRegionView::show_list_editor);
2476 Editor::rename_region ()
2478 RegionSelection rs = get_regions_from_selection_and_entered ();
2484 ArdourDialog d (*this, _("Rename Region"), true, false);
2486 Label label (_("New name:"));
2489 hbox.set_spacing (6);
2490 hbox.pack_start (label, false, false);
2491 hbox.pack_start (entry, true, true);
2493 d.get_vbox()->set_border_width (12);
2494 d.get_vbox()->pack_start (hbox, false, false);
2496 d.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
2497 d.add_button(Gtk::Stock::OK, Gtk::RESPONSE_OK);
2499 d.set_size_request (300, -1);
2501 entry.set_text (rs.front()->region()->name());
2502 entry.select_region (0, -1);
2504 entry.signal_activate().connect (sigc::bind (sigc::mem_fun (d, &Dialog::response), RESPONSE_OK));
2510 int const ret = d.run();
2514 if (ret != RESPONSE_OK) {
2518 std::string str = entry.get_text();
2519 strip_whitespace_edges (str);
2521 rs.front()->region()->set_name (str);
2522 _regions->redisplay ();
2527 Editor::audition_playlist_region_via_route (boost::shared_ptr<Region> region, Route& route)
2529 if (_session->is_auditioning()) {
2530 _session->cancel_audition ();
2533 // note: some potential for creativity here, because region doesn't
2534 // have to belong to the playlist that Route is handling
2536 // bool was_soloed = route.soloed();
2538 route.set_solo (true, this);
2540 _session->request_bounded_roll (region->position(), region->position() + region->length());
2542 /* XXX how to unset the solo state ? */
2545 /** Start an audition of the first selected region */
2547 Editor::play_edit_range ()
2549 framepos_t start, end;
2551 if (get_edit_op_range (start, end)) {
2552 _session->request_bounded_roll (start, end);
2557 Editor::play_selected_region ()
2559 framepos_t start = max_framepos;
2562 RegionSelection rs = get_regions_from_selection_and_entered ();
2568 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
2569 if ((*i)->region()->position() < start) {
2570 start = (*i)->region()->position();
2572 if ((*i)->region()->last_frame() + 1 > end) {
2573 end = (*i)->region()->last_frame() + 1;
2577 _session->request_bounded_roll (start, end);
2581 Editor::audition_playlist_region_standalone (boost::shared_ptr<Region> region)
2583 _session->audition_region (region);
2587 Editor::region_from_selection ()
2589 if (clicked_axisview == 0) {
2593 if (selection->time.empty()) {
2597 framepos_t start = selection->time[clicked_selection].start;
2598 framepos_t end = selection->time[clicked_selection].end;
2600 TrackViewList tracks = get_tracks_for_range_action ();
2602 framepos_t selection_cnt = end - start + 1;
2604 for (TrackSelection::iterator i = tracks.begin(); i != tracks.end(); ++i) {
2605 boost::shared_ptr<Region> current;
2606 boost::shared_ptr<Playlist> pl;
2607 framepos_t internal_start;
2610 if ((pl = (*i)->playlist()) == 0) {
2614 if ((current = pl->top_region_at (start)) == 0) {
2618 internal_start = start - current->position();
2619 RegionFactory::region_name (new_name, current->name(), true);
2623 plist.add (ARDOUR::Properties::start, current->start() + internal_start);
2624 plist.add (ARDOUR::Properties::length, selection_cnt);
2625 plist.add (ARDOUR::Properties::name, new_name);
2626 plist.add (ARDOUR::Properties::layer, 0);
2628 boost::shared_ptr<Region> region (RegionFactory::create (current, plist));
2633 Editor::create_region_from_selection (vector<boost::shared_ptr<Region> >& new_regions)
2635 if (selection->time.empty() || selection->tracks.empty()) {
2639 framepos_t start = selection->time[clicked_selection].start;
2640 framepos_t end = selection->time[clicked_selection].end;
2642 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
2643 sort_track_selection (ts);
2645 for (TrackSelection::iterator i = ts.begin(); i != ts.end(); ++i) {
2646 boost::shared_ptr<Region> current;
2647 boost::shared_ptr<Playlist> playlist;
2648 framepos_t internal_start;
2651 if ((playlist = (*i)->playlist()) == 0) {
2655 if ((current = playlist->top_region_at(start)) == 0) {
2659 internal_start = start - current->position();
2660 RegionFactory::region_name (new_name, current->name(), true);
2664 plist.add (ARDOUR::Properties::start, current->start() + internal_start);
2665 plist.add (ARDOUR::Properties::length, end - start + 1);
2666 plist.add (ARDOUR::Properties::name, new_name);
2668 new_regions.push_back (RegionFactory::create (current, plist));
2673 Editor::split_multichannel_region ()
2675 RegionSelection rs = get_regions_from_selection_and_entered ();
2681 vector< boost::shared_ptr<Region> > v;
2683 for (list<RegionView*>::iterator x = rs.begin(); x != rs.end(); ++x) {
2684 (*x)->region()->separate_by_channel (*_session, v);
2689 Editor::new_region_from_selection ()
2691 region_from_selection ();
2692 cancel_selection ();
2696 add_if_covered (RegionView* rv, const AudioRange* ar, RegionSelection* rs)
2698 switch (rv->region()->coverage (ar->start, ar->end - 1)) {
2699 case Evoral::OverlapNone:
2707 * - selected tracks, or if there are none...
2708 * - tracks containing selected regions, or if there are none...
2713 Editor::get_tracks_for_range_action () const
2717 if (selection->tracks.empty()) {
2719 /* use tracks with selected regions */
2721 RegionSelection rs = selection->regions;
2723 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
2724 TimeAxisView* tv = &(*i)->get_time_axis_view();
2726 if (!t.contains (tv)) {
2732 /* no regions and no tracks: use all tracks */
2738 t = selection->tracks;
2741 return t.filter_to_unique_playlists();
2745 Editor::separate_regions_between (const TimeSelection& ts)
2747 bool in_command = false;
2748 boost::shared_ptr<Playlist> playlist;
2749 RegionSelection new_selection;
2751 TrackViewList tmptracks = get_tracks_for_range_action ();
2752 sort_track_selection (tmptracks);
2754 for (TrackSelection::iterator i = tmptracks.begin(); i != tmptracks.end(); ++i) {
2756 RouteTimeAxisView* rtv;
2758 if ((rtv = dynamic_cast<RouteTimeAxisView*> ((*i))) != 0) {
2760 if (rtv->is_track()) {
2762 /* no edits to destructive tracks */
2764 if (rtv->track()->destructive()) {
2768 if ((playlist = rtv->playlist()) != 0) {
2770 playlist->clear_changes ();
2772 /* XXX need to consider musical time selections here at some point */
2774 double speed = rtv->track()->speed();
2777 for (list<AudioRange>::const_iterator t = ts.begin(); t != ts.end(); ++t) {
2779 sigc::connection c = rtv->view()->RegionViewAdded.connect (
2780 sigc::mem_fun(*this, &Editor::collect_new_region_view));
2782 latest_regionviews.clear ();
2784 playlist->partition ((framepos_t)((*t).start * speed),
2785 (framepos_t)((*t).end * speed), false);
2789 if (!latest_regionviews.empty()) {
2791 rtv->view()->foreach_regionview (sigc::bind (
2792 sigc::ptr_fun (add_if_covered),
2793 &(*t), &new_selection));
2796 begin_reversible_command (_("separate"));
2800 /* pick up changes to existing regions */
2802 vector<Command*> cmds;
2803 playlist->rdiff (cmds);
2804 _session->add_commands (cmds);
2806 /* pick up changes to the playlist itself (adds/removes)
2809 _session->add_command(new StatefulDiffCommand (playlist));
2818 selection->set (new_selection);
2819 set_mouse_mode (MouseObject);
2821 commit_reversible_command ();
2825 struct PlaylistState {
2826 boost::shared_ptr<Playlist> playlist;
2830 /** Take tracks from get_tracks_for_range_action and cut any regions
2831 * on those tracks so that the tracks are empty over the time
2835 Editor::separate_region_from_selection ()
2837 /* preferentially use *all* ranges in the time selection if we're in range mode
2838 to allow discontiguous operation, since get_edit_op_range() currently
2839 returns a single range.
2842 if (!selection->time.empty()) {
2844 separate_regions_between (selection->time);
2851 if (get_edit_op_range (start, end)) {
2853 AudioRange ar (start, end, 1);
2857 separate_regions_between (ts);
2863 Editor::separate_region_from_punch ()
2865 Location* loc = _session->locations()->auto_punch_location();
2867 separate_regions_using_location (*loc);
2872 Editor::separate_region_from_loop ()
2874 Location* loc = _session->locations()->auto_loop_location();
2876 separate_regions_using_location (*loc);
2881 Editor::separate_regions_using_location (Location& loc)
2883 if (loc.is_mark()) {
2887 AudioRange ar (loc.start(), loc.end(), 1);
2892 separate_regions_between (ts);
2895 /** Separate regions under the selected region */
2897 Editor::separate_under_selected_regions ()
2899 vector<PlaylistState> playlists;
2903 rs = get_regions_from_selection_and_entered();
2905 if (!_session || rs.empty()) {
2909 begin_reversible_command (_("separate region under"));
2911 list<boost::shared_ptr<Region> > regions_to_remove;
2913 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
2914 // we can't just remove the region(s) in this loop because
2915 // this removes them from the RegionSelection, and they thus
2916 // disappear from underneath the iterator, and the ++i above
2917 // SEGVs in a puzzling fashion.
2919 // so, first iterate over the regions to be removed from rs and
2920 // add them to the regions_to_remove list, and then
2921 // iterate over the list to actually remove them.
2923 regions_to_remove.push_back ((*i)->region());
2926 for (list<boost::shared_ptr<Region> >::iterator rl = regions_to_remove.begin(); rl != regions_to_remove.end(); ++rl) {
2928 boost::shared_ptr<Playlist> playlist = (*rl)->playlist();
2931 // is this check necessary?
2935 vector<PlaylistState>::iterator i;
2937 //only take state if this is a new playlist.
2938 for (i = playlists.begin(); i != playlists.end(); ++i) {
2939 if ((*i).playlist == playlist) {
2944 if (i == playlists.end()) {
2946 PlaylistState before;
2947 before.playlist = playlist;
2948 before.before = &playlist->get_state();
2950 playlist->freeze ();
2951 playlists.push_back(before);
2954 //Partition on the region bounds
2955 playlist->partition ((*rl)->first_frame() - 1, (*rl)->last_frame() + 1, true);
2957 //Re-add region that was just removed due to the partition operation
2958 playlist->add_region( (*rl), (*rl)->first_frame() );
2961 vector<PlaylistState>::iterator pl;
2963 for (pl = playlists.begin(); pl != playlists.end(); ++pl) {
2964 (*pl).playlist->thaw ();
2965 _session->add_command(new MementoCommand<Playlist>(*(*pl).playlist, (*pl).before, &(*pl).playlist->get_state()));
2968 commit_reversible_command ();
2972 Editor::crop_region_to_selection ()
2974 if (!selection->time.empty()) {
2976 crop_region_to (selection->time.start(), selection->time.end_frame());
2983 if (get_edit_op_range (start, end)) {
2984 crop_region_to (start, end);
2991 Editor::crop_region_to (framepos_t start, framepos_t end)
2993 vector<boost::shared_ptr<Playlist> > playlists;
2994 boost::shared_ptr<Playlist> playlist;
2997 if (selection->tracks.empty()) {
2998 ts = track_views.filter_to_unique_playlists();
3000 ts = selection->tracks.filter_to_unique_playlists ();
3003 sort_track_selection (ts);
3005 for (TrackSelection::iterator i = ts.begin(); i != ts.end(); ++i) {
3007 RouteTimeAxisView* rtv;
3009 if ((rtv = dynamic_cast<RouteTimeAxisView*> ((*i))) != 0) {
3011 boost::shared_ptr<Track> t = rtv->track();
3013 if (t != 0 && ! t->destructive()) {
3015 if ((playlist = rtv->playlist()) != 0) {
3016 playlists.push_back (playlist);
3022 if (playlists.empty()) {
3026 framepos_t the_start;
3030 begin_reversible_command (_("trim to selection"));
3032 for (vector<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
3034 boost::shared_ptr<Region> region;
3038 if ((region = (*i)->top_region_at(the_start)) == 0) {
3042 /* now adjust lengths to that we do the right thing
3043 if the selection extends beyond the region
3046 the_start = max (the_start, (framepos_t) region->position());
3047 if (max_framepos - the_start < region->length()) {
3048 the_end = the_start + region->length() - 1;
3050 the_end = max_framepos;
3052 the_end = min (end, the_end);
3053 cnt = the_end - the_start + 1;
3055 region->clear_changes ();
3056 region->trim_to (the_start, cnt);
3057 _session->add_command (new StatefulDiffCommand (region));
3060 commit_reversible_command ();
3064 Editor::region_fill_track ()
3066 RegionSelection rs = get_regions_from_selection_and_entered ();
3068 if (!_session || rs.empty()) {
3072 framepos_t const end = _session->current_end_frame ();
3074 begin_reversible_command (Operations::region_fill);
3076 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3078 boost::shared_ptr<Region> region ((*i)->region());
3080 boost::shared_ptr<Playlist> pl = region->playlist();
3082 if (end <= region->last_frame()) {
3086 double times = (double) (end - region->last_frame()) / (double) region->length();
3092 pl->clear_changes ();
3093 pl->add_region (RegionFactory::create (region, true), region->last_frame(), times);
3094 _session->add_command (new StatefulDiffCommand (pl));
3097 commit_reversible_command ();
3101 Editor::region_fill_selection ()
3103 if (clicked_routeview == 0 || !clicked_routeview->is_audio_track()) {
3107 if (selection->time.empty()) {
3111 boost::shared_ptr<Region> region = _regions->get_single_selection ();
3116 framepos_t start = selection->time[clicked_selection].start;
3117 framepos_t end = selection->time[clicked_selection].end;
3119 boost::shared_ptr<Playlist> playlist;
3121 if (selection->tracks.empty()) {
3125 framepos_t selection_length = end - start;
3126 float times = (float)selection_length / region->length();
3128 begin_reversible_command (Operations::fill_selection);
3130 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
3132 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
3134 if ((playlist = (*i)->playlist()) == 0) {
3138 playlist->clear_changes ();
3139 playlist->add_region (RegionFactory::create (region, true), start, times);
3140 _session->add_command (new StatefulDiffCommand (playlist));
3143 commit_reversible_command ();
3147 Editor::set_region_sync_position ()
3149 set_sync_point (get_preferred_edit_position (), get_regions_from_selection_and_edit_point ());
3153 Editor::set_sync_point (framepos_t where, const RegionSelection& rs)
3155 bool in_command = false;
3157 for (RegionSelection::const_iterator r = rs.begin(); r != rs.end(); ++r) {
3159 if (!(*r)->region()->covers (where)) {
3163 boost::shared_ptr<Region> region ((*r)->region());
3166 begin_reversible_command (_("set sync point"));
3170 region->clear_changes ();
3171 region->set_sync_position (where);
3172 _session->add_command(new StatefulDiffCommand (region));
3176 commit_reversible_command ();
3180 /** Remove the sync positions of the selection */
3182 Editor::remove_region_sync ()
3184 RegionSelection rs = get_regions_from_selection_and_entered ();
3190 begin_reversible_command (_("remove region sync"));
3192 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3194 (*i)->region()->clear_changes ();
3195 (*i)->region()->clear_sync_position ();
3196 _session->add_command(new StatefulDiffCommand ((*i)->region()));
3199 commit_reversible_command ();
3203 Editor::naturalize_region ()
3205 RegionSelection rs = get_regions_from_selection_and_entered ();
3211 if (rs.size() > 1) {
3212 begin_reversible_command (_("move regions to original position"));
3214 begin_reversible_command (_("move region to original position"));
3217 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3218 (*i)->region()->clear_changes ();
3219 (*i)->region()->move_to_natural_position ();
3220 _session->add_command (new StatefulDiffCommand ((*i)->region()));
3223 commit_reversible_command ();
3227 Editor::align_regions (RegionPoint what)
3229 RegionSelection const rs = get_regions_from_selection_and_edit_point ();
3235 begin_reversible_command (_("align selection"));
3237 framepos_t const position = get_preferred_edit_position ();
3239 for (RegionSelection::const_iterator i = rs.begin(); i != rs.end(); ++i) {
3240 align_region_internal ((*i)->region(), what, position);
3243 commit_reversible_command ();
3246 struct RegionSortByTime {
3247 bool operator() (const RegionView* a, const RegionView* b) {
3248 return a->region()->position() < b->region()->position();
3253 Editor::align_regions_relative (RegionPoint point)
3255 RegionSelection const rs = get_regions_from_selection_and_edit_point ();
3261 framepos_t const position = get_preferred_edit_position ();
3263 framepos_t distance = 0;
3267 list<RegionView*> sorted;
3268 rs.by_position (sorted);
3270 boost::shared_ptr<Region> r ((*sorted.begin())->region());
3275 if (position > r->position()) {
3276 distance = position - r->position();
3278 distance = r->position() - position;
3284 if (position > r->last_frame()) {
3285 distance = position - r->last_frame();
3286 pos = r->position() + distance;
3288 distance = r->last_frame() - position;
3289 pos = r->position() - distance;
3295 pos = r->adjust_to_sync (position);
3296 if (pos > r->position()) {
3297 distance = pos - r->position();
3299 distance = r->position() - pos;
3305 if (pos == r->position()) {
3309 begin_reversible_command (_("align selection (relative)"));
3311 /* move first one specially */
3313 r->clear_changes ();
3314 r->set_position (pos);
3315 _session->add_command(new StatefulDiffCommand (r));
3317 /* move rest by the same amount */
3321 for (list<RegionView*>::iterator i = sorted.begin(); i != sorted.end(); ++i) {
3323 boost::shared_ptr<Region> region ((*i)->region());
3325 region->clear_changes ();
3328 region->set_position (region->position() + distance);
3330 region->set_position (region->position() - distance);
3333 _session->add_command(new StatefulDiffCommand (region));
3337 commit_reversible_command ();
3341 Editor::align_region (boost::shared_ptr<Region> region, RegionPoint point, framepos_t position)
3343 begin_reversible_command (_("align region"));
3344 align_region_internal (region, point, position);
3345 commit_reversible_command ();
3349 Editor::align_region_internal (boost::shared_ptr<Region> region, RegionPoint point, framepos_t position)
3351 region->clear_changes ();
3355 region->set_position (region->adjust_to_sync (position));
3359 if (position > region->length()) {
3360 region->set_position (position - region->length());
3365 region->set_position (position);
3369 _session->add_command(new StatefulDiffCommand (region));
3373 Editor::trim_region_front ()
3379 Editor::trim_region_back ()
3381 trim_region (false);
3385 Editor::trim_region (bool front)
3387 framepos_t where = get_preferred_edit_position();
3388 RegionSelection rs = get_regions_from_selection_and_edit_point ();
3394 begin_reversible_command (front ? _("trim front") : _("trim back"));
3396 for (list<RegionView*>::const_iterator i = rs.by_layer().begin(); i != rs.by_layer().end(); ++i) {
3397 if (!(*i)->region()->locked()) {
3399 (*i)->region()->clear_changes ();
3402 (*i)->region()->trim_front (where);
3403 maybe_locate_with_edit_preroll ( where );
3405 (*i)->region()->trim_end (where);
3406 maybe_locate_with_edit_preroll ( where );
3409 _session->add_command (new StatefulDiffCommand ((*i)->region()));
3413 commit_reversible_command ();
3416 /** Trim the end of the selected regions to the position of the edit cursor */
3418 Editor::trim_region_to_loop ()
3420 Location* loc = _session->locations()->auto_loop_location();
3424 trim_region_to_location (*loc, _("trim to loop"));
3428 Editor::trim_region_to_punch ()
3430 Location* loc = _session->locations()->auto_punch_location();
3434 trim_region_to_location (*loc, _("trim to punch"));
3438 Editor::trim_region_to_location (const Location& loc, const char* str)
3440 RegionSelection rs = get_regions_from_selection_and_entered ();
3442 begin_reversible_command (str);
3444 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
3445 RegionView* rv = (*x);
3447 /* require region to span proposed trim */
3448 switch (rv->region()->coverage (loc.start(), loc.end())) {
3449 case Evoral::OverlapInternal:
3455 RouteTimeAxisView* tav = dynamic_cast<RouteTimeAxisView*> (&rv->get_time_axis_view());
3464 if (tav->track() != 0) {
3465 speed = tav->track()->speed();
3468 start = session_frame_to_track_frame (loc.start(), speed);
3469 end = session_frame_to_track_frame (loc.end(), speed);
3471 rv->region()->clear_changes ();
3472 rv->region()->trim_to (start, (end - start));
3473 _session->add_command(new StatefulDiffCommand (rv->region()));
3476 commit_reversible_command ();
3480 Editor::trim_region_to_previous_region_end ()
3482 return trim_to_region(false);
3486 Editor::trim_region_to_next_region_start ()
3488 return trim_to_region(true);
3492 Editor::trim_to_region(bool forward)
3494 RegionSelection rs = get_regions_from_selection_and_entered ();
3496 begin_reversible_command (_("trim to region"));
3498 boost::shared_ptr<Region> next_region;
3500 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
3502 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*x);
3508 AudioTimeAxisView* atav = dynamic_cast<AudioTimeAxisView*> (&arv->get_time_axis_view());
3516 if (atav->track() != 0) {
3517 speed = atav->track()->speed();
3521 boost::shared_ptr<Region> region = arv->region();
3522 boost::shared_ptr<Playlist> playlist (region->playlist());
3524 region->clear_changes ();
3528 next_region = playlist->find_next_region (region->first_frame(), Start, 1);
3534 region->trim_end((framepos_t) ( (next_region->first_frame() - 1) * speed));
3535 arv->region_changed (PropertyChange (ARDOUR::Properties::length));
3539 next_region = playlist->find_next_region (region->first_frame(), Start, 0);
3545 region->trim_front((framepos_t) ((next_region->last_frame() + 1) * speed));
3547 arv->region_changed (ARDOUR::bounds_change);
3550 _session->add_command(new StatefulDiffCommand (region));
3553 commit_reversible_command ();
3557 Editor::unfreeze_route ()
3559 if (clicked_routeview == 0 || !clicked_routeview->is_track()) {
3563 clicked_routeview->track()->unfreeze ();
3567 Editor::_freeze_thread (void* arg)
3569 return static_cast<Editor*>(arg)->freeze_thread ();
3573 Editor::freeze_thread ()
3575 /* create event pool because we may need to talk to the session */
3576 SessionEvent::create_per_thread_pool ("freeze events", 64);
3577 /* create per-thread buffers for process() tree to use */
3578 clicked_routeview->audio_track()->freeze_me (*current_interthread_info);
3579 current_interthread_info->done = true;
3584 Editor::freeze_route ()
3590 /* stop transport before we start. this is important */
3592 _session->request_transport_speed (0.0);
3594 /* wait for just a little while, because the above call is asynchronous */
3596 Glib::usleep (250000);
3598 if (clicked_routeview == 0 || !clicked_routeview->is_audio_track()) {
3602 if (!clicked_routeview->track()->bounceable (clicked_routeview->track()->main_outs(), true)) {
3604 _("This track/bus cannot be frozen because the signal adds or loses channels before reaching the outputs.\n"
3605 "This is typically caused by plugins that generate stereo output from mono input or vice versa.")
3607 d.set_title (_("Cannot freeze"));
3612 if (clicked_routeview->track()->has_external_redirects()) {
3613 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"
3614 "Freezing will only process the signal as far as the first send/insert/return."),
3615 clicked_routeview->track()->name()), true, MESSAGE_INFO, BUTTONS_NONE, true);
3617 d.add_button (_("Freeze anyway"), Gtk::RESPONSE_OK);
3618 d.add_button (_("Don't freeze"), Gtk::RESPONSE_CANCEL);
3619 d.set_title (_("Freeze Limits"));
3621 int response = d.run ();
3624 case Gtk::RESPONSE_CANCEL:
3631 InterThreadInfo itt;
3632 current_interthread_info = &itt;
3634 InterthreadProgressWindow ipw (current_interthread_info, _("Freeze"), _("Cancel Freeze"));
3636 pthread_create_and_store (X_("freezer"), &itt.thread, _freeze_thread, this);
3638 set_canvas_cursor (_cursors->wait);
3640 while (!itt.done && !itt.cancel) {
3641 gtk_main_iteration ();
3644 current_interthread_info = 0;
3645 set_canvas_cursor (current_canvas_cursor);
3649 Editor::bounce_range_selection (bool replace, bool enable_processing)
3651 if (selection->time.empty()) {
3655 TrackSelection views = selection->tracks;
3657 for (TrackViewList::iterator i = views.begin(); i != views.end(); ++i) {
3659 if (enable_processing) {
3661 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*i);
3663 if (rtv && rtv->track() && replace && enable_processing && !rtv->track()->bounceable (rtv->track()->main_outs(), false)) {
3665 _("You can't perform this operation because the processing of the signal "
3666 "will cause one or more of the tracks to end up with a region with more channels than this track has inputs.\n\n"
3667 "You can do this without processing, which is a different operation.")
3669 d.set_title (_("Cannot bounce"));
3676 framepos_t start = selection->time[clicked_selection].start;
3677 framepos_t end = selection->time[clicked_selection].end;
3678 framepos_t cnt = end - start + 1;
3680 begin_reversible_command (_("bounce range"));
3682 for (TrackViewList::iterator i = views.begin(); i != views.end(); ++i) {
3684 RouteTimeAxisView* rtv;
3686 if ((rtv = dynamic_cast<RouteTimeAxisView*> (*i)) == 0) {
3690 boost::shared_ptr<Playlist> playlist;
3692 if ((playlist = rtv->playlist()) == 0) {
3696 InterThreadInfo itt;
3698 playlist->clear_changes ();
3699 playlist->clear_owned_changes ();
3701 boost::shared_ptr<Region> r;
3703 if (enable_processing) {
3704 r = rtv->track()->bounce_range (start, start+cnt, itt, rtv->track()->main_outs(), false);
3706 r = rtv->track()->bounce_range (start, start+cnt, itt, boost::shared_ptr<Processor>(), false);
3714 list<AudioRange> ranges;
3715 ranges.push_back (AudioRange (start, start+cnt, 0));
3716 playlist->cut (ranges); // discard result
3717 playlist->add_region (r, start);
3720 vector<Command*> cmds;
3721 playlist->rdiff (cmds);
3722 _session->add_commands (cmds);
3724 _session->add_command (new StatefulDiffCommand (playlist));
3727 commit_reversible_command ();
3730 /** Delete selected regions, automation points or a time range */
3737 /** Cut selected regions, automation points or a time range */
3744 /** Copy selected regions, automation points or a time range */
3752 /** @return true if a Cut, Copy or Clear is possible */
3754 Editor::can_cut_copy () const
3756 switch (effective_mouse_mode()) {
3759 if (!selection->regions.empty() || !selection->points.empty()) {
3765 if (!selection->time.empty()) {
3778 /** Cut, copy or clear selected regions, automation points or a time range.
3779 * @param op Operation (Cut, Copy or Clear)
3782 Editor::cut_copy (CutCopyOp op)
3784 /* only cancel selection if cut/copy is successful.*/
3790 opname = _("delete");
3799 opname = _("clear");
3803 /* if we're deleting something, and the mouse is still pressed,
3804 the thing we started a drag for will be gone when we release
3805 the mouse button(s). avoid this. see part 2 at the end of
3809 if (op == Delete || op == Cut || op == Clear) {
3810 if (_drags->active ()) {
3815 if ( op != Clear ) //"Delete" doesn't change copy/paste buf
3816 cut_buffer->clear ();
3818 if (entered_marker) {
3820 /* cut/delete op while pointing at a marker */
3823 Location* loc = find_location_from_marker (entered_marker, ignored);
3825 if (_session && loc) {
3826 Glib::signal_idle().connect (sigc::bind (sigc::mem_fun(*this, &Editor::really_remove_marker), loc));
3833 if (internal_editing()) {
3835 switch (effective_mouse_mode()) {
3838 begin_reversible_command (opname + ' ' + X_("MIDI"));
3840 commit_reversible_command ();
3849 bool did_edit = false;
3851 switch (effective_mouse_mode()) {
3853 if (!selection->points.empty()) {
3854 begin_reversible_command (opname + _(" points"));
3856 cut_copy_points (op);
3857 if (op == Cut || op == Delete) {
3858 selection->clear_points ();
3865 if (!selection->regions.empty() || !selection->points.empty()) {
3869 if (selection->regions.empty()) {
3870 thing_name = _("points");
3871 } else if (selection->points.empty()) {
3872 thing_name = _("regions");
3874 thing_name = _("objects");
3877 begin_reversible_command (opname + ' ' + thing_name);
3880 if (!selection->regions.empty()) {
3881 cut_copy_regions (op, selection->regions);
3883 if (op == Cut || op == Delete) {
3884 selection->clear_regions ();
3888 if (!selection->points.empty()) {
3889 cut_copy_points (op);
3891 if (op == Cut || op == Delete) {
3892 selection->clear_points ();
3899 if (selection->time.empty()) {
3900 framepos_t start, end;
3901 /* no time selection, see if we can get an edit range
3904 if (get_edit_op_range (start, end)) {
3905 selection->set (start, end);
3908 if (!selection->time.empty()) {
3909 begin_reversible_command (opname + _(" range"));
3912 cut_copy_ranges (op);
3914 if (op == Cut || op == Delete) {
3915 selection->clear_time ();
3925 commit_reversible_command ();
3928 if (op == Delete || op == Cut || op == Clear) {
3933 struct AutomationRecord {
3934 AutomationRecord () : state (0) {}
3935 AutomationRecord (XMLNode* s) : state (s) {}
3937 XMLNode* state; ///< state before any operation
3938 boost::shared_ptr<Evoral::ControlList> copy; ///< copied events for the cut buffer
3941 /** Cut, copy or clear selected automation points.
3942 * @param op Operation (Cut, Copy or Clear)
3945 Editor::cut_copy_points (CutCopyOp op)
3947 if (selection->points.empty ()) {
3951 /* XXX: not ideal, as there may be more than one track involved in the point selection */
3952 _last_cut_copy_source_track = &selection->points.front()->line().trackview;
3954 /* Keep a record of the AutomationLists that we end up using in this operation */
3955 typedef std::map<boost::shared_ptr<AutomationList>, AutomationRecord> Lists;
3958 /* Go through all selected points, making an AutomationRecord for each distinct AutomationList */
3959 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
3960 boost::shared_ptr<AutomationList> al = (*i)->line().the_list();
3961 if (lists.find (al) == lists.end ()) {
3962 /* We haven't seen this list yet, so make a record for it. This includes
3963 taking a copy of its current state, in case this is needed for undo later.
3965 lists[al] = AutomationRecord (&al->get_state ());
3969 if (op == Cut || op == Copy) {
3970 /* This operation will involve putting things in the cut buffer, so create an empty
3971 ControlList for each of our source lists to put the cut buffer data in.
3973 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
3974 i->second.copy = i->first->create (i->first->parameter ());
3977 /* Add all selected points to the relevant copy ControlLists */
3978 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
3979 boost::shared_ptr<AutomationList> al = (*i)->line().the_list();
3980 AutomationList::const_iterator j = (*i)->model ();
3981 lists[al].copy->add ((*j)->when, (*j)->value);
3984 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
3985 /* Correct this copy list so that it starts at time 0 */
3986 double const start = i->second.copy->front()->when;
3987 for (AutomationList::iterator j = i->second.copy->begin(); j != i->second.copy->end(); ++j) {
3988 (*j)->when -= start;
3991 /* And add it to the cut buffer */
3992 cut_buffer->add (i->second.copy);
3996 if (op == Delete || op == Cut) {
3997 /* This operation needs to remove things from the main AutomationList, so do that now */
3999 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
4000 i->first->freeze ();
4003 /* Remove each selected point from its AutomationList */
4004 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
4005 boost::shared_ptr<AutomationList> al = (*i)->line().the_list();
4006 al->erase ((*i)->model ());
4009 /* Thaw the lists and add undo records for them */
4010 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
4011 boost::shared_ptr<AutomationList> al = i->first;
4013 _session->add_command (new MementoCommand<AutomationList> (*al.get(), i->second.state, &(al->get_state ())));
4018 /** Cut, copy or clear selected automation points.
4019 * @param op Operation (Cut, Copy or Clear)
4022 Editor::cut_copy_midi (CutCopyOp op)
4024 for (MidiRegionSelection::iterator i = selection->midi_regions.begin(); i != selection->midi_regions.end(); ++i) {
4025 MidiRegionView* mrv = *i;
4026 mrv->cut_copy_clear (op);
4032 struct lt_playlist {
4033 bool operator () (const PlaylistState& a, const PlaylistState& b) {
4034 return a.playlist < b.playlist;
4038 struct PlaylistMapping {
4040 boost::shared_ptr<Playlist> pl;
4042 PlaylistMapping (TimeAxisView* tvp) : tv (tvp) {}
4045 /** Remove `clicked_regionview' */
4047 Editor::remove_clicked_region ()
4049 if (clicked_routeview == 0 || clicked_regionview == 0) {
4053 boost::shared_ptr<Playlist> playlist = clicked_routeview->playlist();
4055 begin_reversible_command (_("remove region"));
4056 playlist->clear_changes ();
4057 playlist->clear_owned_changes ();
4058 playlist->remove_region (clicked_regionview->region());
4060 /* We might have removed regions, which alters other regions' layering_index,
4061 so we need to do a recursive diff here.
4063 vector<Command*> cmds;
4064 playlist->rdiff (cmds);
4065 _session->add_commands (cmds);
4067 _session->add_command(new StatefulDiffCommand (playlist));
4068 commit_reversible_command ();
4072 /** Remove the selected regions */
4074 Editor::remove_selected_regions ()
4076 RegionSelection rs = get_regions_from_selection_and_entered ();
4078 if (!_session || rs.empty()) {
4082 begin_reversible_command (_("remove region"));
4084 list<boost::shared_ptr<Region> > regions_to_remove;
4086 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
4087 // we can't just remove the region(s) in this loop because
4088 // this removes them from the RegionSelection, and they thus
4089 // disappear from underneath the iterator, and the ++i above
4090 // SEGVs in a puzzling fashion.
4092 // so, first iterate over the regions to be removed from rs and
4093 // add them to the regions_to_remove list, and then
4094 // iterate over the list to actually remove them.
4096 regions_to_remove.push_back ((*i)->region());
4099 vector<boost::shared_ptr<Playlist> > playlists;
4101 for (list<boost::shared_ptr<Region> >::iterator rl = regions_to_remove.begin(); rl != regions_to_remove.end(); ++rl) {
4103 boost::shared_ptr<Playlist> playlist = (*rl)->playlist();
4106 // is this check necessary?
4110 /* get_regions_from_selection_and_entered() guarantees that
4111 the playlists involved are unique, so there is no need
4115 playlists.push_back (playlist);
4117 playlist->clear_changes ();
4118 playlist->clear_owned_changes ();
4119 playlist->freeze ();
4120 playlist->remove_region (*rl);
4123 vector<boost::shared_ptr<Playlist> >::iterator pl;
4125 for (pl = playlists.begin(); pl != playlists.end(); ++pl) {
4128 /* We might have removed regions, which alters other regions' layering_index,
4129 so we need to do a recursive diff here.
4131 vector<Command*> cmds;
4132 (*pl)->rdiff (cmds);
4133 _session->add_commands (cmds);
4135 _session->add_command(new StatefulDiffCommand (*pl));
4138 commit_reversible_command ();
4141 /** Cut, copy or clear selected regions.
4142 * @param op Operation (Cut, Copy or Clear)
4145 Editor::cut_copy_regions (CutCopyOp op, RegionSelection& rs)
4147 /* we can't use a std::map here because the ordering is important, and we can't trivially sort
4148 a map when we want ordered access to both elements. i think.
4151 vector<PlaylistMapping> pmap;
4153 framepos_t first_position = max_framepos;
4155 typedef set<boost::shared_ptr<Playlist> > FreezeList;
4156 FreezeList freezelist;
4158 /* get ordering correct before we cut/copy */
4160 rs.sort_by_position_and_track ();
4162 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
4164 first_position = min ((framepos_t) (*x)->region()->position(), first_position);
4166 if (op == Cut || op == Clear || op == Delete) {
4167 boost::shared_ptr<Playlist> pl = (*x)->region()->playlist();
4170 FreezeList::iterator fl;
4172 // only take state if this is a new playlist.
4173 for (fl = freezelist.begin(); fl != freezelist.end(); ++fl) {
4179 if (fl == freezelist.end()) {
4180 pl->clear_changes();
4181 pl->clear_owned_changes ();
4183 freezelist.insert (pl);
4188 TimeAxisView* tv = &(*x)->get_time_axis_view();
4189 vector<PlaylistMapping>::iterator z;
4191 for (z = pmap.begin(); z != pmap.end(); ++z) {
4192 if ((*z).tv == tv) {
4197 if (z == pmap.end()) {
4198 pmap.push_back (PlaylistMapping (tv));
4202 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ) {
4204 boost::shared_ptr<Playlist> pl = (*x)->region()->playlist();
4207 /* region not yet associated with a playlist (e.g. unfinished
4214 TimeAxisView& tv = (*x)->get_time_axis_view();
4215 boost::shared_ptr<Playlist> npl;
4216 RegionSelection::iterator tmp;
4223 vector<PlaylistMapping>::iterator z;
4225 for (z = pmap.begin(); z != pmap.end(); ++z) {
4226 if ((*z).tv == &tv) {
4231 assert (z != pmap.end());
4234 npl = PlaylistFactory::create (pl->data_type(), *_session, "cutlist", true);
4242 boost::shared_ptr<Region> r = (*x)->region();
4243 boost::shared_ptr<Region> _xx;
4249 pl->remove_region (r);
4253 _xx = RegionFactory::create (r);
4254 npl->add_region (_xx, r->position() - first_position);
4255 pl->remove_region (r);
4259 /* copy region before adding, so we're not putting same object into two different playlists */
4260 npl->add_region (RegionFactory::create (r), r->position() - first_position);
4264 pl->remove_region (r);
4273 list<boost::shared_ptr<Playlist> > foo;
4275 /* the pmap is in the same order as the tracks in which selected regions occured */
4277 for (vector<PlaylistMapping>::iterator i = pmap.begin(); i != pmap.end(); ++i) {
4280 foo.push_back ((*i).pl);
4285 cut_buffer->set (foo);
4289 _last_cut_copy_source_track = 0;
4291 _last_cut_copy_source_track = pmap.front().tv;
4295 for (FreezeList::iterator pl = freezelist.begin(); pl != freezelist.end(); ++pl) {
4298 /* We might have removed regions, which alters other regions' layering_index,
4299 so we need to do a recursive diff here.
4301 vector<Command*> cmds;
4302 (*pl)->rdiff (cmds);
4303 _session->add_commands (cmds);
4305 _session->add_command (new StatefulDiffCommand (*pl));
4310 Editor::cut_copy_ranges (CutCopyOp op)
4312 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4314 /* Sort the track selection now, so that it if is used, the playlists
4315 selected by the calls below to cut_copy_clear are in the order that
4316 their tracks appear in the editor. This makes things like paste
4317 of ranges work properly.
4320 sort_track_selection (ts);
4323 if (!entered_track) {
4326 ts.push_back (entered_track);
4329 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4330 (*i)->cut_copy_clear (*selection, op);
4335 Editor::paste (float times, bool from_context)
4337 DEBUG_TRACE (DEBUG::CutNPaste, "paste to preferred edit pos\n");
4339 paste_internal (get_preferred_edit_position (false, from_context), times);
4343 Editor::mouse_paste ()
4348 if (!mouse_frame (where, ignored)) {
4353 paste_internal (where, 1);
4357 Editor::paste_internal (framepos_t position, float times)
4359 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("apparent paste position is %1\n", position));
4361 if (internal_editing()) {
4362 if (cut_buffer->midi_notes.empty()) {
4366 if (cut_buffer->empty()) {
4371 if (position == max_framepos) {
4372 position = get_preferred_edit_position();
4373 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("preferred edit position is %1\n", position));
4377 TrackViewList::iterator i;
4380 /* get everything in the correct order */
4382 if (_edit_point == Editing::EditAtMouse && entered_track) {
4383 /* With the mouse edit point, paste onto the track under the mouse */
4384 ts.push_back (entered_track);
4385 } else if (!selection->tracks.empty()) {
4386 /* Otherwise, if there are some selected tracks, paste to them */
4387 ts = selection->tracks.filter_to_unique_playlists ();
4388 sort_track_selection (ts);
4389 } else if (_last_cut_copy_source_track) {
4390 /* Otherwise paste to the track that the cut/copy came from;
4391 see discussion in mantis #3333.
4393 ts.push_back (_last_cut_copy_source_track);
4396 if (internal_editing ()) {
4398 /* undo/redo is handled by individual tracks/regions */
4400 for (nth = 0, i = ts.begin(); i != ts.end(); ++i, ++nth) {
4403 RegionSelection::iterator r;
4404 MidiNoteSelection::iterator cb;
4406 get_regions_at (rs, position, ts);
4408 for (cb = cut_buffer->midi_notes.begin(), r = rs.begin();
4409 cb != cut_buffer->midi_notes.end() && r != rs.end(); ++r) {
4410 MidiRegionView* mrv = dynamic_cast<MidiRegionView*> (*r);
4412 mrv->paste (position, times, **cb);
4420 /* we do redo (do you do voodoo?) */
4422 begin_reversible_command (Operations::paste);
4424 for (nth = 0, i = ts.begin(); i != ts.end(); ++i, ++nth) {
4425 (*i)->paste (position, times, *cut_buffer, nth);
4428 commit_reversible_command ();
4433 Editor::duplicate_some_regions (RegionSelection& regions, float times)
4435 boost::shared_ptr<Playlist> playlist;
4436 RegionSelection sel = regions; // clear (below) may clear the argument list if its the current region selection
4437 RegionSelection foo;
4439 framepos_t const start_frame = regions.start ();
4440 framepos_t const end_frame = regions.end_frame ();
4442 begin_reversible_command (Operations::duplicate_region);
4444 selection->clear_regions ();
4446 for (RegionSelection::iterator i = sel.begin(); i != sel.end(); ++i) {
4448 boost::shared_ptr<Region> r ((*i)->region());
4450 TimeAxisView& tv = (*i)->get_time_axis_view();
4451 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (&tv);
4452 latest_regionviews.clear ();
4453 sigc::connection c = rtv->view()->RegionViewAdded.connect (sigc::mem_fun(*this, &Editor::collect_new_region_view));
4455 playlist = (*i)->region()->playlist();
4456 playlist->clear_changes ();
4457 playlist->duplicate (r, end_frame + (r->first_frame() - start_frame), times);
4458 _session->add_command(new StatefulDiffCommand (playlist));
4462 foo.insert (foo.end(), latest_regionviews.begin(), latest_regionviews.end());
4465 commit_reversible_command ();
4468 selection->set (foo);
4473 Editor::duplicate_selection (float times)
4475 if (selection->time.empty() || selection->tracks.empty()) {
4479 boost::shared_ptr<Playlist> playlist;
4480 vector<boost::shared_ptr<Region> > new_regions;
4481 vector<boost::shared_ptr<Region> >::iterator ri;
4483 create_region_from_selection (new_regions);
4485 if (new_regions.empty()) {
4489 begin_reversible_command (_("duplicate selection"));
4491 ri = new_regions.begin();
4493 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4495 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4496 if ((playlist = (*i)->playlist()) == 0) {
4499 playlist->clear_changes ();
4500 playlist->duplicate (*ri, selection->time[clicked_selection].end, times);
4501 _session->add_command (new StatefulDiffCommand (playlist));
4504 if (ri == new_regions.end()) {
4509 commit_reversible_command ();
4512 /** Reset all selected points to the relevant default value */
4514 Editor::reset_point_selection ()
4516 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
4517 ARDOUR::AutomationList::iterator j = (*i)->model ();
4518 (*j)->value = (*i)->line().the_list()->default_value ();
4523 Editor::center_playhead ()
4525 float const page = _visible_canvas_width * samples_per_pixel;
4526 center_screen_internal (playhead_cursor->current_frame (), page);
4530 Editor::center_edit_point ()
4532 float const page = _visible_canvas_width * samples_per_pixel;
4533 center_screen_internal (get_preferred_edit_position(), page);
4536 /** Caller must begin and commit a reversible command */
4538 Editor::clear_playlist (boost::shared_ptr<Playlist> playlist)
4540 playlist->clear_changes ();
4542 _session->add_command (new StatefulDiffCommand (playlist));
4546 Editor::nudge_track (bool use_edit, bool forwards)
4548 boost::shared_ptr<Playlist> playlist;
4549 framepos_t distance;
4550 framepos_t next_distance;
4554 start = get_preferred_edit_position();
4559 if ((distance = get_nudge_distance (start, next_distance)) == 0) {
4563 if (selection->tracks.empty()) {
4567 begin_reversible_command (_("nudge track"));
4569 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4571 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4573 if ((playlist = (*i)->playlist()) == 0) {
4577 playlist->clear_changes ();
4578 playlist->clear_owned_changes ();
4580 playlist->nudge_after (start, distance, forwards);
4582 vector<Command*> cmds;
4584 playlist->rdiff (cmds);
4585 _session->add_commands (cmds);
4587 _session->add_command (new StatefulDiffCommand (playlist));
4590 commit_reversible_command ();
4594 Editor::remove_last_capture ()
4596 vector<string> choices;
4603 if (Config->get_verify_remove_last_capture()) {
4604 prompt = _("Do you really want to destroy the last capture?"
4605 "\n(This is destructive and cannot be undone)");
4607 choices.push_back (_("No, do nothing."));
4608 choices.push_back (_("Yes, destroy it."));
4610 Gtkmm2ext::Choice prompter (_("Destroy last capture"), prompt, choices);
4612 if (prompter.run () == 1) {
4613 _session->remove_last_capture ();
4614 _regions->redisplay ();
4618 _session->remove_last_capture();
4619 _regions->redisplay ();
4624 Editor::normalize_region ()
4630 RegionSelection rs = get_regions_from_selection_and_entered ();
4636 NormalizeDialog dialog (rs.size() > 1);
4638 if (dialog.run () == RESPONSE_CANCEL) {
4642 set_canvas_cursor (_cursors->wait);
4645 /* XXX: should really only count audio regions here */
4646 int const regions = rs.size ();
4648 /* Make a list of the selected audio regions' maximum amplitudes, and also
4649 obtain the maximum amplitude of them all.
4651 list<double> max_amps;
4653 for (RegionSelection::const_iterator i = rs.begin(); i != rs.end(); ++i) {
4654 AudioRegionView const * arv = dynamic_cast<AudioRegionView const *> (*i);
4656 dialog.descend (1.0 / regions);
4657 double const a = arv->audio_region()->maximum_amplitude (&dialog);
4660 /* the user cancelled the operation */
4661 set_canvas_cursor (current_canvas_cursor);
4665 max_amps.push_back (a);
4666 max_amp = max (max_amp, a);
4671 begin_reversible_command (_("normalize"));
4673 list<double>::const_iterator a = max_amps.begin ();
4675 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
4676 AudioRegionView* const arv = dynamic_cast<AudioRegionView*> (*r);
4681 arv->region()->clear_changes ();
4683 double const amp = dialog.normalize_individually() ? *a : max_amp;
4685 arv->audio_region()->normalize (amp, dialog.target ());
4686 _session->add_command (new StatefulDiffCommand (arv->region()));
4691 commit_reversible_command ();
4692 set_canvas_cursor (current_canvas_cursor);
4697 Editor::reset_region_scale_amplitude ()
4703 RegionSelection rs = get_regions_from_selection_and_entered ();
4709 begin_reversible_command ("reset gain");
4711 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
4712 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
4715 arv->region()->clear_changes ();
4716 arv->audio_region()->set_scale_amplitude (1.0f);
4717 _session->add_command (new StatefulDiffCommand (arv->region()));
4720 commit_reversible_command ();
4724 Editor::adjust_region_gain (bool up)
4726 RegionSelection rs = get_regions_from_selection_and_entered ();
4728 if (!_session || rs.empty()) {
4732 begin_reversible_command ("adjust region gain");
4734 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
4735 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
4740 arv->region()->clear_changes ();
4742 double dB = accurate_coefficient_to_dB (arv->audio_region()->scale_amplitude ());
4750 arv->audio_region()->set_scale_amplitude (dB_to_coefficient (dB));
4751 _session->add_command (new StatefulDiffCommand (arv->region()));
4754 commit_reversible_command ();
4759 Editor::reverse_region ()
4765 Reverse rev (*_session);
4766 apply_filter (rev, _("reverse regions"));
4770 Editor::strip_region_silence ()
4776 RegionSelection rs = get_regions_from_selection_and_entered ();
4782 std::list<RegionView*> audio_only;
4784 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
4785 AudioRegionView* const arv = dynamic_cast<AudioRegionView*> (*i);
4787 audio_only.push_back (arv);
4791 StripSilenceDialog d (_session, audio_only);
4792 int const r = d.run ();
4796 if (r == Gtk::RESPONSE_OK) {
4797 ARDOUR::AudioIntervalMap silences;
4798 d.silences (silences);
4799 StripSilence s (*_session, silences, d.fade_length());
4800 apply_filter (s, _("strip silence"), &d);
4805 Editor::apply_midi_note_edit_op_to_region (MidiOperator& op, MidiRegionView& mrv)
4807 Evoral::Sequence<Evoral::MusicalTime>::Notes selected;
4808 mrv.selection_as_notelist (selected, true);
4810 vector<Evoral::Sequence<Evoral::MusicalTime>::Notes> v;
4811 v.push_back (selected);
4813 framepos_t pos_frames = mrv.midi_region()->position() - mrv.midi_region()->start();
4814 double pos_beats = _session->tempo_map().framewalk_to_beats(0, pos_frames);
4816 return op (mrv.midi_region()->model(), pos_beats, v);
4820 Editor::apply_midi_note_edit_op (MidiOperator& op)
4824 RegionSelection rs = get_regions_from_selection_and_entered ();
4830 begin_reversible_command (op.name ());
4832 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
4833 RegionSelection::iterator tmp = r;
4836 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*r);
4839 cmd = apply_midi_note_edit_op_to_region (op, *mrv);
4842 _session->add_command (cmd);
4849 commit_reversible_command ();
4853 Editor::fork_region ()
4855 RegionSelection rs = get_regions_from_selection_and_entered ();
4861 begin_reversible_command (_("Fork Region(s)"));
4863 set_canvas_cursor (_cursors->wait);
4866 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
4867 RegionSelection::iterator tmp = r;
4870 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*>(*r);
4874 boost::shared_ptr<Playlist> playlist = mrv->region()->playlist();
4875 boost::shared_ptr<MidiSource> new_source = _session->create_midi_source_by_stealing_name (mrv->midi_view()->track());
4876 boost::shared_ptr<MidiRegion> newregion = mrv->midi_region()->clone (new_source);
4878 playlist->clear_changes ();
4879 playlist->replace_region (mrv->region(), newregion, mrv->region()->position());
4880 _session->add_command(new StatefulDiffCommand (playlist));
4882 error << string_compose (_("Could not unlink %1"), mrv->region()->name()) << endmsg;
4889 commit_reversible_command ();
4891 set_canvas_cursor (current_canvas_cursor);
4895 Editor::quantize_region ()
4897 int selected_midi_region_cnt = 0;
4903 RegionSelection rs = get_regions_from_selection_and_entered ();
4909 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
4910 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*r);
4912 selected_midi_region_cnt++;
4916 if (selected_midi_region_cnt == 0) {
4920 QuantizeDialog* qd = new QuantizeDialog (*this);
4923 const int r = qd->run ();
4926 if (r == Gtk::RESPONSE_OK) {
4927 Quantize quant (*_session, qd->snap_start(), qd->snap_end(),
4928 qd->start_grid_size(), qd->end_grid_size(),
4929 qd->strength(), qd->swing(), qd->threshold());
4931 apply_midi_note_edit_op (quant);
4936 Editor::insert_patch_change (bool from_context)
4938 RegionSelection rs = get_regions_from_selection_and_entered ();
4944 const framepos_t p = get_preferred_edit_position (false, from_context);
4946 /* XXX: bit of a hack; use the MIDNAM from the first selected region;
4947 there may be more than one, but the PatchChangeDialog can only offer
4948 one set of patch menus.
4950 MidiRegionView* first = dynamic_cast<MidiRegionView*> (rs.front ());
4952 Evoral::PatchChange<Evoral::MusicalTime> empty (0, 0, 0, 0);
4953 PatchChangeDialog d (0, _session, empty, first->instrument_info(), Gtk::Stock::ADD);
4955 if (d.run() == RESPONSE_CANCEL) {
4959 for (RegionSelection::iterator i = rs.begin (); i != rs.end(); ++i) {
4960 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*i);
4962 if (p >= mrv->region()->first_frame() && p <= mrv->region()->last_frame()) {
4963 mrv->add_patch_change (p - mrv->region()->position(), d.patch ());
4970 Editor::apply_filter (Filter& filter, string command, ProgressReporter* progress)
4972 RegionSelection rs = get_regions_from_selection_and_entered ();
4978 begin_reversible_command (command);
4980 set_canvas_cursor (_cursors->wait);
4984 int const N = rs.size ();
4986 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
4987 RegionSelection::iterator tmp = r;
4990 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
4992 boost::shared_ptr<Playlist> playlist = arv->region()->playlist();
4995 progress->descend (1.0 / N);
4998 if (arv->audio_region()->apply (filter, progress) == 0) {
5000 playlist->clear_changes ();
5001 playlist->clear_owned_changes ();
5003 if (filter.results.empty ()) {
5005 /* no regions returned; remove the old one */
5006 playlist->remove_region (arv->region ());
5010 std::vector<boost::shared_ptr<Region> >::iterator res = filter.results.begin ();
5012 /* first region replaces the old one */
5013 playlist->replace_region (arv->region(), *res, (*res)->position());
5017 while (res != filter.results.end()) {
5018 playlist->add_region (*res, (*res)->position());
5024 /* We might have removed regions, which alters other regions' layering_index,
5025 so we need to do a recursive diff here.
5027 vector<Command*> cmds;
5028 playlist->rdiff (cmds);
5029 _session->add_commands (cmds);
5031 _session->add_command(new StatefulDiffCommand (playlist));
5037 progress->ascend ();
5045 commit_reversible_command ();
5048 set_canvas_cursor (current_canvas_cursor);
5052 Editor::external_edit_region ()
5058 Editor::reset_region_gain_envelopes ()
5060 RegionSelection rs = get_regions_from_selection_and_entered ();
5062 if (!_session || rs.empty()) {
5066 _session->begin_reversible_command (_("reset region gain"));
5068 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5069 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
5071 boost::shared_ptr<AutomationList> alist (arv->audio_region()->envelope());
5072 XMLNode& before (alist->get_state());
5074 arv->audio_region()->set_default_envelope ();
5075 _session->add_command (new MementoCommand<AutomationList>(*arv->audio_region()->envelope().get(), &before, &alist->get_state()));
5079 _session->commit_reversible_command ();
5083 Editor::set_region_gain_visibility (RegionView* rv)
5085 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (rv);
5087 arv->update_envelope_visibility();
5092 Editor::set_gain_envelope_visibility ()
5098 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5099 AudioTimeAxisView* v = dynamic_cast<AudioTimeAxisView*>(*i);
5101 v->audio_view()->foreach_regionview (sigc::mem_fun (this, &Editor::set_region_gain_visibility));
5107 Editor::toggle_gain_envelope_active ()
5109 if (_ignore_region_action) {
5113 RegionSelection rs = get_regions_from_selection_and_entered ();
5115 if (!_session || rs.empty()) {
5119 _session->begin_reversible_command (_("region gain envelope active"));
5121 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5122 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
5124 arv->region()->clear_changes ();
5125 arv->audio_region()->set_envelope_active (!arv->audio_region()->envelope_active());
5126 _session->add_command (new StatefulDiffCommand (arv->region()));
5130 _session->commit_reversible_command ();
5134 Editor::toggle_region_lock ()
5136 if (_ignore_region_action) {
5140 RegionSelection rs = get_regions_from_selection_and_entered ();
5142 if (!_session || rs.empty()) {
5146 _session->begin_reversible_command (_("toggle region lock"));
5148 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5149 (*i)->region()->clear_changes ();
5150 (*i)->region()->set_locked (!(*i)->region()->locked());
5151 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5154 _session->commit_reversible_command ();
5158 Editor::toggle_region_video_lock ()
5160 if (_ignore_region_action) {
5164 RegionSelection rs = get_regions_from_selection_and_entered ();
5166 if (!_session || rs.empty()) {
5170 _session->begin_reversible_command (_("Toggle Video Lock"));
5172 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5173 (*i)->region()->clear_changes ();
5174 (*i)->region()->set_video_locked (!(*i)->region()->video_locked());
5175 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5178 _session->commit_reversible_command ();
5182 Editor::toggle_region_lock_style ()
5184 if (_ignore_region_action) {
5188 RegionSelection rs = get_regions_from_selection_and_entered ();
5190 if (!_session || rs.empty()) {
5194 _session->begin_reversible_command (_("region lock style"));
5196 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5197 (*i)->region()->clear_changes ();
5198 PositionLockStyle const ns = (*i)->region()->position_lock_style() == AudioTime ? MusicTime : AudioTime;
5199 (*i)->region()->set_position_lock_style (ns);
5200 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5203 _session->commit_reversible_command ();
5207 Editor::toggle_opaque_region ()
5209 if (_ignore_region_action) {
5213 RegionSelection rs = get_regions_from_selection_and_entered ();
5215 if (!_session || rs.empty()) {
5219 _session->begin_reversible_command (_("change region opacity"));
5221 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5222 (*i)->region()->clear_changes ();
5223 (*i)->region()->set_opaque (!(*i)->region()->opaque());
5224 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5227 _session->commit_reversible_command ();
5231 Editor::toggle_record_enable ()
5233 bool new_state = false;
5235 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5236 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5239 if (!rtav->is_track())
5243 new_state = !rtav->track()->record_enabled();
5247 rtav->track()->set_record_enabled (new_state, this);
5252 Editor::toggle_solo ()
5254 bool new_state = false;
5256 boost::shared_ptr<RouteList> rl (new RouteList);
5258 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5259 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5266 new_state = !rtav->route()->soloed ();
5270 rl->push_back (rtav->route());
5273 _session->set_solo (rl, new_state, Session::rt_cleanup, true);
5277 Editor::toggle_mute ()
5279 bool new_state = false;
5281 boost::shared_ptr<RouteList> rl (new RouteList);
5283 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5284 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5291 new_state = !rtav->route()->muted();
5295 rl->push_back (rtav->route());
5298 _session->set_mute (rl, new_state, Session::rt_cleanup, true);
5302 Editor::toggle_solo_isolate ()
5307 Editor::set_fade_length (bool in)
5309 RegionSelection rs = get_regions_from_selection_and_entered ();
5315 /* we need a region to measure the offset from the start */
5317 RegionView* rv = rs.front ();
5319 framepos_t pos = get_preferred_edit_position();
5323 if (pos > rv->region()->last_frame() || pos < rv->region()->first_frame()) {
5324 /* edit point is outside the relevant region */
5329 if (pos <= rv->region()->position()) {
5333 len = pos - rv->region()->position();
5334 cmd = _("set fade in length");
5336 if (pos >= rv->region()->last_frame()) {
5340 len = rv->region()->last_frame() - pos;
5341 cmd = _("set fade out length");
5344 begin_reversible_command (cmd);
5346 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5347 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5353 boost::shared_ptr<AutomationList> alist;
5355 alist = tmp->audio_region()->fade_in();
5357 alist = tmp->audio_region()->fade_out();
5360 XMLNode &before = alist->get_state();
5363 tmp->audio_region()->set_fade_in_length (len);
5364 tmp->audio_region()->set_fade_in_active (true);
5366 tmp->audio_region()->set_fade_out_length (len);
5367 tmp->audio_region()->set_fade_out_active (true);
5370 XMLNode &after = alist->get_state();
5371 _session->add_command(new MementoCommand<AutomationList>(*alist, &before, &after));
5374 commit_reversible_command ();
5378 Editor::set_fade_in_shape (FadeShape shape)
5380 RegionSelection rs = get_regions_from_selection_and_entered ();
5386 begin_reversible_command (_("set fade in shape"));
5388 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5389 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5395 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_in();
5396 XMLNode &before = alist->get_state();
5398 tmp->audio_region()->set_fade_in_shape (shape);
5400 XMLNode &after = alist->get_state();
5401 _session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
5404 commit_reversible_command ();
5409 Editor::set_fade_out_shape (FadeShape shape)
5411 RegionSelection rs = get_regions_from_selection_and_entered ();
5417 begin_reversible_command (_("set fade out shape"));
5419 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5420 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5426 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_out();
5427 XMLNode &before = alist->get_state();
5429 tmp->audio_region()->set_fade_out_shape (shape);
5431 XMLNode &after = alist->get_state();
5432 _session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
5435 commit_reversible_command ();
5439 Editor::set_fade_in_active (bool yn)
5441 RegionSelection rs = get_regions_from_selection_and_entered ();
5447 begin_reversible_command (_("set fade in active"));
5449 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5450 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5457 boost::shared_ptr<AudioRegion> ar (tmp->audio_region());
5459 ar->clear_changes ();
5460 ar->set_fade_in_active (yn);
5461 _session->add_command (new StatefulDiffCommand (ar));
5464 commit_reversible_command ();
5468 Editor::set_fade_out_active (bool yn)
5470 RegionSelection rs = get_regions_from_selection_and_entered ();
5476 begin_reversible_command (_("set fade out active"));
5478 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5479 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5485 boost::shared_ptr<AudioRegion> ar (tmp->audio_region());
5487 ar->clear_changes ();
5488 ar->set_fade_out_active (yn);
5489 _session->add_command(new StatefulDiffCommand (ar));
5492 commit_reversible_command ();
5496 Editor::toggle_region_fades (int dir)
5498 if (_ignore_region_action) {
5502 boost::shared_ptr<AudioRegion> ar;
5505 RegionSelection rs = get_regions_from_selection_and_entered ();
5511 RegionSelection::iterator i;
5512 for (i = rs.begin(); i != rs.end(); ++i) {
5513 if ((ar = boost::dynamic_pointer_cast<AudioRegion>((*i)->region())) != 0) {
5515 yn = ar->fade_out_active ();
5517 yn = ar->fade_in_active ();
5523 if (i == rs.end()) {
5527 /* XXX should this undo-able? */
5529 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5530 if ((ar = boost::dynamic_pointer_cast<AudioRegion>((*i)->region())) == 0) {
5533 if (dir == 1 || dir == 0) {
5534 ar->set_fade_in_active (!yn);
5537 if (dir == -1 || dir == 0) {
5538 ar->set_fade_out_active (!yn);
5544 /** Update region fade visibility after its configuration has been changed */
5546 Editor::update_region_fade_visibility ()
5548 bool _fade_visibility = _session->config.get_show_region_fades ();
5550 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5551 AudioTimeAxisView* v = dynamic_cast<AudioTimeAxisView*>(*i);
5553 if (_fade_visibility) {
5554 v->audio_view()->show_all_fades ();
5556 v->audio_view()->hide_all_fades ();
5563 Editor::set_edit_point ()
5568 if (!mouse_frame (where, ignored)) {
5574 if (selection->markers.empty()) {
5576 mouse_add_new_marker (where);
5581 Location* loc = find_location_from_marker (selection->markers.front(), ignored);
5584 loc->move_to (where);
5590 Editor::set_playhead_cursor ()
5592 if (entered_marker) {
5593 _session->request_locate (entered_marker->position(), _session->transport_rolling());
5598 if (!mouse_frame (where, ignored)) {
5605 _session->request_locate (where, _session->transport_rolling());
5609 if ( Config->get_always_play_range() )
5610 cancel_time_selection();
5614 Editor::split_region ()
5616 if ( !selection->time.empty()) {
5617 separate_regions_between (selection->time);
5621 RegionSelection rs = get_regions_from_selection_and_edit_point ();
5623 framepos_t where = get_preferred_edit_position ();
5629 split_regions_at (where, rs);
5632 struct EditorOrderRouteSorter {
5633 bool operator() (boost::shared_ptr<Route> a, boost::shared_ptr<Route> b) {
5634 return a->order_key () < b->order_key ();
5639 Editor::select_next_route()
5641 if (selection->tracks.empty()) {
5642 selection->set (track_views.front());
5646 TimeAxisView* current = selection->tracks.front();
5650 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5651 if (*i == current) {
5653 if (i != track_views.end()) {
5656 current = (*(track_views.begin()));
5657 //selection->set (*(track_views.begin()));
5662 rui = dynamic_cast<RouteUI *>(current);
5663 } while ( current->hidden() || (rui != NULL && !rui->route()->active()));
5665 selection->set(current);
5667 ensure_track_visible(current);
5671 Editor::select_prev_route()
5673 if (selection->tracks.empty()) {
5674 selection->set (track_views.front());
5678 TimeAxisView* current = selection->tracks.front();
5682 for (TrackViewList::reverse_iterator i = track_views.rbegin(); i != track_views.rend(); ++i) {
5683 if (*i == current) {
5685 if (i != track_views.rend()) {
5688 current = *(track_views.rbegin());
5693 rui = dynamic_cast<RouteUI *>(current);
5694 } while ( current->hidden() || (rui != NULL && !rui->route()->active()));
5696 selection->set (current);
5698 ensure_track_visible(current);
5702 Editor::ensure_track_visible(TimeAxisView *track)
5704 if (track->hidden())
5707 double const current_view_min_y = vertical_adjustment.get_value();
5708 double const current_view_max_y = vertical_adjustment.get_value() + vertical_adjustment.get_page_size();
5710 double const track_min_y = track->y_position ();
5711 double const track_max_y = track->y_position () + track->effective_height ();
5713 if (track_min_y >= current_view_min_y &&
5714 track_max_y <= current_view_max_y) {
5720 if (track_min_y < current_view_min_y) {
5721 // Track is above the current view
5722 new_value = track_min_y;
5724 // Track is below the current view
5725 new_value = track->y_position () + track->effective_height() - vertical_adjustment.get_page_size();
5728 vertical_adjustment.set_value(new_value);
5732 Editor::set_loop_from_selection (bool play)
5734 if (_session == 0 || selection->time.empty()) {
5738 framepos_t start = selection->time[clicked_selection].start;
5739 framepos_t end = selection->time[clicked_selection].end;
5741 set_loop_range (start, end, _("set loop range from selection"));
5744 _session->request_play_loop (true);
5745 _session->request_locate (start, true);
5750 Editor::set_loop_from_edit_range (bool play)
5752 if (_session == 0) {
5759 if (!get_edit_op_range (start, end)) {
5763 set_loop_range (start, end, _("set loop range from edit range"));
5766 _session->request_play_loop (true);
5767 _session->request_locate (start, true);
5772 Editor::set_loop_from_region (bool play)
5774 framepos_t start = max_framepos;
5777 RegionSelection rs = get_regions_from_selection_and_entered ();
5783 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5784 if ((*i)->region()->position() < start) {
5785 start = (*i)->region()->position();
5787 if ((*i)->region()->last_frame() + 1 > end) {
5788 end = (*i)->region()->last_frame() + 1;
5792 set_loop_range (start, end, _("set loop range from region"));
5795 _session->request_play_loop (true);
5796 _session->request_locate (start, true);
5801 Editor::set_punch_from_selection ()
5803 if (_session == 0 || selection->time.empty()) {
5807 framepos_t start = selection->time[clicked_selection].start;
5808 framepos_t end = selection->time[clicked_selection].end;
5810 set_punch_range (start, end, _("set punch range from selection"));
5814 Editor::set_punch_from_edit_range ()
5816 if (_session == 0) {
5823 if (!get_edit_op_range (start, end)) {
5827 set_punch_range (start, end, _("set punch range from edit range"));
5831 Editor::set_punch_from_region ()
5833 framepos_t start = max_framepos;
5836 RegionSelection rs = get_regions_from_selection_and_entered ();
5842 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5843 if ((*i)->region()->position() < start) {
5844 start = (*i)->region()->position();
5846 if ((*i)->region()->last_frame() + 1 > end) {
5847 end = (*i)->region()->last_frame() + 1;
5851 set_punch_range (start, end, _("set punch range from region"));
5855 Editor::pitch_shift_region ()
5857 RegionSelection rs = get_regions_from_selection_and_entered ();
5859 RegionSelection audio_rs;
5860 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5861 if (dynamic_cast<AudioRegionView*> (*i)) {
5862 audio_rs.push_back (*i);
5866 if (audio_rs.empty()) {
5870 pitch_shift (audio_rs, 1.2);
5874 Editor::transpose_region ()
5876 RegionSelection rs = get_regions_from_selection_and_entered ();
5878 list<MidiRegionView*> midi_region_views;
5879 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5880 MidiRegionView* mrv = dynamic_cast<MidiRegionView*> (*i);
5882 midi_region_views.push_back (mrv);
5887 int const r = d.run ();
5888 if (r != RESPONSE_ACCEPT) {
5892 for (list<MidiRegionView*>::iterator i = midi_region_views.begin(); i != midi_region_views.end(); ++i) {
5893 (*i)->midi_region()->transpose (d.semitones ());
5898 Editor::set_tempo_from_region ()
5900 RegionSelection rs = get_regions_from_selection_and_entered ();
5902 if (!_session || rs.empty()) {
5906 RegionView* rv = rs.front();
5908 define_one_bar (rv->region()->position(), rv->region()->last_frame() + 1);
5912 Editor::use_range_as_bar ()
5914 framepos_t start, end;
5915 if (get_edit_op_range (start, end)) {
5916 define_one_bar (start, end);
5921 Editor::define_one_bar (framepos_t start, framepos_t end)
5923 framepos_t length = end - start;
5925 const Meter& m (_session->tempo_map().meter_at (start));
5927 /* length = 1 bar */
5929 /* now we want frames per beat.
5930 we have frames per bar, and beats per bar, so ...
5933 /* XXXX METER MATH */
5935 double frames_per_beat = length / m.divisions_per_bar();
5937 /* beats per minute = */
5939 double beats_per_minute = (_session->frame_rate() * 60.0) / frames_per_beat;
5941 /* now decide whether to:
5943 (a) set global tempo
5944 (b) add a new tempo marker
5948 const TempoSection& t (_session->tempo_map().tempo_section_at (start));
5950 bool do_global = false;
5952 if ((_session->tempo_map().n_tempos() == 1) && (_session->tempo_map().n_meters() == 1)) {
5954 /* only 1 tempo & 1 meter: ask if the user wants to set the tempo
5955 at the start, or create a new marker
5958 vector<string> options;
5959 options.push_back (_("Cancel"));
5960 options.push_back (_("Add new marker"));
5961 options.push_back (_("Set global tempo"));
5964 _("Define one bar"),
5965 _("Do you want to set the global tempo or add a new tempo marker?"),
5969 c.set_default_response (2);
5985 /* more than 1 tempo and/or meter section already, go ahead do the "usual":
5986 if the marker is at the region starter, change it, otherwise add
5991 begin_reversible_command (_("set tempo from region"));
5992 XMLNode& before (_session->tempo_map().get_state());
5995 _session->tempo_map().change_initial_tempo (beats_per_minute, t.note_type());
5996 } else if (t.frame() == start) {
5997 _session->tempo_map().change_existing_tempo_at (start, beats_per_minute, t.note_type());
5999 Timecode::BBT_Time bbt;
6000 _session->tempo_map().bbt_time (start, bbt);
6001 _session->tempo_map().add_tempo (Tempo (beats_per_minute, t.note_type()), bbt);
6004 XMLNode& after (_session->tempo_map().get_state());
6006 _session->add_command (new MementoCommand<TempoMap>(_session->tempo_map(), &before, &after));
6007 commit_reversible_command ();
6011 Editor::split_region_at_transients ()
6013 AnalysisFeatureList positions;
6015 RegionSelection rs = get_regions_from_selection_and_entered ();
6017 if (!_session || rs.empty()) {
6021 _session->begin_reversible_command (_("split regions"));
6023 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ) {
6025 RegionSelection::iterator tmp;
6030 boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion> ((*i)->region());
6032 if (ar && (ar->get_transients (positions) == 0)) {
6033 split_region_at_points ((*i)->region(), positions, true);
6040 _session->commit_reversible_command ();
6045 Editor::split_region_at_points (boost::shared_ptr<Region> r, AnalysisFeatureList& positions, bool can_ferret, bool select_new)
6047 bool use_rhythmic_rodent = false;
6049 boost::shared_ptr<Playlist> pl = r->playlist();
6051 list<boost::shared_ptr<Region> > new_regions;
6057 if (positions.empty()) {
6062 if (positions.size() > 20 && can_ferret) {
6063 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);
6064 MessageDialog msg (msgstr,
6067 Gtk::BUTTONS_OK_CANCEL);
6070 msg.add_button (_("Call for the Ferret!"), RESPONSE_APPLY);
6071 msg.set_secondary_text (_("Press OK to continue with this split operation\nor ask the Ferret dialog to tune the analysis"));
6073 msg.set_secondary_text (_("Press OK to continue with this split operation"));
6076 msg.set_title (_("Excessive split?"));
6079 int response = msg.run();
6085 case RESPONSE_APPLY:
6086 use_rhythmic_rodent = true;
6093 if (use_rhythmic_rodent) {
6094 show_rhythm_ferret ();
6098 AnalysisFeatureList::const_iterator x;
6100 pl->clear_changes ();
6101 pl->clear_owned_changes ();
6103 x = positions.begin();
6105 if (x == positions.end()) {
6110 pl->remove_region (r);
6114 while (x != positions.end()) {
6116 /* deal with positons that are out of scope of present region bounds */
6117 if (*x <= 0 || *x > r->length()) {
6122 /* file start = original start + how far we from the initial position ?
6125 framepos_t file_start = r->start() + pos;
6127 /* length = next position - current position
6130 framepos_t len = (*x) - pos;
6132 /* XXX we do we really want to allow even single-sample regions?
6133 shouldn't we have some kind of lower limit on region size?
6142 if (RegionFactory::region_name (new_name, r->name())) {
6146 /* do NOT announce new regions 1 by one, just wait till they are all done */
6150 plist.add (ARDOUR::Properties::start, file_start);
6151 plist.add (ARDOUR::Properties::length, len);
6152 plist.add (ARDOUR::Properties::name, new_name);
6153 plist.add (ARDOUR::Properties::layer, 0);
6155 boost::shared_ptr<Region> nr = RegionFactory::create (r->sources(), plist, false);
6156 /* because we set annouce to false, manually add the new region to the
6159 RegionFactory::map_add (nr);
6161 pl->add_region (nr, r->position() + pos);
6164 new_regions.push_front(nr);
6173 RegionFactory::region_name (new_name, r->name());
6175 /* Add the final region */
6178 plist.add (ARDOUR::Properties::start, r->start() + pos);
6179 plist.add (ARDOUR::Properties::length, r->last_frame() - (r->position() + pos) + 1);
6180 plist.add (ARDOUR::Properties::name, new_name);
6181 plist.add (ARDOUR::Properties::layer, 0);
6183 boost::shared_ptr<Region> nr = RegionFactory::create (r->sources(), plist, false);
6184 /* because we set annouce to false, manually add the new region to the
6187 RegionFactory::map_add (nr);
6188 pl->add_region (nr, r->position() + pos);
6191 new_regions.push_front(nr);
6196 /* We might have removed regions, which alters other regions' layering_index,
6197 so we need to do a recursive diff here.
6199 vector<Command*> cmds;
6201 _session->add_commands (cmds);
6203 _session->add_command (new StatefulDiffCommand (pl));
6207 for (list<boost::shared_ptr<Region> >::iterator i = new_regions.begin(); i != new_regions.end(); ++i){
6208 set_selected_regionview_from_region_list ((*i), Selection::Add);
6214 Editor::place_transient()
6220 RegionSelection rs = get_regions_from_selection_and_edit_point ();
6226 framepos_t where = get_preferred_edit_position();
6228 _session->begin_reversible_command (_("place transient"));
6230 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6231 framepos_t position = (*r)->region()->position();
6232 (*r)->region()->add_transient(where - position);
6235 _session->commit_reversible_command ();
6239 Editor::remove_transient(ArdourCanvas::Item* item)
6245 ArdourCanvas::Line* _line = reinterpret_cast<ArdourCanvas::Line*> (item);
6248 AudioRegionView* _arv = reinterpret_cast<AudioRegionView*> (item->get_data ("regionview"));
6249 _arv->remove_transient (*(float*) _line->get_data ("position"));
6253 Editor::snap_regions_to_grid ()
6255 list <boost::shared_ptr<Playlist > > used_playlists;
6257 RegionSelection rs = get_regions_from_selection_and_entered ();
6259 if (!_session || rs.empty()) {
6263 _session->begin_reversible_command (_("snap regions to grid"));
6265 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6267 boost::shared_ptr<Playlist> pl = (*r)->region()->playlist();
6269 if (!pl->frozen()) {
6270 /* we haven't seen this playlist before */
6272 /* remember used playlists so we can thaw them later */
6273 used_playlists.push_back(pl);
6277 framepos_t start_frame = (*r)->region()->first_frame ();
6278 snap_to (start_frame);
6279 (*r)->region()->set_position (start_frame);
6282 while (used_playlists.size() > 0) {
6283 list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
6285 used_playlists.pop_front();
6288 _session->commit_reversible_command ();
6292 Editor::close_region_gaps ()
6294 list <boost::shared_ptr<Playlist > > used_playlists;
6296 RegionSelection rs = get_regions_from_selection_and_entered ();
6298 if (!_session || rs.empty()) {
6302 Dialog dialog (_("Close Region Gaps"));
6305 table.set_spacings (12);
6306 table.set_border_width (12);
6307 Label* l = manage (left_aligned_label (_("Crossfade length")));
6308 table.attach (*l, 0, 1, 0, 1);
6310 SpinButton spin_crossfade (1, 0);
6311 spin_crossfade.set_range (0, 15);
6312 spin_crossfade.set_increments (1, 1);
6313 spin_crossfade.set_value (5);
6314 table.attach (spin_crossfade, 1, 2, 0, 1);
6316 table.attach (*manage (new Label (_("ms"))), 2, 3, 0, 1);
6318 l = manage (left_aligned_label (_("Pull-back length")));
6319 table.attach (*l, 0, 1, 1, 2);
6321 SpinButton spin_pullback (1, 0);
6322 spin_pullback.set_range (0, 100);
6323 spin_pullback.set_increments (1, 1);
6324 spin_pullback.set_value(30);
6325 table.attach (spin_pullback, 1, 2, 1, 2);
6327 table.attach (*manage (new Label (_("ms"))), 2, 3, 1, 2);
6329 dialog.get_vbox()->pack_start (table);
6330 dialog.add_button (Stock::CANCEL, RESPONSE_CANCEL);
6331 dialog.add_button (_("Ok"), RESPONSE_ACCEPT);
6334 if (dialog.run () == RESPONSE_CANCEL) {
6338 framepos_t crossfade_len = spin_crossfade.get_value();
6339 framepos_t pull_back_frames = spin_pullback.get_value();
6341 crossfade_len = lrintf (crossfade_len * _session->frame_rate()/1000);
6342 pull_back_frames = lrintf (pull_back_frames * _session->frame_rate()/1000);
6344 /* Iterate over the region list and make adjacent regions overlap by crossfade_len_ms */
6346 _session->begin_reversible_command (_("close region gaps"));
6349 boost::shared_ptr<Region> last_region;
6351 rs.sort_by_position_and_track();
6353 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6355 boost::shared_ptr<Playlist> pl = (*r)->region()->playlist();
6357 if (!pl->frozen()) {
6358 /* we haven't seen this playlist before */
6360 /* remember used playlists so we can thaw them later */
6361 used_playlists.push_back(pl);
6365 framepos_t position = (*r)->region()->position();
6367 if (idx == 0 || position < last_region->position()){
6368 last_region = (*r)->region();
6373 (*r)->region()->trim_front( (position - pull_back_frames));
6374 last_region->trim_end( (position - pull_back_frames + crossfade_len));
6376 last_region = (*r)->region();
6381 while (used_playlists.size() > 0) {
6382 list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
6384 used_playlists.pop_front();
6387 _session->commit_reversible_command ();
6391 Editor::tab_to_transient (bool forward)
6393 AnalysisFeatureList positions;
6395 RegionSelection rs = get_regions_from_selection_and_entered ();
6401 framepos_t pos = _session->audible_frame ();
6403 if (!selection->tracks.empty()) {
6405 /* don't waste time searching for transients in duplicate playlists.
6408 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
6410 for (TrackViewList::iterator t = ts.begin(); t != ts.end(); ++t) {
6412 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*t);
6415 boost::shared_ptr<Track> tr = rtv->track();
6417 boost::shared_ptr<Playlist> pl = tr->playlist ();
6419 framepos_t result = pl->find_next_transient (pos, forward ? 1 : -1);
6422 positions.push_back (result);
6435 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6436 (*r)->region()->get_transients (positions);
6440 TransientDetector::cleanup_transients (positions, _session->frame_rate(), 3.0);
6443 AnalysisFeatureList::iterator x;
6445 for (x = positions.begin(); x != positions.end(); ++x) {
6451 if (x != positions.end ()) {
6452 _session->request_locate (*x);
6456 AnalysisFeatureList::reverse_iterator x;
6458 for (x = positions.rbegin(); x != positions.rend(); ++x) {
6464 if (x != positions.rend ()) {
6465 _session->request_locate (*x);
6471 Editor::playhead_forward_to_grid ()
6477 framepos_t pos = playhead_cursor->current_frame ();
6478 if (pos < max_framepos - 1) {
6480 snap_to_internal (pos, 1, false);
6481 _session->request_locate (pos);
6487 Editor::playhead_backward_to_grid ()
6493 framepos_t pos = playhead_cursor->current_frame ();
6496 snap_to_internal (pos, -1, false);
6497 _session->request_locate (pos);
6502 Editor::set_track_height (Height h)
6504 TrackSelection& ts (selection->tracks);
6506 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
6507 (*x)->set_height_enum (h);
6512 Editor::toggle_tracks_active ()
6514 TrackSelection& ts (selection->tracks);
6516 bool target = false;
6522 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
6523 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*x);
6527 target = !rtv->_route->active();
6530 rtv->_route->set_active (target, this);
6536 Editor::remove_tracks ()
6538 TrackSelection& ts (selection->tracks);
6544 vector<string> choices;
6548 const char* trackstr;
6550 vector<boost::shared_ptr<Route> > routes;
6551 bool special_bus = false;
6553 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
6554 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*x);
6558 if (rtv->is_track()) {
6563 routes.push_back (rtv->_route);
6565 if (rtv->route()->is_master() || rtv->route()->is_monitor()) {
6570 if (special_bus && !Config->get_allow_special_bus_removal()) {
6571 MessageDialog msg (_("That would be bad news ...."),
6575 msg.set_secondary_text (string_compose (_(
6576 "Removing the master or monitor bus is such a bad idea\n\
6577 that %1 is not going to allow it.\n\
6579 If you really want to do this sort of thing\n\
6580 edit your ardour.rc file to set the\n\
6581 \"allow-special-bus-removal\" option to be \"yes\""), PROGRAM_NAME));
6588 if (ntracks + nbusses == 0) {
6593 trackstr = _("tracks");
6595 trackstr = _("track");
6599 busstr = _("busses");
6606 prompt = string_compose (_("Do you really want to remove %1 %2 and %3 %4?\n"
6607 "(You may also lose the playlists associated with the %2)\n\n"
6608 "This action cannot be undone, and the session file will be overwritten!"),
6609 ntracks, trackstr, nbusses, busstr);
6611 prompt = string_compose (_("Do you really want to remove %1 %2?\n"
6612 "(You may also lose the playlists associated with the %2)\n\n"
6613 "This action cannot be undone, and the session file will be overwritten!"),
6616 } else if (nbusses) {
6617 prompt = string_compose (_("Do you really want to remove %1 %2?\n\n"
6618 "This action cannot be undon, and the session file will be overwritten"),
6622 choices.push_back (_("No, do nothing."));
6623 if (ntracks + nbusses > 1) {
6624 choices.push_back (_("Yes, remove them."));
6626 choices.push_back (_("Yes, remove it."));
6631 title = string_compose (_("Remove %1"), trackstr);
6633 title = string_compose (_("Remove %1"), busstr);
6636 Choice prompter (title, prompt, choices);
6638 if (prompter.run () != 1) {
6642 for (vector<boost::shared_ptr<Route> >::iterator x = routes.begin(); x != routes.end(); ++x) {
6643 _session->remove_route (*x);
6648 Editor::do_insert_time ()
6650 if (selection->tracks.empty()) {
6654 InsertTimeDialog d (*this);
6655 int response = d.run ();
6657 if (response != RESPONSE_OK) {
6661 if (d.distance() == 0) {
6665 InsertTimeOption opt = d.intersected_region_action ();
6668 get_preferred_edit_position(),
6674 d.move_glued_markers(),
6675 d.move_locked_markers(),
6681 Editor::insert_time (
6682 framepos_t pos, framecnt_t frames, InsertTimeOption opt,
6683 bool all_playlists, bool ignore_music_glue, bool markers_too, bool glued_markers_too, bool locked_markers_too, bool tempo_too
6686 bool commit = false;
6688 if (Config->get_edit_mode() == Lock) {
6692 begin_reversible_command (_("insert time"));
6694 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
6696 for (TrackViewList::iterator x = ts.begin(); x != ts.end(); ++x) {
6700 /* don't operate on any playlist more than once, which could
6701 * happen if "all playlists" is enabled, but there is more
6702 * than 1 track using playlists "from" a given track.
6705 set<boost::shared_ptr<Playlist> > pl;
6707 if (all_playlists) {
6708 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*x);
6710 vector<boost::shared_ptr<Playlist> > all = _session->playlists->playlists_for_track (rtav->track ());
6711 for (vector<boost::shared_ptr<Playlist> >::iterator p = all.begin(); p != all.end(); ++p) {
6716 if ((*x)->playlist ()) {
6717 pl.insert ((*x)->playlist ());
6721 for (set<boost::shared_ptr<Playlist> >::iterator i = pl.begin(); i != pl.end(); ++i) {
6723 (*i)->clear_changes ();
6724 (*i)->clear_owned_changes ();
6726 if (opt == SplitIntersected) {
6730 (*i)->shift (pos, frames, (opt == MoveIntersected), ignore_music_glue);
6732 vector<Command*> cmds;
6734 _session->add_commands (cmds);
6736 _session->add_command (new StatefulDiffCommand (*i));
6741 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*x);
6743 rtav->route ()->shift (pos, frames);
6751 XMLNode& before (_session->locations()->get_state());
6752 Locations::LocationList copy (_session->locations()->list());
6754 for (Locations::LocationList::iterator i = copy.begin(); i != copy.end(); ++i) {
6756 Locations::LocationList::const_iterator tmp;
6758 bool const was_locked = (*i)->locked ();
6759 if (locked_markers_too) {
6763 if ((*i)->position_lock_style() == AudioTime || glued_markers_too) {
6765 if ((*i)->start() >= pos) {
6766 (*i)->set_start ((*i)->start() + frames);
6767 if (!(*i)->is_mark()) {
6768 (*i)->set_end ((*i)->end() + frames);
6781 XMLNode& after (_session->locations()->get_state());
6782 _session->add_command (new MementoCommand<Locations>(*_session->locations(), &before, &after));
6787 _session->tempo_map().insert_time (pos, frames);
6791 commit_reversible_command ();
6796 Editor::fit_selected_tracks ()
6798 if (!selection->tracks.empty()) {
6799 fit_tracks (selection->tracks);
6803 /* no selected tracks - use tracks with selected regions */
6805 if (!selection->regions.empty()) {
6806 for (RegionSelection::iterator r = selection->regions.begin(); r != selection->regions.end(); ++r) {
6807 tvl.push_back (&(*r)->get_time_axis_view ());
6813 } else if (internal_editing()) {
6814 /* no selected tracks, or regions, but in internal edit mode, so follow the mouse and use
6817 if (entered_track) {
6818 tvl.push_back (entered_track);
6826 Editor::fit_tracks (TrackViewList & tracks)
6828 if (tracks.empty()) {
6832 uint32_t child_heights = 0;
6833 int visible_tracks = 0;
6835 for (TrackSelection::iterator t = tracks.begin(); t != tracks.end(); ++t) {
6837 if (!(*t)->marked_for_display()) {
6841 child_heights += (*t)->effective_height() - (*t)->current_height();
6845 uint32_t h = (uint32_t) floor ((_visible_canvas_height - child_heights) / visible_tracks);
6846 double first_y_pos = DBL_MAX;
6848 if (h < TimeAxisView::preset_height (HeightSmall)) {
6849 MessageDialog msg (*this, _("There are too many tracks to fit in the current window"));
6850 /* too small to be displayed */
6854 undo_visual_stack.push_back (current_visual_state (true));
6855 no_save_visual = true;
6857 /* build a list of all tracks, including children */
6860 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
6862 TimeAxisView::Children c = (*i)->get_child_list ();
6863 for (TimeAxisView::Children::iterator j = c.begin(); j != c.end(); ++j) {
6864 all.push_back (j->get());
6868 /* operate on all tracks, hide unselected ones that are in the middle of selected ones */
6870 bool prev_was_selected = false;
6871 bool is_selected = tracks.contains (all.front());
6872 bool next_is_selected;
6874 for (TrackViewList::iterator t = all.begin(); t != all.end(); ++t) {
6876 TrackViewList::iterator next;
6881 if (next != all.end()) {
6882 next_is_selected = tracks.contains (*next);
6884 next_is_selected = false;
6887 if ((*t)->marked_for_display ()) {
6889 (*t)->set_height (h);
6890 first_y_pos = std::min ((*t)->y_position (), first_y_pos);
6892 if (prev_was_selected && next_is_selected) {
6893 hide_track_in_display (*t);
6898 prev_was_selected = is_selected;
6899 is_selected = next_is_selected;
6903 set the controls_layout height now, because waiting for its size
6904 request signal handler will cause the vertical adjustment setting to fail
6907 controls_layout.property_height () = _full_canvas_height;
6908 vertical_adjustment.set_value (first_y_pos);
6910 redo_visual_stack.push_back (current_visual_state (true));
6914 Editor::save_visual_state (uint32_t n)
6916 while (visual_states.size() <= n) {
6917 visual_states.push_back (0);
6920 if (visual_states[n] != 0) {
6921 delete visual_states[n];
6924 visual_states[n] = current_visual_state (true);
6929 Editor::goto_visual_state (uint32_t n)
6931 if (visual_states.size() <= n) {
6935 if (visual_states[n] == 0) {
6939 use_visual_state (*visual_states[n]);
6943 Editor::start_visual_state_op (uint32_t n)
6945 save_visual_state (n);
6947 PopUp* pup = new PopUp (WIN_POS_MOUSE, 1000, true);
6949 snprintf (buf, sizeof (buf), _("Saved view %u"), n+1);
6950 pup->set_text (buf);
6955 Editor::cancel_visual_state_op (uint32_t n)
6957 goto_visual_state (n);
6961 Editor::toggle_region_mute ()
6963 if (_ignore_region_action) {
6967 RegionSelection rs = get_regions_from_selection_and_entered ();
6973 if (rs.size() > 1) {
6974 begin_reversible_command (_("mute regions"));
6976 begin_reversible_command (_("mute region"));
6979 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
6981 (*i)->region()->playlist()->clear_changes ();
6982 (*i)->region()->set_muted (!(*i)->region()->muted ());
6983 _session->add_command (new StatefulDiffCommand ((*i)->region()->playlist()));
6987 commit_reversible_command ();
6991 Editor::combine_regions ()
6993 /* foreach track with selected regions, take all selected regions
6994 and join them into a new region containing the subregions (as a
6998 typedef set<RouteTimeAxisView*> RTVS;
7001 if (selection->regions.empty()) {
7005 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
7006 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(&(*i)->get_time_axis_view());
7009 tracks.insert (rtv);
7013 begin_reversible_command (_("combine regions"));
7015 vector<RegionView*> new_selection;
7017 for (RTVS::iterator i = tracks.begin(); i != tracks.end(); ++i) {
7020 if ((rv = (*i)->combine_regions ()) != 0) {
7021 new_selection.push_back (rv);
7025 selection->clear_regions ();
7026 for (vector<RegionView*>::iterator i = new_selection.begin(); i != new_selection.end(); ++i) {
7027 selection->add (*i);
7030 commit_reversible_command ();
7034 Editor::uncombine_regions ()
7036 typedef set<RouteTimeAxisView*> RTVS;
7039 if (selection->regions.empty()) {
7043 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
7044 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(&(*i)->get_time_axis_view());
7047 tracks.insert (rtv);
7051 begin_reversible_command (_("uncombine regions"));
7053 for (RTVS::iterator i = tracks.begin(); i != tracks.end(); ++i) {
7054 (*i)->uncombine_regions ();
7057 commit_reversible_command ();
7061 Editor::toggle_midi_input_active (bool flip_others)
7064 boost::shared_ptr<RouteList> rl (new RouteList);
7066 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
7067 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
7073 boost::shared_ptr<MidiTrack> mt = rtav->midi_track();
7076 rl->push_back (rtav->route());
7077 onoff = !mt->input_active();
7081 _session->set_exclusive_input_active (rl, onoff, flip_others);