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 current_interthread_info->process_thread.get_buffers ();
3579 clicked_routeview->audio_track()->freeze_me (*current_interthread_info);
3580 current_interthread_info->done = true;
3581 current_interthread_info->process_thread.drop_buffers();
3586 Editor::freeze_route ()
3592 /* stop transport before we start. this is important */
3594 _session->request_transport_speed (0.0);
3596 /* wait for just a little while, because the above call is asynchronous */
3598 Glib::usleep (250000);
3600 if (clicked_routeview == 0 || !clicked_routeview->is_audio_track()) {
3604 if (!clicked_routeview->track()->bounceable (clicked_routeview->track()->main_outs(), true)) {
3606 _("This track/bus cannot be frozen because the signal adds or loses channels before reaching the outputs.\n"
3607 "This is typically caused by plugins that generate stereo output from mono input or vice versa.")
3609 d.set_title (_("Cannot freeze"));
3614 if (clicked_routeview->track()->has_external_redirects()) {
3615 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"
3616 "Freezing will only process the signal as far as the first send/insert/return."),
3617 clicked_routeview->track()->name()), true, MESSAGE_INFO, BUTTONS_NONE, true);
3619 d.add_button (_("Freeze anyway"), Gtk::RESPONSE_OK);
3620 d.add_button (_("Don't freeze"), Gtk::RESPONSE_CANCEL);
3621 d.set_title (_("Freeze Limits"));
3623 int response = d.run ();
3626 case Gtk::RESPONSE_CANCEL:
3633 InterThreadInfo itt;
3634 current_interthread_info = &itt;
3636 InterthreadProgressWindow ipw (current_interthread_info, _("Freeze"), _("Cancel Freeze"));
3638 pthread_create_and_store (X_("freezer"), &itt.thread, _freeze_thread, this);
3640 set_canvas_cursor (_cursors->wait);
3642 while (!itt.done && !itt.cancel) {
3643 gtk_main_iteration ();
3646 current_interthread_info = 0;
3647 set_canvas_cursor (current_canvas_cursor);
3651 Editor::bounce_range_selection (bool replace, bool enable_processing)
3653 if (selection->time.empty()) {
3657 TrackSelection views = selection->tracks;
3659 for (TrackViewList::iterator i = views.begin(); i != views.end(); ++i) {
3661 if (enable_processing) {
3663 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*i);
3665 if (rtv && rtv->track() && replace && enable_processing && !rtv->track()->bounceable (rtv->track()->main_outs(), false)) {
3667 _("You can't perform this operation because the processing of the signal "
3668 "will cause one or more of the tracks to end up with a region with more channels than this track has inputs.\n\n"
3669 "You can do this without processing, which is a different operation.")
3671 d.set_title (_("Cannot bounce"));
3678 framepos_t start = selection->time[clicked_selection].start;
3679 framepos_t end = selection->time[clicked_selection].end;
3680 framepos_t cnt = end - start + 1;
3682 begin_reversible_command (_("bounce range"));
3684 for (TrackViewList::iterator i = views.begin(); i != views.end(); ++i) {
3686 RouteTimeAxisView* rtv;
3688 if ((rtv = dynamic_cast<RouteTimeAxisView*> (*i)) == 0) {
3692 boost::shared_ptr<Playlist> playlist;
3694 if ((playlist = rtv->playlist()) == 0) {
3698 InterThreadInfo itt;
3700 playlist->clear_changes ();
3701 playlist->clear_owned_changes ();
3703 boost::shared_ptr<Region> r;
3705 if (enable_processing) {
3706 r = rtv->track()->bounce_range (start, start+cnt, itt, rtv->track()->main_outs(), false);
3708 r = rtv->track()->bounce_range (start, start+cnt, itt, boost::shared_ptr<Processor>(), false);
3716 list<AudioRange> ranges;
3717 ranges.push_back (AudioRange (start, start+cnt, 0));
3718 playlist->cut (ranges); // discard result
3719 playlist->add_region (r, start);
3722 vector<Command*> cmds;
3723 playlist->rdiff (cmds);
3724 _session->add_commands (cmds);
3726 _session->add_command (new StatefulDiffCommand (playlist));
3729 commit_reversible_command ();
3732 /** Delete selected regions, automation points or a time range */
3739 /** Cut selected regions, automation points or a time range */
3746 /** Copy selected regions, automation points or a time range */
3754 /** @return true if a Cut, Copy or Clear is possible */
3756 Editor::can_cut_copy () const
3758 switch (effective_mouse_mode()) {
3761 if (!selection->regions.empty() || !selection->points.empty()) {
3767 if (!selection->time.empty()) {
3780 /** Cut, copy or clear selected regions, automation points or a time range.
3781 * @param op Operation (Cut, Copy or Clear)
3784 Editor::cut_copy (CutCopyOp op)
3786 /* only cancel selection if cut/copy is successful.*/
3792 opname = _("delete");
3801 opname = _("clear");
3805 /* if we're deleting something, and the mouse is still pressed,
3806 the thing we started a drag for will be gone when we release
3807 the mouse button(s). avoid this. see part 2 at the end of
3811 if (op == Delete || op == Cut || op == Clear) {
3812 if (_drags->active ()) {
3817 if ( op != Clear ) //"Delete" doesn't change copy/paste buf
3818 cut_buffer->clear ();
3820 if (entered_marker) {
3822 /* cut/delete op while pointing at a marker */
3825 Location* loc = find_location_from_marker (entered_marker, ignored);
3827 if (_session && loc) {
3828 Glib::signal_idle().connect (sigc::bind (sigc::mem_fun(*this, &Editor::really_remove_marker), loc));
3835 if (internal_editing()) {
3837 switch (effective_mouse_mode()) {
3840 begin_reversible_command (opname + ' ' + X_("MIDI"));
3842 commit_reversible_command ();
3851 bool did_edit = false;
3853 switch (effective_mouse_mode()) {
3855 if (!selection->points.empty()) {
3856 begin_reversible_command (opname + _(" points"));
3858 cut_copy_points (op);
3859 if (op == Cut || op == Delete) {
3860 selection->clear_points ();
3867 if (!selection->regions.empty() || !selection->points.empty()) {
3871 if (selection->regions.empty()) {
3872 thing_name = _("points");
3873 } else if (selection->points.empty()) {
3874 thing_name = _("regions");
3876 thing_name = _("objects");
3879 begin_reversible_command (opname + ' ' + thing_name);
3882 if (!selection->regions.empty()) {
3883 cut_copy_regions (op, selection->regions);
3885 if (op == Cut || op == Delete) {
3886 selection->clear_regions ();
3890 if (!selection->points.empty()) {
3891 cut_copy_points (op);
3893 if (op == Cut || op == Delete) {
3894 selection->clear_points ();
3901 if (selection->time.empty()) {
3902 framepos_t start, end;
3903 /* no time selection, see if we can get an edit range
3906 if (get_edit_op_range (start, end)) {
3907 selection->set (start, end);
3910 if (!selection->time.empty()) {
3911 begin_reversible_command (opname + _(" range"));
3914 cut_copy_ranges (op);
3916 if (op == Cut || op == Delete) {
3917 selection->clear_time ();
3927 commit_reversible_command ();
3930 if (op == Delete || op == Cut || op == Clear) {
3935 struct AutomationRecord {
3936 AutomationRecord () : state (0) {}
3937 AutomationRecord (XMLNode* s) : state (s) {}
3939 XMLNode* state; ///< state before any operation
3940 boost::shared_ptr<Evoral::ControlList> copy; ///< copied events for the cut buffer
3943 /** Cut, copy or clear selected automation points.
3944 * @param op Operation (Cut, Copy or Clear)
3947 Editor::cut_copy_points (CutCopyOp op)
3949 if (selection->points.empty ()) {
3953 /* XXX: not ideal, as there may be more than one track involved in the point selection */
3954 _last_cut_copy_source_track = &selection->points.front()->line().trackview;
3956 /* Keep a record of the AutomationLists that we end up using in this operation */
3957 typedef std::map<boost::shared_ptr<AutomationList>, AutomationRecord> Lists;
3960 /* Go through all selected points, making an AutomationRecord for each distinct AutomationList */
3961 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
3962 boost::shared_ptr<AutomationList> al = (*i)->line().the_list();
3963 if (lists.find (al) == lists.end ()) {
3964 /* We haven't seen this list yet, so make a record for it. This includes
3965 taking a copy of its current state, in case this is needed for undo later.
3967 lists[al] = AutomationRecord (&al->get_state ());
3971 if (op == Cut || op == Copy) {
3972 /* This operation will involve putting things in the cut buffer, so create an empty
3973 ControlList for each of our source lists to put the cut buffer data in.
3975 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
3976 i->second.copy = i->first->create (i->first->parameter ());
3979 /* Add all selected points to the relevant copy ControlLists */
3980 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
3981 boost::shared_ptr<AutomationList> al = (*i)->line().the_list();
3982 AutomationList::const_iterator j = (*i)->model ();
3983 lists[al].copy->add ((*j)->when, (*j)->value);
3986 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
3987 /* Correct this copy list so that it starts at time 0 */
3988 double const start = i->second.copy->front()->when;
3989 for (AutomationList::iterator j = i->second.copy->begin(); j != i->second.copy->end(); ++j) {
3990 (*j)->when -= start;
3993 /* And add it to the cut buffer */
3994 cut_buffer->add (i->second.copy);
3998 if (op == Delete || op == Cut) {
3999 /* This operation needs to remove things from the main AutomationList, so do that now */
4001 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
4002 i->first->freeze ();
4005 /* Remove each selected point from its AutomationList */
4006 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
4007 boost::shared_ptr<AutomationList> al = (*i)->line().the_list();
4008 al->erase ((*i)->model ());
4011 /* Thaw the lists and add undo records for them */
4012 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
4013 boost::shared_ptr<AutomationList> al = i->first;
4015 _session->add_command (new MementoCommand<AutomationList> (*al.get(), i->second.state, &(al->get_state ())));
4020 /** Cut, copy or clear selected automation points.
4021 * @param op Operation (Cut, Copy or Clear)
4024 Editor::cut_copy_midi (CutCopyOp op)
4026 for (MidiRegionSelection::iterator i = selection->midi_regions.begin(); i != selection->midi_regions.end(); ++i) {
4027 MidiRegionView* mrv = *i;
4028 mrv->cut_copy_clear (op);
4034 struct lt_playlist {
4035 bool operator () (const PlaylistState& a, const PlaylistState& b) {
4036 return a.playlist < b.playlist;
4040 struct PlaylistMapping {
4042 boost::shared_ptr<Playlist> pl;
4044 PlaylistMapping (TimeAxisView* tvp) : tv (tvp) {}
4047 /** Remove `clicked_regionview' */
4049 Editor::remove_clicked_region ()
4051 if (clicked_routeview == 0 || clicked_regionview == 0) {
4055 boost::shared_ptr<Playlist> playlist = clicked_routeview->playlist();
4057 begin_reversible_command (_("remove region"));
4058 playlist->clear_changes ();
4059 playlist->clear_owned_changes ();
4060 playlist->remove_region (clicked_regionview->region());
4062 /* We might have removed regions, which alters other regions' layering_index,
4063 so we need to do a recursive diff here.
4065 vector<Command*> cmds;
4066 playlist->rdiff (cmds);
4067 _session->add_commands (cmds);
4069 _session->add_command(new StatefulDiffCommand (playlist));
4070 commit_reversible_command ();
4074 /** Remove the selected regions */
4076 Editor::remove_selected_regions ()
4078 RegionSelection rs = get_regions_from_selection_and_entered ();
4080 if (!_session || rs.empty()) {
4084 begin_reversible_command (_("remove region"));
4086 list<boost::shared_ptr<Region> > regions_to_remove;
4088 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
4089 // we can't just remove the region(s) in this loop because
4090 // this removes them from the RegionSelection, and they thus
4091 // disappear from underneath the iterator, and the ++i above
4092 // SEGVs in a puzzling fashion.
4094 // so, first iterate over the regions to be removed from rs and
4095 // add them to the regions_to_remove list, and then
4096 // iterate over the list to actually remove them.
4098 regions_to_remove.push_back ((*i)->region());
4101 vector<boost::shared_ptr<Playlist> > playlists;
4103 for (list<boost::shared_ptr<Region> >::iterator rl = regions_to_remove.begin(); rl != regions_to_remove.end(); ++rl) {
4105 boost::shared_ptr<Playlist> playlist = (*rl)->playlist();
4108 // is this check necessary?
4112 /* get_regions_from_selection_and_entered() guarantees that
4113 the playlists involved are unique, so there is no need
4117 playlists.push_back (playlist);
4119 playlist->clear_changes ();
4120 playlist->clear_owned_changes ();
4121 playlist->freeze ();
4122 playlist->remove_region (*rl);
4125 vector<boost::shared_ptr<Playlist> >::iterator pl;
4127 for (pl = playlists.begin(); pl != playlists.end(); ++pl) {
4130 /* We might have removed regions, which alters other regions' layering_index,
4131 so we need to do a recursive diff here.
4133 vector<Command*> cmds;
4134 (*pl)->rdiff (cmds);
4135 _session->add_commands (cmds);
4137 _session->add_command(new StatefulDiffCommand (*pl));
4140 commit_reversible_command ();
4143 /** Cut, copy or clear selected regions.
4144 * @param op Operation (Cut, Copy or Clear)
4147 Editor::cut_copy_regions (CutCopyOp op, RegionSelection& rs)
4149 /* we can't use a std::map here because the ordering is important, and we can't trivially sort
4150 a map when we want ordered access to both elements. i think.
4153 vector<PlaylistMapping> pmap;
4155 framepos_t first_position = max_framepos;
4157 typedef set<boost::shared_ptr<Playlist> > FreezeList;
4158 FreezeList freezelist;
4160 /* get ordering correct before we cut/copy */
4162 rs.sort_by_position_and_track ();
4164 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
4166 first_position = min ((framepos_t) (*x)->region()->position(), first_position);
4168 if (op == Cut || op == Clear || op == Delete) {
4169 boost::shared_ptr<Playlist> pl = (*x)->region()->playlist();
4172 FreezeList::iterator fl;
4174 // only take state if this is a new playlist.
4175 for (fl = freezelist.begin(); fl != freezelist.end(); ++fl) {
4181 if (fl == freezelist.end()) {
4182 pl->clear_changes();
4183 pl->clear_owned_changes ();
4185 freezelist.insert (pl);
4190 TimeAxisView* tv = &(*x)->get_time_axis_view();
4191 vector<PlaylistMapping>::iterator z;
4193 for (z = pmap.begin(); z != pmap.end(); ++z) {
4194 if ((*z).tv == tv) {
4199 if (z == pmap.end()) {
4200 pmap.push_back (PlaylistMapping (tv));
4204 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ) {
4206 boost::shared_ptr<Playlist> pl = (*x)->region()->playlist();
4209 /* region not yet associated with a playlist (e.g. unfinished
4216 TimeAxisView& tv = (*x)->get_time_axis_view();
4217 boost::shared_ptr<Playlist> npl;
4218 RegionSelection::iterator tmp;
4225 vector<PlaylistMapping>::iterator z;
4227 for (z = pmap.begin(); z != pmap.end(); ++z) {
4228 if ((*z).tv == &tv) {
4233 assert (z != pmap.end());
4236 npl = PlaylistFactory::create (pl->data_type(), *_session, "cutlist", true);
4244 boost::shared_ptr<Region> r = (*x)->region();
4245 boost::shared_ptr<Region> _xx;
4251 pl->remove_region (r);
4255 _xx = RegionFactory::create (r);
4256 npl->add_region (_xx, r->position() - first_position);
4257 pl->remove_region (r);
4261 /* copy region before adding, so we're not putting same object into two different playlists */
4262 npl->add_region (RegionFactory::create (r), r->position() - first_position);
4266 pl->remove_region (r);
4275 list<boost::shared_ptr<Playlist> > foo;
4277 /* the pmap is in the same order as the tracks in which selected regions occured */
4279 for (vector<PlaylistMapping>::iterator i = pmap.begin(); i != pmap.end(); ++i) {
4282 foo.push_back ((*i).pl);
4287 cut_buffer->set (foo);
4291 _last_cut_copy_source_track = 0;
4293 _last_cut_copy_source_track = pmap.front().tv;
4297 for (FreezeList::iterator pl = freezelist.begin(); pl != freezelist.end(); ++pl) {
4300 /* We might have removed regions, which alters other regions' layering_index,
4301 so we need to do a recursive diff here.
4303 vector<Command*> cmds;
4304 (*pl)->rdiff (cmds);
4305 _session->add_commands (cmds);
4307 _session->add_command (new StatefulDiffCommand (*pl));
4312 Editor::cut_copy_ranges (CutCopyOp op)
4314 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4316 /* Sort the track selection now, so that it if is used, the playlists
4317 selected by the calls below to cut_copy_clear are in the order that
4318 their tracks appear in the editor. This makes things like paste
4319 of ranges work properly.
4322 sort_track_selection (ts);
4325 if (!entered_track) {
4328 ts.push_back (entered_track);
4331 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4332 (*i)->cut_copy_clear (*selection, op);
4337 Editor::paste (float times, bool from_context)
4339 DEBUG_TRACE (DEBUG::CutNPaste, "paste to preferred edit pos\n");
4341 paste_internal (get_preferred_edit_position (false, from_context), times);
4345 Editor::mouse_paste ()
4350 if (!mouse_frame (where, ignored)) {
4355 paste_internal (where, 1);
4359 Editor::paste_internal (framepos_t position, float times)
4361 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("apparent paste position is %1\n", position));
4363 if (internal_editing()) {
4364 if (cut_buffer->midi_notes.empty()) {
4368 if (cut_buffer->empty()) {
4373 if (position == max_framepos) {
4374 position = get_preferred_edit_position();
4375 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("preferred edit position is %1\n", position));
4379 TrackViewList::iterator i;
4382 /* get everything in the correct order */
4384 if (_edit_point == Editing::EditAtMouse && entered_track) {
4385 /* With the mouse edit point, paste onto the track under the mouse */
4386 ts.push_back (entered_track);
4387 } else if (!selection->tracks.empty()) {
4388 /* Otherwise, if there are some selected tracks, paste to them */
4389 ts = selection->tracks.filter_to_unique_playlists ();
4390 sort_track_selection (ts);
4391 } else if (_last_cut_copy_source_track) {
4392 /* Otherwise paste to the track that the cut/copy came from;
4393 see discussion in mantis #3333.
4395 ts.push_back (_last_cut_copy_source_track);
4398 if (internal_editing ()) {
4400 /* undo/redo is handled by individual tracks/regions */
4402 for (nth = 0, i = ts.begin(); i != ts.end(); ++i, ++nth) {
4405 RegionSelection::iterator r;
4406 MidiNoteSelection::iterator cb;
4408 get_regions_at (rs, position, ts);
4410 for (cb = cut_buffer->midi_notes.begin(), r = rs.begin();
4411 cb != cut_buffer->midi_notes.end() && r != rs.end(); ++r) {
4412 MidiRegionView* mrv = dynamic_cast<MidiRegionView*> (*r);
4414 mrv->paste (position, times, **cb);
4422 /* we do redo (do you do voodoo?) */
4424 begin_reversible_command (Operations::paste);
4426 for (nth = 0, i = ts.begin(); i != ts.end(); ++i, ++nth) {
4427 (*i)->paste (position, times, *cut_buffer, nth);
4430 commit_reversible_command ();
4435 Editor::duplicate_some_regions (RegionSelection& regions, float times)
4437 boost::shared_ptr<Playlist> playlist;
4438 RegionSelection sel = regions; // clear (below) may clear the argument list if its the current region selection
4439 RegionSelection foo;
4441 framepos_t const start_frame = regions.start ();
4442 framepos_t const end_frame = regions.end_frame ();
4444 begin_reversible_command (Operations::duplicate_region);
4446 selection->clear_regions ();
4448 for (RegionSelection::iterator i = sel.begin(); i != sel.end(); ++i) {
4450 boost::shared_ptr<Region> r ((*i)->region());
4452 TimeAxisView& tv = (*i)->get_time_axis_view();
4453 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (&tv);
4454 latest_regionviews.clear ();
4455 sigc::connection c = rtv->view()->RegionViewAdded.connect (sigc::mem_fun(*this, &Editor::collect_new_region_view));
4457 playlist = (*i)->region()->playlist();
4458 playlist->clear_changes ();
4459 playlist->duplicate (r, end_frame + (r->first_frame() - start_frame), times);
4460 _session->add_command(new StatefulDiffCommand (playlist));
4464 foo.insert (foo.end(), latest_regionviews.begin(), latest_regionviews.end());
4467 commit_reversible_command ();
4470 selection->set (foo);
4475 Editor::duplicate_selection (float times)
4477 if (selection->time.empty() || selection->tracks.empty()) {
4481 boost::shared_ptr<Playlist> playlist;
4482 vector<boost::shared_ptr<Region> > new_regions;
4483 vector<boost::shared_ptr<Region> >::iterator ri;
4485 create_region_from_selection (new_regions);
4487 if (new_regions.empty()) {
4491 begin_reversible_command (_("duplicate selection"));
4493 ri = new_regions.begin();
4495 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4497 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4498 if ((playlist = (*i)->playlist()) == 0) {
4501 playlist->clear_changes ();
4502 playlist->duplicate (*ri, selection->time[clicked_selection].end, times);
4503 _session->add_command (new StatefulDiffCommand (playlist));
4506 if (ri == new_regions.end()) {
4511 commit_reversible_command ();
4514 /** Reset all selected points to the relevant default value */
4516 Editor::reset_point_selection ()
4518 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
4519 ARDOUR::AutomationList::iterator j = (*i)->model ();
4520 (*j)->value = (*i)->line().the_list()->default_value ();
4525 Editor::center_playhead ()
4527 float const page = _visible_canvas_width * samples_per_pixel;
4528 center_screen_internal (playhead_cursor->current_frame (), page);
4532 Editor::center_edit_point ()
4534 float const page = _visible_canvas_width * samples_per_pixel;
4535 center_screen_internal (get_preferred_edit_position(), page);
4538 /** Caller must begin and commit a reversible command */
4540 Editor::clear_playlist (boost::shared_ptr<Playlist> playlist)
4542 playlist->clear_changes ();
4544 _session->add_command (new StatefulDiffCommand (playlist));
4548 Editor::nudge_track (bool use_edit, bool forwards)
4550 boost::shared_ptr<Playlist> playlist;
4551 framepos_t distance;
4552 framepos_t next_distance;
4556 start = get_preferred_edit_position();
4561 if ((distance = get_nudge_distance (start, next_distance)) == 0) {
4565 if (selection->tracks.empty()) {
4569 begin_reversible_command (_("nudge track"));
4571 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4573 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4575 if ((playlist = (*i)->playlist()) == 0) {
4579 playlist->clear_changes ();
4580 playlist->clear_owned_changes ();
4582 playlist->nudge_after (start, distance, forwards);
4584 vector<Command*> cmds;
4586 playlist->rdiff (cmds);
4587 _session->add_commands (cmds);
4589 _session->add_command (new StatefulDiffCommand (playlist));
4592 commit_reversible_command ();
4596 Editor::remove_last_capture ()
4598 vector<string> choices;
4605 if (Config->get_verify_remove_last_capture()) {
4606 prompt = _("Do you really want to destroy the last capture?"
4607 "\n(This is destructive and cannot be undone)");
4609 choices.push_back (_("No, do nothing."));
4610 choices.push_back (_("Yes, destroy it."));
4612 Gtkmm2ext::Choice prompter (_("Destroy last capture"), prompt, choices);
4614 if (prompter.run () == 1) {
4615 _session->remove_last_capture ();
4616 _regions->redisplay ();
4620 _session->remove_last_capture();
4621 _regions->redisplay ();
4626 Editor::normalize_region ()
4632 RegionSelection rs = get_regions_from_selection_and_entered ();
4638 NormalizeDialog dialog (rs.size() > 1);
4640 if (dialog.run () == RESPONSE_CANCEL) {
4644 set_canvas_cursor (_cursors->wait);
4647 /* XXX: should really only count audio regions here */
4648 int const regions = rs.size ();
4650 /* Make a list of the selected audio regions' maximum amplitudes, and also
4651 obtain the maximum amplitude of them all.
4653 list<double> max_amps;
4655 for (RegionSelection::const_iterator i = rs.begin(); i != rs.end(); ++i) {
4656 AudioRegionView const * arv = dynamic_cast<AudioRegionView const *> (*i);
4658 dialog.descend (1.0 / regions);
4659 double const a = arv->audio_region()->maximum_amplitude (&dialog);
4662 /* the user cancelled the operation */
4663 set_canvas_cursor (current_canvas_cursor);
4667 max_amps.push_back (a);
4668 max_amp = max (max_amp, a);
4673 begin_reversible_command (_("normalize"));
4675 list<double>::const_iterator a = max_amps.begin ();
4677 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
4678 AudioRegionView* const arv = dynamic_cast<AudioRegionView*> (*r);
4683 arv->region()->clear_changes ();
4685 double const amp = dialog.normalize_individually() ? *a : max_amp;
4687 arv->audio_region()->normalize (amp, dialog.target ());
4688 _session->add_command (new StatefulDiffCommand (arv->region()));
4693 commit_reversible_command ();
4694 set_canvas_cursor (current_canvas_cursor);
4699 Editor::reset_region_scale_amplitude ()
4705 RegionSelection rs = get_regions_from_selection_and_entered ();
4711 begin_reversible_command ("reset gain");
4713 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
4714 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
4717 arv->region()->clear_changes ();
4718 arv->audio_region()->set_scale_amplitude (1.0f);
4719 _session->add_command (new StatefulDiffCommand (arv->region()));
4722 commit_reversible_command ();
4726 Editor::adjust_region_gain (bool up)
4728 RegionSelection rs = get_regions_from_selection_and_entered ();
4730 if (!_session || rs.empty()) {
4734 begin_reversible_command ("adjust region gain");
4736 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
4737 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
4742 arv->region()->clear_changes ();
4744 double dB = accurate_coefficient_to_dB (arv->audio_region()->scale_amplitude ());
4752 arv->audio_region()->set_scale_amplitude (dB_to_coefficient (dB));
4753 _session->add_command (new StatefulDiffCommand (arv->region()));
4756 commit_reversible_command ();
4761 Editor::reverse_region ()
4767 Reverse rev (*_session);
4768 apply_filter (rev, _("reverse regions"));
4772 Editor::strip_region_silence ()
4778 RegionSelection rs = get_regions_from_selection_and_entered ();
4784 std::list<RegionView*> audio_only;
4786 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
4787 AudioRegionView* const arv = dynamic_cast<AudioRegionView*> (*i);
4789 audio_only.push_back (arv);
4793 StripSilenceDialog d (_session, audio_only);
4794 int const r = d.run ();
4798 if (r == Gtk::RESPONSE_OK) {
4799 ARDOUR::AudioIntervalMap silences;
4800 d.silences (silences);
4801 StripSilence s (*_session, silences, d.fade_length());
4802 apply_filter (s, _("strip silence"), &d);
4807 Editor::apply_midi_note_edit_op_to_region (MidiOperator& op, MidiRegionView& mrv)
4809 Evoral::Sequence<Evoral::MusicalTime>::Notes selected;
4810 mrv.selection_as_notelist (selected, true);
4812 vector<Evoral::Sequence<Evoral::MusicalTime>::Notes> v;
4813 v.push_back (selected);
4815 framepos_t pos_frames = mrv.midi_region()->position() - mrv.midi_region()->start();
4816 double pos_beats = _session->tempo_map().framewalk_to_beats(0, pos_frames);
4818 return op (mrv.midi_region()->model(), pos_beats, v);
4822 Editor::apply_midi_note_edit_op (MidiOperator& op)
4826 RegionSelection rs = get_regions_from_selection_and_entered ();
4832 begin_reversible_command (op.name ());
4834 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
4835 RegionSelection::iterator tmp = r;
4838 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*r);
4841 cmd = apply_midi_note_edit_op_to_region (op, *mrv);
4844 _session->add_command (cmd);
4851 commit_reversible_command ();
4855 Editor::fork_region ()
4857 RegionSelection rs = get_regions_from_selection_and_entered ();
4863 begin_reversible_command (_("Fork Region(s)"));
4865 set_canvas_cursor (_cursors->wait);
4868 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
4869 RegionSelection::iterator tmp = r;
4872 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*>(*r);
4876 boost::shared_ptr<Playlist> playlist = mrv->region()->playlist();
4877 boost::shared_ptr<MidiSource> new_source = _session->create_midi_source_by_stealing_name (mrv->midi_view()->track());
4878 boost::shared_ptr<MidiRegion> newregion = mrv->midi_region()->clone (new_source);
4880 playlist->clear_changes ();
4881 playlist->replace_region (mrv->region(), newregion, mrv->region()->position());
4882 _session->add_command(new StatefulDiffCommand (playlist));
4884 error << string_compose (_("Could not unlink %1"), mrv->region()->name()) << endmsg;
4891 commit_reversible_command ();
4893 set_canvas_cursor (current_canvas_cursor);
4897 Editor::quantize_region ()
4899 int selected_midi_region_cnt = 0;
4905 RegionSelection rs = get_regions_from_selection_and_entered ();
4911 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
4912 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*r);
4914 selected_midi_region_cnt++;
4918 if (selected_midi_region_cnt == 0) {
4922 QuantizeDialog* qd = new QuantizeDialog (*this);
4925 const int r = qd->run ();
4928 if (r == Gtk::RESPONSE_OK) {
4929 Quantize quant (*_session, qd->snap_start(), qd->snap_end(),
4930 qd->start_grid_size(), qd->end_grid_size(),
4931 qd->strength(), qd->swing(), qd->threshold());
4933 apply_midi_note_edit_op (quant);
4938 Editor::insert_patch_change (bool from_context)
4940 RegionSelection rs = get_regions_from_selection_and_entered ();
4946 const framepos_t p = get_preferred_edit_position (false, from_context);
4948 /* XXX: bit of a hack; use the MIDNAM from the first selected region;
4949 there may be more than one, but the PatchChangeDialog can only offer
4950 one set of patch menus.
4952 MidiRegionView* first = dynamic_cast<MidiRegionView*> (rs.front ());
4954 Evoral::PatchChange<Evoral::MusicalTime> empty (0, 0, 0, 0);
4955 PatchChangeDialog d (0, _session, empty, first->instrument_info(), Gtk::Stock::ADD);
4957 if (d.run() == RESPONSE_CANCEL) {
4961 for (RegionSelection::iterator i = rs.begin (); i != rs.end(); ++i) {
4962 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*i);
4964 if (p >= mrv->region()->first_frame() && p <= mrv->region()->last_frame()) {
4965 mrv->add_patch_change (p - mrv->region()->position(), d.patch ());
4972 Editor::apply_filter (Filter& filter, string command, ProgressReporter* progress)
4974 RegionSelection rs = get_regions_from_selection_and_entered ();
4980 begin_reversible_command (command);
4982 set_canvas_cursor (_cursors->wait);
4986 int const N = rs.size ();
4988 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
4989 RegionSelection::iterator tmp = r;
4992 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
4994 boost::shared_ptr<Playlist> playlist = arv->region()->playlist();
4997 progress->descend (1.0 / N);
5000 if (arv->audio_region()->apply (filter, progress) == 0) {
5002 playlist->clear_changes ();
5003 playlist->clear_owned_changes ();
5005 if (filter.results.empty ()) {
5007 /* no regions returned; remove the old one */
5008 playlist->remove_region (arv->region ());
5012 std::vector<boost::shared_ptr<Region> >::iterator res = filter.results.begin ();
5014 /* first region replaces the old one */
5015 playlist->replace_region (arv->region(), *res, (*res)->position());
5019 while (res != filter.results.end()) {
5020 playlist->add_region (*res, (*res)->position());
5026 /* We might have removed regions, which alters other regions' layering_index,
5027 so we need to do a recursive diff here.
5029 vector<Command*> cmds;
5030 playlist->rdiff (cmds);
5031 _session->add_commands (cmds);
5033 _session->add_command(new StatefulDiffCommand (playlist));
5039 progress->ascend ();
5047 commit_reversible_command ();
5050 set_canvas_cursor (current_canvas_cursor);
5054 Editor::external_edit_region ()
5060 Editor::reset_region_gain_envelopes ()
5062 RegionSelection rs = get_regions_from_selection_and_entered ();
5064 if (!_session || rs.empty()) {
5068 _session->begin_reversible_command (_("reset region gain"));
5070 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5071 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
5073 boost::shared_ptr<AutomationList> alist (arv->audio_region()->envelope());
5074 XMLNode& before (alist->get_state());
5076 arv->audio_region()->set_default_envelope ();
5077 _session->add_command (new MementoCommand<AutomationList>(*arv->audio_region()->envelope().get(), &before, &alist->get_state()));
5081 _session->commit_reversible_command ();
5085 Editor::set_region_gain_visibility (RegionView* rv)
5087 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (rv);
5089 arv->update_envelope_visibility();
5094 Editor::set_gain_envelope_visibility ()
5100 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5101 AudioTimeAxisView* v = dynamic_cast<AudioTimeAxisView*>(*i);
5103 v->audio_view()->foreach_regionview (sigc::mem_fun (this, &Editor::set_region_gain_visibility));
5109 Editor::toggle_gain_envelope_active ()
5111 if (_ignore_region_action) {
5115 RegionSelection rs = get_regions_from_selection_and_entered ();
5117 if (!_session || rs.empty()) {
5121 _session->begin_reversible_command (_("region gain envelope active"));
5123 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5124 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
5126 arv->region()->clear_changes ();
5127 arv->audio_region()->set_envelope_active (!arv->audio_region()->envelope_active());
5128 _session->add_command (new StatefulDiffCommand (arv->region()));
5132 _session->commit_reversible_command ();
5136 Editor::toggle_region_lock ()
5138 if (_ignore_region_action) {
5142 RegionSelection rs = get_regions_from_selection_and_entered ();
5144 if (!_session || rs.empty()) {
5148 _session->begin_reversible_command (_("toggle region lock"));
5150 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5151 (*i)->region()->clear_changes ();
5152 (*i)->region()->set_locked (!(*i)->region()->locked());
5153 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5156 _session->commit_reversible_command ();
5160 Editor::toggle_region_video_lock ()
5162 if (_ignore_region_action) {
5166 RegionSelection rs = get_regions_from_selection_and_entered ();
5168 if (!_session || rs.empty()) {
5172 _session->begin_reversible_command (_("Toggle Video Lock"));
5174 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5175 (*i)->region()->clear_changes ();
5176 (*i)->region()->set_video_locked (!(*i)->region()->video_locked());
5177 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5180 _session->commit_reversible_command ();
5184 Editor::toggle_region_lock_style ()
5186 if (_ignore_region_action) {
5190 RegionSelection rs = get_regions_from_selection_and_entered ();
5192 if (!_session || rs.empty()) {
5196 _session->begin_reversible_command (_("region lock style"));
5198 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5199 (*i)->region()->clear_changes ();
5200 PositionLockStyle const ns = (*i)->region()->position_lock_style() == AudioTime ? MusicTime : AudioTime;
5201 (*i)->region()->set_position_lock_style (ns);
5202 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5205 _session->commit_reversible_command ();
5209 Editor::toggle_opaque_region ()
5211 if (_ignore_region_action) {
5215 RegionSelection rs = get_regions_from_selection_and_entered ();
5217 if (!_session || rs.empty()) {
5221 _session->begin_reversible_command (_("change region opacity"));
5223 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5224 (*i)->region()->clear_changes ();
5225 (*i)->region()->set_opaque (!(*i)->region()->opaque());
5226 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5229 _session->commit_reversible_command ();
5233 Editor::toggle_record_enable ()
5235 bool new_state = false;
5237 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5238 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5241 if (!rtav->is_track())
5245 new_state = !rtav->track()->record_enabled();
5249 rtav->track()->set_record_enabled (new_state, this);
5254 Editor::toggle_solo ()
5256 bool new_state = false;
5258 boost::shared_ptr<RouteList> rl (new RouteList);
5260 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5261 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5268 new_state = !rtav->route()->soloed ();
5272 rl->push_back (rtav->route());
5275 _session->set_solo (rl, new_state, Session::rt_cleanup, true);
5279 Editor::toggle_mute ()
5281 bool new_state = false;
5283 boost::shared_ptr<RouteList> rl (new RouteList);
5285 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5286 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5293 new_state = !rtav->route()->muted();
5297 rl->push_back (rtav->route());
5300 _session->set_mute (rl, new_state, Session::rt_cleanup, true);
5304 Editor::toggle_solo_isolate ()
5309 Editor::set_fade_length (bool in)
5311 RegionSelection rs = get_regions_from_selection_and_entered ();
5317 /* we need a region to measure the offset from the start */
5319 RegionView* rv = rs.front ();
5321 framepos_t pos = get_preferred_edit_position();
5325 if (pos > rv->region()->last_frame() || pos < rv->region()->first_frame()) {
5326 /* edit point is outside the relevant region */
5331 if (pos <= rv->region()->position()) {
5335 len = pos - rv->region()->position();
5336 cmd = _("set fade in length");
5338 if (pos >= rv->region()->last_frame()) {
5342 len = rv->region()->last_frame() - pos;
5343 cmd = _("set fade out length");
5346 begin_reversible_command (cmd);
5348 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5349 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5355 boost::shared_ptr<AutomationList> alist;
5357 alist = tmp->audio_region()->fade_in();
5359 alist = tmp->audio_region()->fade_out();
5362 XMLNode &before = alist->get_state();
5365 tmp->audio_region()->set_fade_in_length (len);
5366 tmp->audio_region()->set_fade_in_active (true);
5368 tmp->audio_region()->set_fade_out_length (len);
5369 tmp->audio_region()->set_fade_out_active (true);
5372 XMLNode &after = alist->get_state();
5373 _session->add_command(new MementoCommand<AutomationList>(*alist, &before, &after));
5376 commit_reversible_command ();
5380 Editor::set_fade_in_shape (FadeShape shape)
5382 RegionSelection rs = get_regions_from_selection_and_entered ();
5388 begin_reversible_command (_("set fade in shape"));
5390 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5391 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5397 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_in();
5398 XMLNode &before = alist->get_state();
5400 tmp->audio_region()->set_fade_in_shape (shape);
5402 XMLNode &after = alist->get_state();
5403 _session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
5406 commit_reversible_command ();
5411 Editor::set_fade_out_shape (FadeShape shape)
5413 RegionSelection rs = get_regions_from_selection_and_entered ();
5419 begin_reversible_command (_("set fade out shape"));
5421 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5422 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5428 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_out();
5429 XMLNode &before = alist->get_state();
5431 tmp->audio_region()->set_fade_out_shape (shape);
5433 XMLNode &after = alist->get_state();
5434 _session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
5437 commit_reversible_command ();
5441 Editor::set_fade_in_active (bool yn)
5443 RegionSelection rs = get_regions_from_selection_and_entered ();
5449 begin_reversible_command (_("set fade in active"));
5451 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5452 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5459 boost::shared_ptr<AudioRegion> ar (tmp->audio_region());
5461 ar->clear_changes ();
5462 ar->set_fade_in_active (yn);
5463 _session->add_command (new StatefulDiffCommand (ar));
5466 commit_reversible_command ();
5470 Editor::set_fade_out_active (bool yn)
5472 RegionSelection rs = get_regions_from_selection_and_entered ();
5478 begin_reversible_command (_("set fade out active"));
5480 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5481 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5487 boost::shared_ptr<AudioRegion> ar (tmp->audio_region());
5489 ar->clear_changes ();
5490 ar->set_fade_out_active (yn);
5491 _session->add_command(new StatefulDiffCommand (ar));
5494 commit_reversible_command ();
5498 Editor::toggle_region_fades (int dir)
5500 if (_ignore_region_action) {
5504 boost::shared_ptr<AudioRegion> ar;
5507 RegionSelection rs = get_regions_from_selection_and_entered ();
5513 RegionSelection::iterator i;
5514 for (i = rs.begin(); i != rs.end(); ++i) {
5515 if ((ar = boost::dynamic_pointer_cast<AudioRegion>((*i)->region())) != 0) {
5517 yn = ar->fade_out_active ();
5519 yn = ar->fade_in_active ();
5525 if (i == rs.end()) {
5529 /* XXX should this undo-able? */
5531 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5532 if ((ar = boost::dynamic_pointer_cast<AudioRegion>((*i)->region())) == 0) {
5535 if (dir == 1 || dir == 0) {
5536 ar->set_fade_in_active (!yn);
5539 if (dir == -1 || dir == 0) {
5540 ar->set_fade_out_active (!yn);
5546 /** Update region fade visibility after its configuration has been changed */
5548 Editor::update_region_fade_visibility ()
5550 bool _fade_visibility = _session->config.get_show_region_fades ();
5552 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5553 AudioTimeAxisView* v = dynamic_cast<AudioTimeAxisView*>(*i);
5555 if (_fade_visibility) {
5556 v->audio_view()->show_all_fades ();
5558 v->audio_view()->hide_all_fades ();
5565 Editor::set_edit_point ()
5570 if (!mouse_frame (where, ignored)) {
5576 if (selection->markers.empty()) {
5578 mouse_add_new_marker (where);
5583 Location* loc = find_location_from_marker (selection->markers.front(), ignored);
5586 loc->move_to (where);
5592 Editor::set_playhead_cursor ()
5594 if (entered_marker) {
5595 _session->request_locate (entered_marker->position(), _session->transport_rolling());
5600 if (!mouse_frame (where, ignored)) {
5607 _session->request_locate (where, _session->transport_rolling());
5611 if ( Config->get_always_play_range() )
5612 cancel_time_selection();
5616 Editor::split_region ()
5618 if ( !selection->time.empty()) {
5619 separate_regions_between (selection->time);
5623 RegionSelection rs = get_regions_from_selection_and_edit_point ();
5625 framepos_t where = get_preferred_edit_position ();
5631 split_regions_at (where, rs);
5634 struct EditorOrderRouteSorter {
5635 bool operator() (boost::shared_ptr<Route> a, boost::shared_ptr<Route> b) {
5636 return a->order_key () < b->order_key ();
5641 Editor::select_next_route()
5643 if (selection->tracks.empty()) {
5644 selection->set (track_views.front());
5648 TimeAxisView* current = selection->tracks.front();
5652 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5653 if (*i == current) {
5655 if (i != track_views.end()) {
5658 current = (*(track_views.begin()));
5659 //selection->set (*(track_views.begin()));
5664 rui = dynamic_cast<RouteUI *>(current);
5665 } while ( current->hidden() || (rui != NULL && !rui->route()->active()));
5667 selection->set(current);
5669 ensure_track_visible(current);
5673 Editor::select_prev_route()
5675 if (selection->tracks.empty()) {
5676 selection->set (track_views.front());
5680 TimeAxisView* current = selection->tracks.front();
5684 for (TrackViewList::reverse_iterator i = track_views.rbegin(); i != track_views.rend(); ++i) {
5685 if (*i == current) {
5687 if (i != track_views.rend()) {
5690 current = *(track_views.rbegin());
5695 rui = dynamic_cast<RouteUI *>(current);
5696 } while ( current->hidden() || (rui != NULL && !rui->route()->active()));
5698 selection->set (current);
5700 ensure_track_visible(current);
5704 Editor::ensure_track_visible(TimeAxisView *track)
5706 if (track->hidden())
5709 double const current_view_min_y = vertical_adjustment.get_value();
5710 double const current_view_max_y = vertical_adjustment.get_value() + vertical_adjustment.get_page_size();
5712 double const track_min_y = track->y_position ();
5713 double const track_max_y = track->y_position () + track->effective_height ();
5715 if (track_min_y >= current_view_min_y &&
5716 track_max_y <= current_view_max_y) {
5722 if (track_min_y < current_view_min_y) {
5723 // Track is above the current view
5724 new_value = track_min_y;
5726 // Track is below the current view
5727 new_value = track->y_position () + track->effective_height() - vertical_adjustment.get_page_size();
5730 vertical_adjustment.set_value(new_value);
5734 Editor::set_loop_from_selection (bool play)
5736 if (_session == 0 || selection->time.empty()) {
5740 framepos_t start = selection->time[clicked_selection].start;
5741 framepos_t end = selection->time[clicked_selection].end;
5743 set_loop_range (start, end, _("set loop range from selection"));
5746 _session->request_play_loop (true);
5747 _session->request_locate (start, true);
5752 Editor::set_loop_from_edit_range (bool play)
5754 if (_session == 0) {
5761 if (!get_edit_op_range (start, end)) {
5765 set_loop_range (start, end, _("set loop range from edit range"));
5768 _session->request_play_loop (true);
5769 _session->request_locate (start, true);
5774 Editor::set_loop_from_region (bool play)
5776 framepos_t start = max_framepos;
5779 RegionSelection rs = get_regions_from_selection_and_entered ();
5785 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5786 if ((*i)->region()->position() < start) {
5787 start = (*i)->region()->position();
5789 if ((*i)->region()->last_frame() + 1 > end) {
5790 end = (*i)->region()->last_frame() + 1;
5794 set_loop_range (start, end, _("set loop range from region"));
5797 _session->request_play_loop (true);
5798 _session->request_locate (start, true);
5803 Editor::set_punch_from_selection ()
5805 if (_session == 0 || selection->time.empty()) {
5809 framepos_t start = selection->time[clicked_selection].start;
5810 framepos_t end = selection->time[clicked_selection].end;
5812 set_punch_range (start, end, _("set punch range from selection"));
5816 Editor::set_punch_from_edit_range ()
5818 if (_session == 0) {
5825 if (!get_edit_op_range (start, end)) {
5829 set_punch_range (start, end, _("set punch range from edit range"));
5833 Editor::set_punch_from_region ()
5835 framepos_t start = max_framepos;
5838 RegionSelection rs = get_regions_from_selection_and_entered ();
5844 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5845 if ((*i)->region()->position() < start) {
5846 start = (*i)->region()->position();
5848 if ((*i)->region()->last_frame() + 1 > end) {
5849 end = (*i)->region()->last_frame() + 1;
5853 set_punch_range (start, end, _("set punch range from region"));
5857 Editor::pitch_shift_region ()
5859 RegionSelection rs = get_regions_from_selection_and_entered ();
5861 RegionSelection audio_rs;
5862 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5863 if (dynamic_cast<AudioRegionView*> (*i)) {
5864 audio_rs.push_back (*i);
5868 if (audio_rs.empty()) {
5872 pitch_shift (audio_rs, 1.2);
5876 Editor::transpose_region ()
5878 RegionSelection rs = get_regions_from_selection_and_entered ();
5880 list<MidiRegionView*> midi_region_views;
5881 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5882 MidiRegionView* mrv = dynamic_cast<MidiRegionView*> (*i);
5884 midi_region_views.push_back (mrv);
5889 int const r = d.run ();
5890 if (r != RESPONSE_ACCEPT) {
5894 for (list<MidiRegionView*>::iterator i = midi_region_views.begin(); i != midi_region_views.end(); ++i) {
5895 (*i)->midi_region()->transpose (d.semitones ());
5900 Editor::set_tempo_from_region ()
5902 RegionSelection rs = get_regions_from_selection_and_entered ();
5904 if (!_session || rs.empty()) {
5908 RegionView* rv = rs.front();
5910 define_one_bar (rv->region()->position(), rv->region()->last_frame() + 1);
5914 Editor::use_range_as_bar ()
5916 framepos_t start, end;
5917 if (get_edit_op_range (start, end)) {
5918 define_one_bar (start, end);
5923 Editor::define_one_bar (framepos_t start, framepos_t end)
5925 framepos_t length = end - start;
5927 const Meter& m (_session->tempo_map().meter_at (start));
5929 /* length = 1 bar */
5931 /* now we want frames per beat.
5932 we have frames per bar, and beats per bar, so ...
5935 /* XXXX METER MATH */
5937 double frames_per_beat = length / m.divisions_per_bar();
5939 /* beats per minute = */
5941 double beats_per_minute = (_session->frame_rate() * 60.0) / frames_per_beat;
5943 /* now decide whether to:
5945 (a) set global tempo
5946 (b) add a new tempo marker
5950 const TempoSection& t (_session->tempo_map().tempo_section_at (start));
5952 bool do_global = false;
5954 if ((_session->tempo_map().n_tempos() == 1) && (_session->tempo_map().n_meters() == 1)) {
5956 /* only 1 tempo & 1 meter: ask if the user wants to set the tempo
5957 at the start, or create a new marker
5960 vector<string> options;
5961 options.push_back (_("Cancel"));
5962 options.push_back (_("Add new marker"));
5963 options.push_back (_("Set global tempo"));
5966 _("Define one bar"),
5967 _("Do you want to set the global tempo or add a new tempo marker?"),
5971 c.set_default_response (2);
5987 /* more than 1 tempo and/or meter section already, go ahead do the "usual":
5988 if the marker is at the region starter, change it, otherwise add
5993 begin_reversible_command (_("set tempo from region"));
5994 XMLNode& before (_session->tempo_map().get_state());
5997 _session->tempo_map().change_initial_tempo (beats_per_minute, t.note_type());
5998 } else if (t.frame() == start) {
5999 _session->tempo_map().change_existing_tempo_at (start, beats_per_minute, t.note_type());
6001 Timecode::BBT_Time bbt;
6002 _session->tempo_map().bbt_time (start, bbt);
6003 _session->tempo_map().add_tempo (Tempo (beats_per_minute, t.note_type()), bbt);
6006 XMLNode& after (_session->tempo_map().get_state());
6008 _session->add_command (new MementoCommand<TempoMap>(_session->tempo_map(), &before, &after));
6009 commit_reversible_command ();
6013 Editor::split_region_at_transients ()
6015 AnalysisFeatureList positions;
6017 RegionSelection rs = get_regions_from_selection_and_entered ();
6019 if (!_session || rs.empty()) {
6023 _session->begin_reversible_command (_("split regions"));
6025 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ) {
6027 RegionSelection::iterator tmp;
6032 boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion> ((*i)->region());
6034 if (ar && (ar->get_transients (positions) == 0)) {
6035 split_region_at_points ((*i)->region(), positions, true);
6042 _session->commit_reversible_command ();
6047 Editor::split_region_at_points (boost::shared_ptr<Region> r, AnalysisFeatureList& positions, bool can_ferret, bool select_new)
6049 bool use_rhythmic_rodent = false;
6051 boost::shared_ptr<Playlist> pl = r->playlist();
6053 list<boost::shared_ptr<Region> > new_regions;
6059 if (positions.empty()) {
6064 if (positions.size() > 20 && can_ferret) {
6065 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);
6066 MessageDialog msg (msgstr,
6069 Gtk::BUTTONS_OK_CANCEL);
6072 msg.add_button (_("Call for the Ferret!"), RESPONSE_APPLY);
6073 msg.set_secondary_text (_("Press OK to continue with this split operation\nor ask the Ferret dialog to tune the analysis"));
6075 msg.set_secondary_text (_("Press OK to continue with this split operation"));
6078 msg.set_title (_("Excessive split?"));
6081 int response = msg.run();
6087 case RESPONSE_APPLY:
6088 use_rhythmic_rodent = true;
6095 if (use_rhythmic_rodent) {
6096 show_rhythm_ferret ();
6100 AnalysisFeatureList::const_iterator x;
6102 pl->clear_changes ();
6103 pl->clear_owned_changes ();
6105 x = positions.begin();
6107 if (x == positions.end()) {
6112 pl->remove_region (r);
6116 while (x != positions.end()) {
6118 /* deal with positons that are out of scope of present region bounds */
6119 if (*x <= 0 || *x > r->length()) {
6124 /* file start = original start + how far we from the initial position ?
6127 framepos_t file_start = r->start() + pos;
6129 /* length = next position - current position
6132 framepos_t len = (*x) - pos;
6134 /* XXX we do we really want to allow even single-sample regions?
6135 shouldn't we have some kind of lower limit on region size?
6144 if (RegionFactory::region_name (new_name, r->name())) {
6148 /* do NOT announce new regions 1 by one, just wait till they are all done */
6152 plist.add (ARDOUR::Properties::start, file_start);
6153 plist.add (ARDOUR::Properties::length, len);
6154 plist.add (ARDOUR::Properties::name, new_name);
6155 plist.add (ARDOUR::Properties::layer, 0);
6157 boost::shared_ptr<Region> nr = RegionFactory::create (r->sources(), plist, false);
6158 /* because we set annouce to false, manually add the new region to the
6161 RegionFactory::map_add (nr);
6163 pl->add_region (nr, r->position() + pos);
6166 new_regions.push_front(nr);
6175 RegionFactory::region_name (new_name, r->name());
6177 /* Add the final region */
6180 plist.add (ARDOUR::Properties::start, r->start() + pos);
6181 plist.add (ARDOUR::Properties::length, r->last_frame() - (r->position() + pos) + 1);
6182 plist.add (ARDOUR::Properties::name, new_name);
6183 plist.add (ARDOUR::Properties::layer, 0);
6185 boost::shared_ptr<Region> nr = RegionFactory::create (r->sources(), plist, false);
6186 /* because we set annouce to false, manually add the new region to the
6189 RegionFactory::map_add (nr);
6190 pl->add_region (nr, r->position() + pos);
6193 new_regions.push_front(nr);
6198 /* We might have removed regions, which alters other regions' layering_index,
6199 so we need to do a recursive diff here.
6201 vector<Command*> cmds;
6203 _session->add_commands (cmds);
6205 _session->add_command (new StatefulDiffCommand (pl));
6209 for (list<boost::shared_ptr<Region> >::iterator i = new_regions.begin(); i != new_regions.end(); ++i){
6210 set_selected_regionview_from_region_list ((*i), Selection::Add);
6216 Editor::place_transient()
6222 RegionSelection rs = get_regions_from_selection_and_edit_point ();
6228 framepos_t where = get_preferred_edit_position();
6230 _session->begin_reversible_command (_("place transient"));
6232 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6233 framepos_t position = (*r)->region()->position();
6234 (*r)->region()->add_transient(where - position);
6237 _session->commit_reversible_command ();
6241 Editor::remove_transient(ArdourCanvas::Item* item)
6247 ArdourCanvas::Line* _line = reinterpret_cast<ArdourCanvas::Line*> (item);
6250 AudioRegionView* _arv = reinterpret_cast<AudioRegionView*> (item->get_data ("regionview"));
6251 _arv->remove_transient (*(float*) _line->get_data ("position"));
6255 Editor::snap_regions_to_grid ()
6257 list <boost::shared_ptr<Playlist > > used_playlists;
6259 RegionSelection rs = get_regions_from_selection_and_entered ();
6261 if (!_session || rs.empty()) {
6265 _session->begin_reversible_command (_("snap regions to grid"));
6267 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6269 boost::shared_ptr<Playlist> pl = (*r)->region()->playlist();
6271 if (!pl->frozen()) {
6272 /* we haven't seen this playlist before */
6274 /* remember used playlists so we can thaw them later */
6275 used_playlists.push_back(pl);
6279 framepos_t start_frame = (*r)->region()->first_frame ();
6280 snap_to (start_frame);
6281 (*r)->region()->set_position (start_frame);
6284 while (used_playlists.size() > 0) {
6285 list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
6287 used_playlists.pop_front();
6290 _session->commit_reversible_command ();
6294 Editor::close_region_gaps ()
6296 list <boost::shared_ptr<Playlist > > used_playlists;
6298 RegionSelection rs = get_regions_from_selection_and_entered ();
6300 if (!_session || rs.empty()) {
6304 Dialog dialog (_("Close Region Gaps"));
6307 table.set_spacings (12);
6308 table.set_border_width (12);
6309 Label* l = manage (left_aligned_label (_("Crossfade length")));
6310 table.attach (*l, 0, 1, 0, 1);
6312 SpinButton spin_crossfade (1, 0);
6313 spin_crossfade.set_range (0, 15);
6314 spin_crossfade.set_increments (1, 1);
6315 spin_crossfade.set_value (5);
6316 table.attach (spin_crossfade, 1, 2, 0, 1);
6318 table.attach (*manage (new Label (_("ms"))), 2, 3, 0, 1);
6320 l = manage (left_aligned_label (_("Pull-back length")));
6321 table.attach (*l, 0, 1, 1, 2);
6323 SpinButton spin_pullback (1, 0);
6324 spin_pullback.set_range (0, 100);
6325 spin_pullback.set_increments (1, 1);
6326 spin_pullback.set_value(30);
6327 table.attach (spin_pullback, 1, 2, 1, 2);
6329 table.attach (*manage (new Label (_("ms"))), 2, 3, 1, 2);
6331 dialog.get_vbox()->pack_start (table);
6332 dialog.add_button (Stock::CANCEL, RESPONSE_CANCEL);
6333 dialog.add_button (_("Ok"), RESPONSE_ACCEPT);
6336 if (dialog.run () == RESPONSE_CANCEL) {
6340 framepos_t crossfade_len = spin_crossfade.get_value();
6341 framepos_t pull_back_frames = spin_pullback.get_value();
6343 crossfade_len = lrintf (crossfade_len * _session->frame_rate()/1000);
6344 pull_back_frames = lrintf (pull_back_frames * _session->frame_rate()/1000);
6346 /* Iterate over the region list and make adjacent regions overlap by crossfade_len_ms */
6348 _session->begin_reversible_command (_("close region gaps"));
6351 boost::shared_ptr<Region> last_region;
6353 rs.sort_by_position_and_track();
6355 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6357 boost::shared_ptr<Playlist> pl = (*r)->region()->playlist();
6359 if (!pl->frozen()) {
6360 /* we haven't seen this playlist before */
6362 /* remember used playlists so we can thaw them later */
6363 used_playlists.push_back(pl);
6367 framepos_t position = (*r)->region()->position();
6369 if (idx == 0 || position < last_region->position()){
6370 last_region = (*r)->region();
6375 (*r)->region()->trim_front( (position - pull_back_frames));
6376 last_region->trim_end( (position - pull_back_frames + crossfade_len));
6378 last_region = (*r)->region();
6383 while (used_playlists.size() > 0) {
6384 list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
6386 used_playlists.pop_front();
6389 _session->commit_reversible_command ();
6393 Editor::tab_to_transient (bool forward)
6395 AnalysisFeatureList positions;
6397 RegionSelection rs = get_regions_from_selection_and_entered ();
6403 framepos_t pos = _session->audible_frame ();
6405 if (!selection->tracks.empty()) {
6407 /* don't waste time searching for transients in duplicate playlists.
6410 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
6412 for (TrackViewList::iterator t = ts.begin(); t != ts.end(); ++t) {
6414 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*t);
6417 boost::shared_ptr<Track> tr = rtv->track();
6419 boost::shared_ptr<Playlist> pl = tr->playlist ();
6421 framepos_t result = pl->find_next_transient (pos, forward ? 1 : -1);
6424 positions.push_back (result);
6437 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6438 (*r)->region()->get_transients (positions);
6442 TransientDetector::cleanup_transients (positions, _session->frame_rate(), 3.0);
6445 AnalysisFeatureList::iterator x;
6447 for (x = positions.begin(); x != positions.end(); ++x) {
6453 if (x != positions.end ()) {
6454 _session->request_locate (*x);
6458 AnalysisFeatureList::reverse_iterator x;
6460 for (x = positions.rbegin(); x != positions.rend(); ++x) {
6466 if (x != positions.rend ()) {
6467 _session->request_locate (*x);
6473 Editor::playhead_forward_to_grid ()
6479 framepos_t pos = playhead_cursor->current_frame ();
6480 if (pos < max_framepos - 1) {
6482 snap_to_internal (pos, 1, false);
6483 _session->request_locate (pos);
6489 Editor::playhead_backward_to_grid ()
6495 framepos_t pos = playhead_cursor->current_frame ();
6498 snap_to_internal (pos, -1, false);
6499 _session->request_locate (pos);
6504 Editor::set_track_height (Height h)
6506 TrackSelection& ts (selection->tracks);
6508 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
6509 (*x)->set_height_enum (h);
6514 Editor::toggle_tracks_active ()
6516 TrackSelection& ts (selection->tracks);
6518 bool target = false;
6524 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
6525 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*x);
6529 target = !rtv->_route->active();
6532 rtv->_route->set_active (target, this);
6538 Editor::remove_tracks ()
6540 TrackSelection& ts (selection->tracks);
6546 vector<string> choices;
6550 const char* trackstr;
6552 vector<boost::shared_ptr<Route> > routes;
6553 bool special_bus = false;
6555 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
6556 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*x);
6560 if (rtv->is_track()) {
6565 routes.push_back (rtv->_route);
6567 if (rtv->route()->is_master() || rtv->route()->is_monitor()) {
6572 if (special_bus && !Config->get_allow_special_bus_removal()) {
6573 MessageDialog msg (_("That would be bad news ...."),
6577 msg.set_secondary_text (string_compose (_(
6578 "Removing the master or monitor bus is such a bad idea\n\
6579 that %1 is not going to allow it.\n\
6581 If you really want to do this sort of thing\n\
6582 edit your ardour.rc file to set the\n\
6583 \"allow-special-bus-removal\" option to be \"yes\""), PROGRAM_NAME));
6590 if (ntracks + nbusses == 0) {
6595 trackstr = _("tracks");
6597 trackstr = _("track");
6601 busstr = _("busses");
6608 prompt = string_compose (_("Do you really want to remove %1 %2 and %3 %4?\n"
6609 "(You may also lose the playlists associated with the %2)\n\n"
6610 "This action cannot be undone, and the session file will be overwritten!"),
6611 ntracks, trackstr, nbusses, busstr);
6613 prompt = string_compose (_("Do you really want to remove %1 %2?\n"
6614 "(You may also lose the playlists associated with the %2)\n\n"
6615 "This action cannot be undone, and the session file will be overwritten!"),
6618 } else if (nbusses) {
6619 prompt = string_compose (_("Do you really want to remove %1 %2?\n\n"
6620 "This action cannot be undon, and the session file will be overwritten"),
6624 choices.push_back (_("No, do nothing."));
6625 if (ntracks + nbusses > 1) {
6626 choices.push_back (_("Yes, remove them."));
6628 choices.push_back (_("Yes, remove it."));
6633 title = string_compose (_("Remove %1"), trackstr);
6635 title = string_compose (_("Remove %1"), busstr);
6638 Choice prompter (title, prompt, choices);
6640 if (prompter.run () != 1) {
6644 for (vector<boost::shared_ptr<Route> >::iterator x = routes.begin(); x != routes.end(); ++x) {
6645 _session->remove_route (*x);
6650 Editor::do_insert_time ()
6652 if (selection->tracks.empty()) {
6656 InsertTimeDialog d (*this);
6657 int response = d.run ();
6659 if (response != RESPONSE_OK) {
6663 if (d.distance() == 0) {
6667 InsertTimeOption opt = d.intersected_region_action ();
6670 get_preferred_edit_position(),
6676 d.move_glued_markers(),
6677 d.move_locked_markers(),
6683 Editor::insert_time (
6684 framepos_t pos, framecnt_t frames, InsertTimeOption opt,
6685 bool all_playlists, bool ignore_music_glue, bool markers_too, bool glued_markers_too, bool locked_markers_too, bool tempo_too
6688 bool commit = false;
6690 if (Config->get_edit_mode() == Lock) {
6694 begin_reversible_command (_("insert time"));
6696 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
6698 for (TrackViewList::iterator x = ts.begin(); x != ts.end(); ++x) {
6702 /* don't operate on any playlist more than once, which could
6703 * happen if "all playlists" is enabled, but there is more
6704 * than 1 track using playlists "from" a given track.
6707 set<boost::shared_ptr<Playlist> > pl;
6709 if (all_playlists) {
6710 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*x);
6712 vector<boost::shared_ptr<Playlist> > all = _session->playlists->playlists_for_track (rtav->track ());
6713 for (vector<boost::shared_ptr<Playlist> >::iterator p = all.begin(); p != all.end(); ++p) {
6718 if ((*x)->playlist ()) {
6719 pl.insert ((*x)->playlist ());
6723 for (set<boost::shared_ptr<Playlist> >::iterator i = pl.begin(); i != pl.end(); ++i) {
6725 (*i)->clear_changes ();
6726 (*i)->clear_owned_changes ();
6728 if (opt == SplitIntersected) {
6732 (*i)->shift (pos, frames, (opt == MoveIntersected), ignore_music_glue);
6734 vector<Command*> cmds;
6736 _session->add_commands (cmds);
6738 _session->add_command (new StatefulDiffCommand (*i));
6743 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*x);
6745 rtav->route ()->shift (pos, frames);
6753 XMLNode& before (_session->locations()->get_state());
6754 Locations::LocationList copy (_session->locations()->list());
6756 for (Locations::LocationList::iterator i = copy.begin(); i != copy.end(); ++i) {
6758 Locations::LocationList::const_iterator tmp;
6760 bool const was_locked = (*i)->locked ();
6761 if (locked_markers_too) {
6765 if ((*i)->position_lock_style() == AudioTime || glued_markers_too) {
6767 if ((*i)->start() >= pos) {
6768 (*i)->set_start ((*i)->start() + frames);
6769 if (!(*i)->is_mark()) {
6770 (*i)->set_end ((*i)->end() + frames);
6783 XMLNode& after (_session->locations()->get_state());
6784 _session->add_command (new MementoCommand<Locations>(*_session->locations(), &before, &after));
6789 _session->tempo_map().insert_time (pos, frames);
6793 commit_reversible_command ();
6798 Editor::fit_selected_tracks ()
6800 if (!selection->tracks.empty()) {
6801 fit_tracks (selection->tracks);
6805 /* no selected tracks - use tracks with selected regions */
6807 if (!selection->regions.empty()) {
6808 for (RegionSelection::iterator r = selection->regions.begin(); r != selection->regions.end(); ++r) {
6809 tvl.push_back (&(*r)->get_time_axis_view ());
6815 } else if (internal_editing()) {
6816 /* no selected tracks, or regions, but in internal edit mode, so follow the mouse and use
6819 if (entered_track) {
6820 tvl.push_back (entered_track);
6828 Editor::fit_tracks (TrackViewList & tracks)
6830 if (tracks.empty()) {
6834 uint32_t child_heights = 0;
6835 int visible_tracks = 0;
6837 for (TrackSelection::iterator t = tracks.begin(); t != tracks.end(); ++t) {
6839 if (!(*t)->marked_for_display()) {
6843 child_heights += (*t)->effective_height() - (*t)->current_height();
6847 uint32_t h = (uint32_t) floor ((_visible_canvas_height - child_heights) / visible_tracks);
6848 double first_y_pos = DBL_MAX;
6850 if (h < TimeAxisView::preset_height (HeightSmall)) {
6851 MessageDialog msg (*this, _("There are too many tracks to fit in the current window"));
6852 /* too small to be displayed */
6856 undo_visual_stack.push_back (current_visual_state (true));
6857 no_save_visual = true;
6859 /* build a list of all tracks, including children */
6862 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
6864 TimeAxisView::Children c = (*i)->get_child_list ();
6865 for (TimeAxisView::Children::iterator j = c.begin(); j != c.end(); ++j) {
6866 all.push_back (j->get());
6870 /* operate on all tracks, hide unselected ones that are in the middle of selected ones */
6872 bool prev_was_selected = false;
6873 bool is_selected = tracks.contains (all.front());
6874 bool next_is_selected;
6876 for (TrackViewList::iterator t = all.begin(); t != all.end(); ++t) {
6878 TrackViewList::iterator next;
6883 if (next != all.end()) {
6884 next_is_selected = tracks.contains (*next);
6886 next_is_selected = false;
6889 if ((*t)->marked_for_display ()) {
6891 (*t)->set_height (h);
6892 first_y_pos = std::min ((*t)->y_position (), first_y_pos);
6894 if (prev_was_selected && next_is_selected) {
6895 hide_track_in_display (*t);
6900 prev_was_selected = is_selected;
6901 is_selected = next_is_selected;
6905 set the controls_layout height now, because waiting for its size
6906 request signal handler will cause the vertical adjustment setting to fail
6909 controls_layout.property_height () = _full_canvas_height;
6910 vertical_adjustment.set_value (first_y_pos);
6912 redo_visual_stack.push_back (current_visual_state (true));
6916 Editor::save_visual_state (uint32_t n)
6918 while (visual_states.size() <= n) {
6919 visual_states.push_back (0);
6922 if (visual_states[n] != 0) {
6923 delete visual_states[n];
6926 visual_states[n] = current_visual_state (true);
6931 Editor::goto_visual_state (uint32_t n)
6933 if (visual_states.size() <= n) {
6937 if (visual_states[n] == 0) {
6941 use_visual_state (*visual_states[n]);
6945 Editor::start_visual_state_op (uint32_t n)
6947 save_visual_state (n);
6949 PopUp* pup = new PopUp (WIN_POS_MOUSE, 1000, true);
6951 snprintf (buf, sizeof (buf), _("Saved view %u"), n+1);
6952 pup->set_text (buf);
6957 Editor::cancel_visual_state_op (uint32_t n)
6959 goto_visual_state (n);
6963 Editor::toggle_region_mute ()
6965 if (_ignore_region_action) {
6969 RegionSelection rs = get_regions_from_selection_and_entered ();
6975 if (rs.size() > 1) {
6976 begin_reversible_command (_("mute regions"));
6978 begin_reversible_command (_("mute region"));
6981 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
6983 (*i)->region()->playlist()->clear_changes ();
6984 (*i)->region()->set_muted (!(*i)->region()->muted ());
6985 _session->add_command (new StatefulDiffCommand ((*i)->region()->playlist()));
6989 commit_reversible_command ();
6993 Editor::combine_regions ()
6995 /* foreach track with selected regions, take all selected regions
6996 and join them into a new region containing the subregions (as a
7000 typedef set<RouteTimeAxisView*> RTVS;
7003 if (selection->regions.empty()) {
7007 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
7008 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(&(*i)->get_time_axis_view());
7011 tracks.insert (rtv);
7015 begin_reversible_command (_("combine regions"));
7017 vector<RegionView*> new_selection;
7019 for (RTVS::iterator i = tracks.begin(); i != tracks.end(); ++i) {
7022 if ((rv = (*i)->combine_regions ()) != 0) {
7023 new_selection.push_back (rv);
7027 selection->clear_regions ();
7028 for (vector<RegionView*>::iterator i = new_selection.begin(); i != new_selection.end(); ++i) {
7029 selection->add (*i);
7032 commit_reversible_command ();
7036 Editor::uncombine_regions ()
7038 typedef set<RouteTimeAxisView*> RTVS;
7041 if (selection->regions.empty()) {
7045 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
7046 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(&(*i)->get_time_axis_view());
7049 tracks.insert (rtv);
7053 begin_reversible_command (_("uncombine regions"));
7055 for (RTVS::iterator i = tracks.begin(); i != tracks.end(); ++i) {
7056 (*i)->uncombine_regions ();
7059 commit_reversible_command ();
7063 Editor::toggle_midi_input_active (bool flip_others)
7066 boost::shared_ptr<RouteList> rl (new RouteList);
7068 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
7069 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
7075 boost::shared_ptr<MidiTrack> mt = rtav->midi_track();
7078 rl->push_back (rtav->route());
7079 onoff = !mt->input_active();
7083 _session->set_exclusive_input_active (rl, onoff, flip_others);