2 Copyright (C) 2000-2004 Paul Davis
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 /* Note: public Editor methods are documented in public_editor.h */
30 #include "pbd/error.h"
31 #include "pbd/basename.h"
32 #include "pbd/pthread_utils.h"
33 #include "pbd/memento_command.h"
34 #include "pbd/unwind.h"
35 #include "pbd/whitespace.h"
36 #include "pbd/stateful_diff_command.h"
38 #include <gtkmm2ext/utils.h>
39 #include <gtkmm2ext/choice.h>
40 #include <gtkmm2ext/popup.h>
42 #include "ardour/audio_track.h"
43 #include "ardour/audioregion.h"
44 #include "ardour/dB.h"
45 #include "ardour/location.h"
46 #include "ardour/midi_region.h"
47 #include "ardour/midi_track.h"
48 #include "ardour/operations.h"
49 #include "ardour/playlist_factory.h"
50 #include "ardour/quantize.h"
51 #include "ardour/region_factory.h"
52 #include "ardour/reverse.h"
53 #include "ardour/session.h"
54 #include "ardour/session_playlists.h"
55 #include "ardour/strip_silence.h"
56 #include "ardour/transient_detector.h"
58 #include "canvas/canvas.h"
61 #include "ardour_ui.h"
62 #include "audio_region_view.h"
63 #include "audio_streamview.h"
64 #include "audio_time_axis.h"
65 #include "automation_time_axis.h"
66 #include "control_point.h"
70 #include "editor_cursors.h"
71 #include "editor_drag.h"
72 #include "editor_regions.h"
73 #include "editor_routes.h"
74 #include "gui_thread.h"
75 #include "insert_time_dialog.h"
76 #include "interthread_progress_window.h"
78 #include "midi_region_view.h"
79 #include "mouse_cursors.h"
80 #include "normalize_dialog.h"
81 #include "patch_change_dialog.h"
82 #include "quantize_dialog.h"
83 #include "region_gain_line.h"
84 #include "rgb_macros.h"
85 #include "route_time_axis.h"
86 #include "selection.h"
87 #include "selection_templates.h"
88 #include "streamview.h"
89 #include "strip_silence_dialog.h"
90 #include "time_axis_view.h"
91 #include "transpose_dialog.h"
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 TrackViewList::reverse_iterator next = track_views.rend();
1337 std::pair<TimeAxisView*,double> res;
1338 const double bottom_of_trackviews = vertical_adjustment.get_value() + vertical_adjustment.get_page_size() - 1;
1340 for (TrackViewList::reverse_iterator t = track_views.rbegin(); t != track_views.rend(); ++t) {
1341 if ((*t)->hidden()) {
1345 /* If this is the bottom visible trackview, we want to display
1349 res = (*t)->covers_y_position (bottom_of_trackviews);
1355 ++next; // moves "next" towards the "front" since it is a reverse iterator
1358 /* move to the track below the first one that covers the */
1360 if (next != track_views.rend()) {
1361 ensure_track_visible (*next);
1369 Editor::scroll_up_one_track ()
1371 double vertical_pos = vertical_adjustment.get_value ();
1373 TrackViewList::iterator prev = track_views.end();
1374 std::pair<TimeAxisView*,double> res;
1376 for (TrackViewList::iterator t = track_views.begin(); t != track_views.end(); ++t) {
1378 if ((*t)->hidden()) {
1382 /* find the trackview at the top of the trackview group */
1383 res = (*t)->covers_y_position (vertical_pos);
1386 cerr << res.first->name() << " covers the top\n";
1393 if (prev != track_views.end()) {
1394 ensure_track_visible (*prev);
1404 Editor::tav_zoom_step (bool coarser)
1406 _routes->suspend_redisplay ();
1410 if (selection->tracks.empty()) {
1413 ts = &selection->tracks;
1416 for (TrackViewList::iterator i = ts->begin(); i != ts->end(); ++i) {
1417 TimeAxisView *tv = (static_cast<TimeAxisView*>(*i));
1418 tv->step_height (coarser);
1421 _routes->resume_redisplay ();
1425 Editor::tav_zoom_smooth (bool coarser, bool force_all)
1427 _routes->suspend_redisplay ();
1431 if (selection->tracks.empty() || force_all) {
1434 ts = &selection->tracks;
1437 for (TrackViewList::iterator i = ts->begin(); i != ts->end(); ++i) {
1438 TimeAxisView *tv = (static_cast<TimeAxisView*>(*i));
1439 uint32_t h = tv->current_height ();
1444 if (h >= TimeAxisView::preset_height (HeightSmall)) {
1449 tv->set_height (h + 5);
1453 _routes->resume_redisplay ();
1457 Editor::clamp_samples_per_pixel (framecnt_t& fpp) const
1459 bool clamped = false;
1469 sr = _session->frame_rate ();
1474 const framecnt_t three_days = 3 * 24 * 60 * 60 * sr;
1475 const framecnt_t lots_of_pixels = 4000;
1477 /* if the zoom level is greater than what you'd get trying to display 3
1478 * days of audio on a really big screen, scale it down.
1481 if (fpp * lots_of_pixels > three_days) {
1482 fpp = three_days / _track_canvas->width();
1490 Editor::temporal_zoom_step (bool coarser)
1492 ENSURE_GUI_THREAD (*this, &Editor::temporal_zoom_step, coarser)
1494 framecnt_t nspp = samples_per_pixel;
1502 temporal_zoom (nspp);
1506 Editor::temporal_zoom (framecnt_t fpp)
1512 framepos_t current_page = current_page_samples();
1513 framepos_t current_leftmost = leftmost_frame;
1514 framepos_t current_rightmost;
1515 framepos_t current_center;
1516 framepos_t new_page_size;
1517 framepos_t half_page_size;
1518 framepos_t leftmost_after_zoom = 0;
1520 bool in_track_canvas;
1524 clamp_samples_per_pixel (fpp);
1525 if (fpp == samples_per_pixel) {
1529 // Imposing an arbitrary limit to zoom out as too much zoom out produces
1530 // segfaults for lack of memory. If somebody decides this is not high enough I
1531 // believe it can be raisen to higher values but some limit must be in place.
1533 // This constant represents 1 day @ 48kHz on a 1600 pixel wide display
1534 // all of which is used for the editor track displays. The whole day
1535 // would be 4147200000 samples, so 2592000 samples per pixel.
1537 nfpp = min (fpp, (framecnt_t) 2592000);
1538 nfpp = max ((framecnt_t) 1, fpp);
1540 new_page_size = (framepos_t) floor (_visible_canvas_width * nfpp);
1541 half_page_size = new_page_size / 2;
1543 switch (zoom_focus) {
1545 leftmost_after_zoom = current_leftmost;
1548 case ZoomFocusRight:
1549 current_rightmost = leftmost_frame + current_page;
1550 if (current_rightmost < new_page_size) {
1551 leftmost_after_zoom = 0;
1553 leftmost_after_zoom = current_rightmost - new_page_size;
1557 case ZoomFocusCenter:
1558 current_center = current_leftmost + (current_page/2);
1559 if (current_center < half_page_size) {
1560 leftmost_after_zoom = 0;
1562 leftmost_after_zoom = current_center - half_page_size;
1566 case ZoomFocusPlayhead:
1567 /* centre playhead */
1568 l = playhead_cursor->current_frame () - (new_page_size * 0.5);
1571 leftmost_after_zoom = 0;
1572 } else if (l > max_framepos) {
1573 leftmost_after_zoom = max_framepos - new_page_size;
1575 leftmost_after_zoom = (framepos_t) l;
1579 case ZoomFocusMouse:
1580 /* try to keep the mouse over the same point in the display */
1582 if (!mouse_frame (where, in_track_canvas)) {
1583 /* use playhead instead */
1584 where = playhead_cursor->current_frame ();
1586 if (where < half_page_size) {
1587 leftmost_after_zoom = 0;
1589 leftmost_after_zoom = where - half_page_size;
1594 l = - ((new_page_size * ((where - current_leftmost)/(double)current_page)) - where);
1597 leftmost_after_zoom = 0;
1598 } else if (l > max_framepos) {
1599 leftmost_after_zoom = max_framepos - new_page_size;
1601 leftmost_after_zoom = (framepos_t) l;
1608 /* try to keep the edit point in the same place */
1609 where = get_preferred_edit_position ();
1613 double l = - ((new_page_size * ((where - current_leftmost)/(double)current_page)) - where);
1616 leftmost_after_zoom = 0;
1617 } else if (l > max_framepos) {
1618 leftmost_after_zoom = max_framepos - new_page_size;
1620 leftmost_after_zoom = (framepos_t) l;
1624 /* edit point not defined */
1631 // leftmost_after_zoom = min (leftmost_after_zoom, _session->current_end_frame());
1633 reposition_and_zoom (leftmost_after_zoom, nfpp);
1637 Editor::temporal_zoom_region (bool both_axes)
1639 framepos_t start = max_framepos;
1641 set<TimeAxisView*> tracks;
1643 RegionSelection rs = get_regions_from_selection_and_entered ();
1649 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
1651 if ((*i)->region()->position() < start) {
1652 start = (*i)->region()->position();
1655 if ((*i)->region()->last_frame() + 1 > end) {
1656 end = (*i)->region()->last_frame() + 1;
1659 tracks.insert (&((*i)->get_time_axis_view()));
1662 /* now comes an "interesting" hack ... make sure we leave a little space
1663 at each end of the editor so that the zoom doesn't fit the region
1664 precisely to the screen.
1667 GdkScreen* screen = gdk_screen_get_default ();
1668 gint pixwidth = gdk_screen_get_width (screen);
1669 gint mmwidth = gdk_screen_get_width_mm (screen);
1670 double pix_per_mm = (double) pixwidth/ (double) mmwidth;
1671 double one_centimeter_in_pixels = pix_per_mm * 10.0;
1673 if ((start == 0 && end == 0) || end < start) {
1677 framepos_t range = end - start;
1678 double new_fpp = (double) range / (double) _visible_canvas_width;
1679 framepos_t extra_samples = (framepos_t) floor (one_centimeter_in_pixels * new_fpp);
1681 if (start > extra_samples) {
1682 start -= extra_samples;
1687 if (max_framepos - extra_samples > end) {
1688 end += extra_samples;
1693 /* if we're zooming on both axes we need to save track heights etc.
1696 undo_visual_stack.push_back (current_visual_state (both_axes));
1698 PBD::Unwinder<bool> nsv (no_save_visual, true);
1700 temporal_zoom_by_frame (start, end);
1703 uint32_t per_track_height = (uint32_t) floor ((_visible_canvas_height - 10.0) / tracks.size());
1705 /* set visible track heights appropriately */
1707 for (set<TimeAxisView*>::iterator t = tracks.begin(); t != tracks.end(); ++t) {
1708 (*t)->set_height (per_track_height);
1711 /* hide irrelevant tracks */
1713 _routes->suspend_redisplay ();
1715 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1716 if (find (tracks.begin(), tracks.end(), (*i)) == tracks.end()) {
1717 hide_track_in_display (*i);
1721 _routes->resume_redisplay ();
1723 vertical_adjustment.set_value (0.0);
1726 redo_visual_stack.push_back (current_visual_state (both_axes));
1730 Editor::zoom_to_region (bool both_axes)
1732 temporal_zoom_region (both_axes);
1736 Editor::temporal_zoom_selection ()
1738 if (!selection) return;
1740 if (selection->time.empty()) {
1744 framepos_t start = selection->time[clicked_selection].start;
1745 framepos_t end = selection->time[clicked_selection].end;
1747 temporal_zoom_by_frame (start, end);
1751 Editor::temporal_zoom_session ()
1753 ENSURE_GUI_THREAD (*this, &Editor::temporal_zoom_session)
1756 framecnt_t const l = _session->current_end_frame() - _session->current_start_frame();
1757 double s = _session->current_start_frame() - l * 0.01;
1761 framecnt_t const e = _session->current_end_frame() + l * 0.01;
1762 temporal_zoom_by_frame (framecnt_t (s), e);
1767 Editor::temporal_zoom_by_frame (framepos_t start, framepos_t end)
1769 if (!_session) return;
1771 if ((start == 0 && end == 0) || end < start) {
1775 framepos_t range = end - start;
1777 double const new_fpp = (double) range / (double) _visible_canvas_width;
1779 framepos_t new_page = (framepos_t) floor (_visible_canvas_width * new_fpp);
1780 framepos_t middle = (framepos_t) floor ((double) start + ((double) range / 2.0f));
1781 framepos_t new_leftmost = (framepos_t) floor ((double) middle - ((double) new_page / 2.0f));
1783 if (new_leftmost > middle) {
1787 if (new_leftmost < 0) {
1791 reposition_and_zoom (new_leftmost, new_fpp);
1795 Editor::temporal_zoom_to_frame (bool coarser, framepos_t frame)
1801 framecnt_t range_before = frame - leftmost_frame;
1805 if (samples_per_pixel <= 1) {
1808 new_spp = samples_per_pixel + (samples_per_pixel/2);
1810 range_before += range_before/2;
1812 if (samples_per_pixel >= 1) {
1813 new_spp = samples_per_pixel - (samples_per_pixel/2);
1815 /* could bail out here since we cannot zoom any finer,
1816 but leave that to the clamp_samples_per_pixel() and
1819 new_spp = samples_per_pixel;
1822 range_before -= range_before/2;
1825 clamp_samples_per_pixel (new_spp);
1827 if (new_spp == samples_per_pixel) {
1831 /* zoom focus is automatically taken as @param frame when this
1835 framepos_t new_leftmost = frame - (framepos_t)range_before;
1837 if (new_leftmost > frame) {
1841 if (new_leftmost < 0) {
1845 reposition_and_zoom (new_leftmost, new_spp);
1850 Editor::choose_new_marker_name(string &name) {
1852 if (!Config->get_name_new_markers()) {
1853 /* don't prompt user for a new name */
1857 ArdourPrompter dialog (true);
1859 dialog.set_prompt (_("New Name:"));
1861 dialog.set_title (_("New Location Marker"));
1863 dialog.set_name ("MarkNameWindow");
1864 dialog.set_size_request (250, -1);
1865 dialog.set_position (Gtk::WIN_POS_MOUSE);
1867 dialog.add_button (Stock::OK, RESPONSE_ACCEPT);
1868 dialog.set_initial_text (name);
1872 switch (dialog.run ()) {
1873 case RESPONSE_ACCEPT:
1879 dialog.get_result(name);
1886 Editor::add_location_from_selection ()
1890 if (selection->time.empty()) {
1894 if (_session == 0 || clicked_axisview == 0) {
1898 framepos_t start = selection->time[clicked_selection].start;
1899 framepos_t end = selection->time[clicked_selection].end;
1901 _session->locations()->next_available_name(rangename,"selection");
1902 Location *location = new Location (*_session, start, end, rangename, Location::IsRangeMarker);
1904 _session->begin_reversible_command (_("add marker"));
1905 XMLNode &before = _session->locations()->get_state();
1906 _session->locations()->add (location, true);
1907 XMLNode &after = _session->locations()->get_state();
1908 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
1909 _session->commit_reversible_command ();
1913 Editor::add_location_mark (framepos_t where)
1917 select_new_marker = true;
1919 _session->locations()->next_available_name(markername,"mark");
1920 if (!choose_new_marker_name(markername)) {
1923 Location *location = new Location (*_session, where, where, markername, Location::IsMark);
1924 _session->begin_reversible_command (_("add marker"));
1925 XMLNode &before = _session->locations()->get_state();
1926 _session->locations()->add (location, true);
1927 XMLNode &after = _session->locations()->get_state();
1928 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
1929 _session->commit_reversible_command ();
1933 Editor::add_location_from_playhead_cursor ()
1935 add_location_mark (_session->audible_frame());
1938 /** Add a range marker around each selected region */
1940 Editor::add_locations_from_region ()
1942 RegionSelection rs = get_regions_from_selection_and_entered ();
1948 _session->begin_reversible_command (selection->regions.size () > 1 ? _("add markers") : _("add marker"));
1949 XMLNode &before = _session->locations()->get_state();
1951 for (RegionSelection::iterator i = rs.begin (); i != rs.end (); ++i) {
1953 boost::shared_ptr<Region> region = (*i)->region ();
1955 Location *location = new Location (*_session, region->position(), region->last_frame(), region->name(), Location::IsRangeMarker);
1957 _session->locations()->add (location, true);
1960 XMLNode &after = _session->locations()->get_state();
1961 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
1962 _session->commit_reversible_command ();
1965 /** Add a single range marker around all selected regions */
1967 Editor::add_location_from_region ()
1969 RegionSelection rs = get_regions_from_selection_and_entered ();
1975 _session->begin_reversible_command (_("add marker"));
1976 XMLNode &before = _session->locations()->get_state();
1980 if (rs.size() > 1) {
1981 _session->locations()->next_available_name(markername, "regions");
1983 RegionView* rv = *(rs.begin());
1984 boost::shared_ptr<Region> region = rv->region();
1985 markername = region->name();
1988 if (!choose_new_marker_name(markername)) {
1992 // single range spanning all selected
1993 Location *location = new Location (*_session, selection->regions.start(), selection->regions.end_frame(), markername, Location::IsRangeMarker);
1994 _session->locations()->add (location, true);
1996 XMLNode &after = _session->locations()->get_state();
1997 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
1998 _session->commit_reversible_command ();
2004 Editor::jump_forward_to_mark ()
2010 framepos_t pos = _session->locations()->first_mark_after (playhead_cursor->current_frame());
2016 _session->request_locate (pos, _session->transport_rolling());
2020 Editor::jump_backward_to_mark ()
2026 framepos_t pos = _session->locations()->first_mark_before (playhead_cursor->current_frame());
2032 _session->request_locate (pos, _session->transport_rolling());
2038 framepos_t const pos = _session->audible_frame ();
2041 _session->locations()->next_available_name (markername, "mark");
2043 if (!choose_new_marker_name (markername)) {
2047 _session->locations()->add (new Location (*_session, pos, 0, markername, Location::IsMark), true);
2051 Editor::clear_markers ()
2054 _session->begin_reversible_command (_("clear markers"));
2055 XMLNode &before = _session->locations()->get_state();
2056 _session->locations()->clear_markers ();
2057 XMLNode &after = _session->locations()->get_state();
2058 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2059 _session->commit_reversible_command ();
2064 Editor::clear_ranges ()
2067 _session->begin_reversible_command (_("clear ranges"));
2068 XMLNode &before = _session->locations()->get_state();
2070 Location * looploc = _session->locations()->auto_loop_location();
2071 Location * punchloc = _session->locations()->auto_punch_location();
2072 Location * sessionloc = _session->locations()->session_range_location();
2074 _session->locations()->clear_ranges ();
2076 if (looploc) _session->locations()->add (looploc);
2077 if (punchloc) _session->locations()->add (punchloc);
2078 if (sessionloc) _session->locations()->add (sessionloc);
2080 XMLNode &after = _session->locations()->get_state();
2081 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2082 _session->commit_reversible_command ();
2087 Editor::clear_locations ()
2089 _session->begin_reversible_command (_("clear locations"));
2090 XMLNode &before = _session->locations()->get_state();
2091 _session->locations()->clear ();
2092 XMLNode &after = _session->locations()->get_state();
2093 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2094 _session->commit_reversible_command ();
2095 _session->locations()->clear ();
2099 Editor::unhide_markers ()
2101 for (LocationMarkerMap::iterator i = location_markers.begin(); i != location_markers.end(); ++i) {
2102 Location *l = (*i).first;
2103 if (l->is_hidden() && l->is_mark()) {
2104 l->set_hidden(false, this);
2110 Editor::unhide_ranges ()
2112 for (LocationMarkerMap::iterator i = location_markers.begin(); i != location_markers.end(); ++i) {
2113 Location *l = (*i).first;
2114 if (l->is_hidden() && l->is_range_marker()) {
2115 l->set_hidden(false, this);
2120 /* INSERT/REPLACE */
2123 Editor::insert_region_list_drag (boost::shared_ptr<Region> region, int x, int y)
2127 RouteTimeAxisView *rtv = 0;
2128 boost::shared_ptr<Playlist> playlist;
2131 event.type = GDK_BUTTON_RELEASE;
2135 where = window_event_sample (&event, &cx, &cy);
2137 if (where < leftmost_frame || where > leftmost_frame + current_page_samples()) {
2138 /* clearly outside canvas area */
2142 std::pair<TimeAxisView*, int> tv = trackview_by_y_position (cy);
2143 if (tv.first == 0) {
2147 if ((rtv = dynamic_cast<RouteTimeAxisView*> (tv.first)) == 0) {
2151 if ((playlist = rtv->playlist()) == 0) {
2157 begin_reversible_command (_("insert dragged region"));
2158 playlist->clear_changes ();
2159 playlist->add_region (RegionFactory::create (region, true), where, 1.0);
2160 _session->add_command(new StatefulDiffCommand (playlist));
2161 commit_reversible_command ();
2165 Editor::insert_route_list_drag (boost::shared_ptr<Route> route, int x, int y)
2168 RouteTimeAxisView *dest_rtv = 0;
2169 RouteTimeAxisView *source_rtv = 0;
2172 event.type = GDK_BUTTON_RELEASE;
2176 window_event_sample (&event, &cx, &cy);
2178 std::pair<TimeAxisView*, int> const tv = trackview_by_y_position (cy);
2179 if (tv.first == 0) {
2183 if ((dest_rtv = dynamic_cast<RouteTimeAxisView*> (tv.first)) == 0) {
2187 /* use this drag source to add underlay to a track. But we really don't care
2188 about the Route, only the view of the route, so find it first */
2189 for(TrackViewList::iterator it = track_views.begin(); it != track_views.end(); ++it) {
2190 if((source_rtv = dynamic_cast<RouteTimeAxisView*>(*it)) == 0) {
2194 if(source_rtv->route() == route && source_rtv != dest_rtv) {
2195 dest_rtv->add_underlay(source_rtv->view());
2202 Editor::insert_region_list_selection (float times)
2204 RouteTimeAxisView *tv = 0;
2205 boost::shared_ptr<Playlist> playlist;
2207 if (clicked_routeview != 0) {
2208 tv = clicked_routeview;
2209 } else if (!selection->tracks.empty()) {
2210 if ((tv = dynamic_cast<RouteTimeAxisView*>(selection->tracks.front())) == 0) {
2213 } else if (entered_track != 0) {
2214 if ((tv = dynamic_cast<RouteTimeAxisView*>(entered_track)) == 0) {
2221 if ((playlist = tv->playlist()) == 0) {
2225 boost::shared_ptr<Region> region = _regions->get_single_selection ();
2230 begin_reversible_command (_("insert region"));
2231 playlist->clear_changes ();
2232 playlist->add_region ((RegionFactory::create (region, true)), get_preferred_edit_position(), times);
2233 _session->add_command(new StatefulDiffCommand (playlist));
2234 commit_reversible_command ();
2237 /* BUILT-IN EFFECTS */
2240 Editor::reverse_selection ()
2245 /* GAIN ENVELOPE EDITING */
2248 Editor::edit_envelope ()
2255 Editor::transition_to_rolling (bool fwd)
2261 if (_session->config.get_external_sync()) {
2262 switch (Config->get_sync_source()) {
2266 /* transport controlled by the master */
2271 if (_session->is_auditioning()) {
2272 _session->cancel_audition ();
2276 _session->request_transport_speed (fwd ? 1.0f : -1.0f);
2280 Editor::play_from_start ()
2282 _session->request_locate (_session->current_start_frame(), true);
2286 Editor::play_from_edit_point ()
2288 _session->request_locate (get_preferred_edit_position(), true);
2292 Editor::play_from_edit_point_and_return ()
2294 framepos_t start_frame;
2295 framepos_t return_frame;
2297 start_frame = get_preferred_edit_position (true);
2299 if (_session->transport_rolling()) {
2300 _session->request_locate (start_frame, false);
2304 /* don't reset the return frame if its already set */
2306 if ((return_frame = _session->requested_return_frame()) < 0) {
2307 return_frame = _session->audible_frame();
2310 if (start_frame >= 0) {
2311 _session->request_roll_at_and_return (start_frame, return_frame);
2316 Editor::play_selection ()
2318 if (selection->time.empty()) {
2322 _session->request_play_range (&selection->time, true);
2326 Editor::get_preroll ()
2328 return 1.0 /*Config->get_edit_preroll_seconds()*/ * _session->frame_rate();
2333 Editor::maybe_locate_with_edit_preroll ( framepos_t location )
2335 if ( _session->transport_rolling() || !Config->get_always_play_range() )
2338 location -= get_preroll();
2340 //don't try to locate before the beginning of time
2344 //if follow_playhead is on, keep the playhead on the screen
2345 if ( _follow_playhead )
2346 if ( location < leftmost_frame )
2347 location = leftmost_frame;
2349 _session->request_locate( location );
2353 Editor::play_with_preroll ()
2355 if (selection->time.empty()) {
2358 framepos_t preroll = get_preroll();
2360 framepos_t start = 0;
2361 if (selection->time[clicked_selection].start > preroll)
2362 start = selection->time[clicked_selection].start - preroll;
2364 framepos_t end = selection->time[clicked_selection].end + preroll;
2366 AudioRange ar (start, end, 0);
2367 list<AudioRange> lar;
2370 _session->request_play_range (&lar, true);
2375 Editor::play_location (Location& location)
2377 if (location.start() <= location.end()) {
2381 _session->request_bounded_roll (location.start(), location.end());
2385 Editor::loop_location (Location& location)
2387 if (location.start() <= location.end()) {
2393 if ((tll = transport_loop_location()) != 0) {
2394 tll->set (location.start(), location.end());
2396 // enable looping, reposition and start rolling
2397 _session->request_play_loop (true);
2398 _session->request_locate (tll->start(), true);
2403 Editor::do_layer_operation (LayerOperation op)
2405 if (selection->regions.empty ()) {
2409 bool const multiple = selection->regions.size() > 1;
2413 begin_reversible_command (_("raise regions"));
2415 begin_reversible_command (_("raise region"));
2421 begin_reversible_command (_("raise regions to top"));
2423 begin_reversible_command (_("raise region to top"));
2429 begin_reversible_command (_("lower regions"));
2431 begin_reversible_command (_("lower region"));
2437 begin_reversible_command (_("lower regions to bottom"));
2439 begin_reversible_command (_("lower region"));
2444 set<boost::shared_ptr<Playlist> > playlists = selection->regions.playlists ();
2445 for (set<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
2446 (*i)->clear_owned_changes ();
2449 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
2450 boost::shared_ptr<Region> r = (*i)->region ();
2462 r->lower_to_bottom ();
2466 for (set<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
2467 vector<Command*> cmds;
2469 _session->add_commands (cmds);
2472 commit_reversible_command ();
2476 Editor::raise_region ()
2478 do_layer_operation (Raise);
2482 Editor::raise_region_to_top ()
2484 do_layer_operation (RaiseToTop);
2488 Editor::lower_region ()
2490 do_layer_operation (Lower);
2494 Editor::lower_region_to_bottom ()
2496 do_layer_operation (LowerToBottom);
2499 /** Show the region editor for the selected regions */
2501 Editor::show_region_properties ()
2503 selection->foreach_regionview (&RegionView::show_region_editor);
2506 /** Show the midi list editor for the selected MIDI regions */
2508 Editor::show_midi_list_editor ()
2510 selection->foreach_midi_regionview (&MidiRegionView::show_list_editor);
2514 Editor::rename_region ()
2516 RegionSelection rs = get_regions_from_selection_and_entered ();
2522 ArdourDialog d (*this, _("Rename Region"), true, false);
2524 Label label (_("New name:"));
2527 hbox.set_spacing (6);
2528 hbox.pack_start (label, false, false);
2529 hbox.pack_start (entry, true, true);
2531 d.get_vbox()->set_border_width (12);
2532 d.get_vbox()->pack_start (hbox, false, false);
2534 d.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
2535 d.add_button(Gtk::Stock::OK, Gtk::RESPONSE_OK);
2537 d.set_size_request (300, -1);
2539 entry.set_text (rs.front()->region()->name());
2540 entry.select_region (0, -1);
2542 entry.signal_activate().connect (sigc::bind (sigc::mem_fun (d, &Dialog::response), RESPONSE_OK));
2548 int const ret = d.run();
2552 if (ret != RESPONSE_OK) {
2556 std::string str = entry.get_text();
2557 strip_whitespace_edges (str);
2559 rs.front()->region()->set_name (str);
2560 _regions->redisplay ();
2565 Editor::audition_playlist_region_via_route (boost::shared_ptr<Region> region, Route& route)
2567 if (_session->is_auditioning()) {
2568 _session->cancel_audition ();
2571 // note: some potential for creativity here, because region doesn't
2572 // have to belong to the playlist that Route is handling
2574 // bool was_soloed = route.soloed();
2576 route.set_solo (true, this);
2578 _session->request_bounded_roll (region->position(), region->position() + region->length());
2580 /* XXX how to unset the solo state ? */
2583 /** Start an audition of the first selected region */
2585 Editor::play_edit_range ()
2587 framepos_t start, end;
2589 if (get_edit_op_range (start, end)) {
2590 _session->request_bounded_roll (start, end);
2595 Editor::play_selected_region ()
2597 framepos_t start = max_framepos;
2600 RegionSelection rs = get_regions_from_selection_and_entered ();
2606 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
2607 if ((*i)->region()->position() < start) {
2608 start = (*i)->region()->position();
2610 if ((*i)->region()->last_frame() + 1 > end) {
2611 end = (*i)->region()->last_frame() + 1;
2615 _session->request_bounded_roll (start, end);
2619 Editor::audition_playlist_region_standalone (boost::shared_ptr<Region> region)
2621 _session->audition_region (region);
2625 Editor::region_from_selection ()
2627 if (clicked_axisview == 0) {
2631 if (selection->time.empty()) {
2635 framepos_t start = selection->time[clicked_selection].start;
2636 framepos_t end = selection->time[clicked_selection].end;
2638 TrackViewList tracks = get_tracks_for_range_action ();
2640 framepos_t selection_cnt = end - start + 1;
2642 for (TrackSelection::iterator i = tracks.begin(); i != tracks.end(); ++i) {
2643 boost::shared_ptr<Region> current;
2644 boost::shared_ptr<Playlist> pl;
2645 framepos_t internal_start;
2648 if ((pl = (*i)->playlist()) == 0) {
2652 if ((current = pl->top_region_at (start)) == 0) {
2656 internal_start = start - current->position();
2657 RegionFactory::region_name (new_name, current->name(), true);
2661 plist.add (ARDOUR::Properties::start, current->start() + internal_start);
2662 plist.add (ARDOUR::Properties::length, selection_cnt);
2663 plist.add (ARDOUR::Properties::name, new_name);
2664 plist.add (ARDOUR::Properties::layer, 0);
2666 boost::shared_ptr<Region> region (RegionFactory::create (current, plist));
2671 Editor::create_region_from_selection (vector<boost::shared_ptr<Region> >& new_regions)
2673 if (selection->time.empty() || selection->tracks.empty()) {
2677 framepos_t start = selection->time[clicked_selection].start;
2678 framepos_t end = selection->time[clicked_selection].end;
2680 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
2681 sort_track_selection (ts);
2683 for (TrackSelection::iterator i = ts.begin(); i != ts.end(); ++i) {
2684 boost::shared_ptr<Region> current;
2685 boost::shared_ptr<Playlist> playlist;
2686 framepos_t internal_start;
2689 if ((playlist = (*i)->playlist()) == 0) {
2693 if ((current = playlist->top_region_at(start)) == 0) {
2697 internal_start = start - current->position();
2698 RegionFactory::region_name (new_name, current->name(), true);
2702 plist.add (ARDOUR::Properties::start, current->start() + internal_start);
2703 plist.add (ARDOUR::Properties::length, end - start + 1);
2704 plist.add (ARDOUR::Properties::name, new_name);
2706 new_regions.push_back (RegionFactory::create (current, plist));
2711 Editor::split_multichannel_region ()
2713 RegionSelection rs = get_regions_from_selection_and_entered ();
2719 vector< boost::shared_ptr<Region> > v;
2721 for (list<RegionView*>::iterator x = rs.begin(); x != rs.end(); ++x) {
2722 (*x)->region()->separate_by_channel (*_session, v);
2727 Editor::new_region_from_selection ()
2729 region_from_selection ();
2730 cancel_selection ();
2734 add_if_covered (RegionView* rv, const AudioRange* ar, RegionSelection* rs)
2736 switch (rv->region()->coverage (ar->start, ar->end - 1)) {
2737 case Evoral::OverlapNone:
2745 * - selected tracks, or if there are none...
2746 * - tracks containing selected regions, or if there are none...
2751 Editor::get_tracks_for_range_action () const
2755 if (selection->tracks.empty()) {
2757 /* use tracks with selected regions */
2759 RegionSelection rs = selection->regions;
2761 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
2762 TimeAxisView* tv = &(*i)->get_time_axis_view();
2764 if (!t.contains (tv)) {
2770 /* no regions and no tracks: use all tracks */
2776 t = selection->tracks;
2779 return t.filter_to_unique_playlists();
2783 Editor::separate_regions_between (const TimeSelection& ts)
2785 bool in_command = false;
2786 boost::shared_ptr<Playlist> playlist;
2787 RegionSelection new_selection;
2789 TrackViewList tmptracks = get_tracks_for_range_action ();
2790 sort_track_selection (tmptracks);
2792 for (TrackSelection::iterator i = tmptracks.begin(); i != tmptracks.end(); ++i) {
2794 RouteTimeAxisView* rtv;
2796 if ((rtv = dynamic_cast<RouteTimeAxisView*> ((*i))) != 0) {
2798 if (rtv->is_track()) {
2800 /* no edits to destructive tracks */
2802 if (rtv->track()->destructive()) {
2806 if ((playlist = rtv->playlist()) != 0) {
2808 playlist->clear_changes ();
2810 /* XXX need to consider musical time selections here at some point */
2812 double speed = rtv->track()->speed();
2815 for (list<AudioRange>::const_iterator t = ts.begin(); t != ts.end(); ++t) {
2817 sigc::connection c = rtv->view()->RegionViewAdded.connect (
2818 sigc::mem_fun(*this, &Editor::collect_new_region_view));
2820 latest_regionviews.clear ();
2822 playlist->partition ((framepos_t)((*t).start * speed),
2823 (framepos_t)((*t).end * speed), false);
2827 if (!latest_regionviews.empty()) {
2829 rtv->view()->foreach_regionview (sigc::bind (
2830 sigc::ptr_fun (add_if_covered),
2831 &(*t), &new_selection));
2834 begin_reversible_command (_("separate"));
2838 /* pick up changes to existing regions */
2840 vector<Command*> cmds;
2841 playlist->rdiff (cmds);
2842 _session->add_commands (cmds);
2844 /* pick up changes to the playlist itself (adds/removes)
2847 _session->add_command(new StatefulDiffCommand (playlist));
2856 selection->set (new_selection);
2857 set_mouse_mode (MouseObject);
2859 commit_reversible_command ();
2863 struct PlaylistState {
2864 boost::shared_ptr<Playlist> playlist;
2868 /** Take tracks from get_tracks_for_range_action and cut any regions
2869 * on those tracks so that the tracks are empty over the time
2873 Editor::separate_region_from_selection ()
2875 /* preferentially use *all* ranges in the time selection if we're in range mode
2876 to allow discontiguous operation, since get_edit_op_range() currently
2877 returns a single range.
2880 if (!selection->time.empty()) {
2882 separate_regions_between (selection->time);
2889 if (get_edit_op_range (start, end)) {
2891 AudioRange ar (start, end, 1);
2895 separate_regions_between (ts);
2901 Editor::separate_region_from_punch ()
2903 Location* loc = _session->locations()->auto_punch_location();
2905 separate_regions_using_location (*loc);
2910 Editor::separate_region_from_loop ()
2912 Location* loc = _session->locations()->auto_loop_location();
2914 separate_regions_using_location (*loc);
2919 Editor::separate_regions_using_location (Location& loc)
2921 if (loc.is_mark()) {
2925 AudioRange ar (loc.start(), loc.end(), 1);
2930 separate_regions_between (ts);
2933 /** Separate regions under the selected region */
2935 Editor::separate_under_selected_regions ()
2937 vector<PlaylistState> playlists;
2941 rs = get_regions_from_selection_and_entered();
2943 if (!_session || rs.empty()) {
2947 begin_reversible_command (_("separate region under"));
2949 list<boost::shared_ptr<Region> > regions_to_remove;
2951 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
2952 // we can't just remove the region(s) in this loop because
2953 // this removes them from the RegionSelection, and they thus
2954 // disappear from underneath the iterator, and the ++i above
2955 // SEGVs in a puzzling fashion.
2957 // so, first iterate over the regions to be removed from rs and
2958 // add them to the regions_to_remove list, and then
2959 // iterate over the list to actually remove them.
2961 regions_to_remove.push_back ((*i)->region());
2964 for (list<boost::shared_ptr<Region> >::iterator rl = regions_to_remove.begin(); rl != regions_to_remove.end(); ++rl) {
2966 boost::shared_ptr<Playlist> playlist = (*rl)->playlist();
2969 // is this check necessary?
2973 vector<PlaylistState>::iterator i;
2975 //only take state if this is a new playlist.
2976 for (i = playlists.begin(); i != playlists.end(); ++i) {
2977 if ((*i).playlist == playlist) {
2982 if (i == playlists.end()) {
2984 PlaylistState before;
2985 before.playlist = playlist;
2986 before.before = &playlist->get_state();
2988 playlist->freeze ();
2989 playlists.push_back(before);
2992 //Partition on the region bounds
2993 playlist->partition ((*rl)->first_frame() - 1, (*rl)->last_frame() + 1, true);
2995 //Re-add region that was just removed due to the partition operation
2996 playlist->add_region( (*rl), (*rl)->first_frame() );
2999 vector<PlaylistState>::iterator pl;
3001 for (pl = playlists.begin(); pl != playlists.end(); ++pl) {
3002 (*pl).playlist->thaw ();
3003 _session->add_command(new MementoCommand<Playlist>(*(*pl).playlist, (*pl).before, &(*pl).playlist->get_state()));
3006 commit_reversible_command ();
3010 Editor::crop_region_to_selection ()
3012 if (!selection->time.empty()) {
3014 crop_region_to (selection->time.start(), selection->time.end_frame());
3021 if (get_edit_op_range (start, end)) {
3022 crop_region_to (start, end);
3029 Editor::crop_region_to (framepos_t start, framepos_t end)
3031 vector<boost::shared_ptr<Playlist> > playlists;
3032 boost::shared_ptr<Playlist> playlist;
3035 if (selection->tracks.empty()) {
3036 ts = track_views.filter_to_unique_playlists();
3038 ts = selection->tracks.filter_to_unique_playlists ();
3041 sort_track_selection (ts);
3043 for (TrackSelection::iterator i = ts.begin(); i != ts.end(); ++i) {
3045 RouteTimeAxisView* rtv;
3047 if ((rtv = dynamic_cast<RouteTimeAxisView*> ((*i))) != 0) {
3049 boost::shared_ptr<Track> t = rtv->track();
3051 if (t != 0 && ! t->destructive()) {
3053 if ((playlist = rtv->playlist()) != 0) {
3054 playlists.push_back (playlist);
3060 if (playlists.empty()) {
3064 framepos_t the_start;
3068 begin_reversible_command (_("trim to selection"));
3070 for (vector<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
3072 boost::shared_ptr<Region> region;
3076 if ((region = (*i)->top_region_at(the_start)) == 0) {
3080 /* now adjust lengths to that we do the right thing
3081 if the selection extends beyond the region
3084 the_start = max (the_start, (framepos_t) region->position());
3085 if (max_framepos - the_start < region->length()) {
3086 the_end = the_start + region->length() - 1;
3088 the_end = max_framepos;
3090 the_end = min (end, the_end);
3091 cnt = the_end - the_start + 1;
3093 region->clear_changes ();
3094 region->trim_to (the_start, cnt);
3095 _session->add_command (new StatefulDiffCommand (region));
3098 commit_reversible_command ();
3102 Editor::region_fill_track ()
3104 RegionSelection rs = get_regions_from_selection_and_entered ();
3106 if (!_session || rs.empty()) {
3110 framepos_t const end = _session->current_end_frame ();
3112 begin_reversible_command (Operations::region_fill);
3114 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3116 boost::shared_ptr<Region> region ((*i)->region());
3118 boost::shared_ptr<Playlist> pl = region->playlist();
3120 if (end <= region->last_frame()) {
3124 double times = (double) (end - region->last_frame()) / (double) region->length();
3130 pl->clear_changes ();
3131 pl->add_region (RegionFactory::create (region, true), region->last_frame(), times);
3132 _session->add_command (new StatefulDiffCommand (pl));
3135 commit_reversible_command ();
3139 Editor::region_fill_selection ()
3141 if (clicked_routeview == 0 || !clicked_routeview->is_audio_track()) {
3145 if (selection->time.empty()) {
3149 boost::shared_ptr<Region> region = _regions->get_single_selection ();
3154 framepos_t start = selection->time[clicked_selection].start;
3155 framepos_t end = selection->time[clicked_selection].end;
3157 boost::shared_ptr<Playlist> playlist;
3159 if (selection->tracks.empty()) {
3163 framepos_t selection_length = end - start;
3164 float times = (float)selection_length / region->length();
3166 begin_reversible_command (Operations::fill_selection);
3168 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
3170 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
3172 if ((playlist = (*i)->playlist()) == 0) {
3176 playlist->clear_changes ();
3177 playlist->add_region (RegionFactory::create (region, true), start, times);
3178 _session->add_command (new StatefulDiffCommand (playlist));
3181 commit_reversible_command ();
3185 Editor::set_region_sync_position ()
3187 set_sync_point (get_preferred_edit_position (), get_regions_from_selection_and_edit_point ());
3191 Editor::set_sync_point (framepos_t where, const RegionSelection& rs)
3193 bool in_command = false;
3195 for (RegionSelection::const_iterator r = rs.begin(); r != rs.end(); ++r) {
3197 if (!(*r)->region()->covers (where)) {
3201 boost::shared_ptr<Region> region ((*r)->region());
3204 begin_reversible_command (_("set sync point"));
3208 region->clear_changes ();
3209 region->set_sync_position (where);
3210 _session->add_command(new StatefulDiffCommand (region));
3214 commit_reversible_command ();
3218 /** Remove the sync positions of the selection */
3220 Editor::remove_region_sync ()
3222 RegionSelection rs = get_regions_from_selection_and_entered ();
3228 begin_reversible_command (_("remove region sync"));
3230 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3232 (*i)->region()->clear_changes ();
3233 (*i)->region()->clear_sync_position ();
3234 _session->add_command(new StatefulDiffCommand ((*i)->region()));
3237 commit_reversible_command ();
3241 Editor::naturalize_region ()
3243 RegionSelection rs = get_regions_from_selection_and_entered ();
3249 if (rs.size() > 1) {
3250 begin_reversible_command (_("move regions to original position"));
3252 begin_reversible_command (_("move region to original position"));
3255 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3256 (*i)->region()->clear_changes ();
3257 (*i)->region()->move_to_natural_position ();
3258 _session->add_command (new StatefulDiffCommand ((*i)->region()));
3261 commit_reversible_command ();
3265 Editor::align_regions (RegionPoint what)
3267 RegionSelection const rs = get_regions_from_selection_and_edit_point ();
3273 begin_reversible_command (_("align selection"));
3275 framepos_t const position = get_preferred_edit_position ();
3277 for (RegionSelection::const_iterator i = rs.begin(); i != rs.end(); ++i) {
3278 align_region_internal ((*i)->region(), what, position);
3281 commit_reversible_command ();
3284 struct RegionSortByTime {
3285 bool operator() (const RegionView* a, const RegionView* b) {
3286 return a->region()->position() < b->region()->position();
3291 Editor::align_regions_relative (RegionPoint point)
3293 RegionSelection const rs = get_regions_from_selection_and_edit_point ();
3299 framepos_t const position = get_preferred_edit_position ();
3301 framepos_t distance = 0;
3305 list<RegionView*> sorted;
3306 rs.by_position (sorted);
3308 boost::shared_ptr<Region> r ((*sorted.begin())->region());
3313 if (position > r->position()) {
3314 distance = position - r->position();
3316 distance = r->position() - position;
3322 if (position > r->last_frame()) {
3323 distance = position - r->last_frame();
3324 pos = r->position() + distance;
3326 distance = r->last_frame() - position;
3327 pos = r->position() - distance;
3333 pos = r->adjust_to_sync (position);
3334 if (pos > r->position()) {
3335 distance = pos - r->position();
3337 distance = r->position() - pos;
3343 if (pos == r->position()) {
3347 begin_reversible_command (_("align selection (relative)"));
3349 /* move first one specially */
3351 r->clear_changes ();
3352 r->set_position (pos);
3353 _session->add_command(new StatefulDiffCommand (r));
3355 /* move rest by the same amount */
3359 for (list<RegionView*>::iterator i = sorted.begin(); i != sorted.end(); ++i) {
3361 boost::shared_ptr<Region> region ((*i)->region());
3363 region->clear_changes ();
3366 region->set_position (region->position() + distance);
3368 region->set_position (region->position() - distance);
3371 _session->add_command(new StatefulDiffCommand (region));
3375 commit_reversible_command ();
3379 Editor::align_region (boost::shared_ptr<Region> region, RegionPoint point, framepos_t position)
3381 begin_reversible_command (_("align region"));
3382 align_region_internal (region, point, position);
3383 commit_reversible_command ();
3387 Editor::align_region_internal (boost::shared_ptr<Region> region, RegionPoint point, framepos_t position)
3389 region->clear_changes ();
3393 region->set_position (region->adjust_to_sync (position));
3397 if (position > region->length()) {
3398 region->set_position (position - region->length());
3403 region->set_position (position);
3407 _session->add_command(new StatefulDiffCommand (region));
3411 Editor::trim_region_front ()
3417 Editor::trim_region_back ()
3419 trim_region (false);
3423 Editor::trim_region (bool front)
3425 framepos_t where = get_preferred_edit_position();
3426 RegionSelection rs = get_regions_from_selection_and_edit_point ();
3432 begin_reversible_command (front ? _("trim front") : _("trim back"));
3434 for (list<RegionView*>::const_iterator i = rs.by_layer().begin(); i != rs.by_layer().end(); ++i) {
3435 if (!(*i)->region()->locked()) {
3437 (*i)->region()->clear_changes ();
3440 (*i)->region()->trim_front (where);
3441 maybe_locate_with_edit_preroll ( where );
3443 (*i)->region()->trim_end (where);
3444 maybe_locate_with_edit_preroll ( where );
3447 _session->add_command (new StatefulDiffCommand ((*i)->region()));
3451 commit_reversible_command ();
3454 /** Trim the end of the selected regions to the position of the edit cursor */
3456 Editor::trim_region_to_loop ()
3458 Location* loc = _session->locations()->auto_loop_location();
3462 trim_region_to_location (*loc, _("trim to loop"));
3466 Editor::trim_region_to_punch ()
3468 Location* loc = _session->locations()->auto_punch_location();
3472 trim_region_to_location (*loc, _("trim to punch"));
3476 Editor::trim_region_to_location (const Location& loc, const char* str)
3478 RegionSelection rs = get_regions_from_selection_and_entered ();
3480 begin_reversible_command (str);
3482 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
3483 RegionView* rv = (*x);
3485 /* require region to span proposed trim */
3486 switch (rv->region()->coverage (loc.start(), loc.end())) {
3487 case Evoral::OverlapInternal:
3493 RouteTimeAxisView* tav = dynamic_cast<RouteTimeAxisView*> (&rv->get_time_axis_view());
3502 if (tav->track() != 0) {
3503 speed = tav->track()->speed();
3506 start = session_frame_to_track_frame (loc.start(), speed);
3507 end = session_frame_to_track_frame (loc.end(), speed);
3509 rv->region()->clear_changes ();
3510 rv->region()->trim_to (start, (end - start));
3511 _session->add_command(new StatefulDiffCommand (rv->region()));
3514 commit_reversible_command ();
3518 Editor::trim_region_to_previous_region_end ()
3520 return trim_to_region(false);
3524 Editor::trim_region_to_next_region_start ()
3526 return trim_to_region(true);
3530 Editor::trim_to_region(bool forward)
3532 RegionSelection rs = get_regions_from_selection_and_entered ();
3534 begin_reversible_command (_("trim to region"));
3536 boost::shared_ptr<Region> next_region;
3538 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
3540 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*x);
3546 AudioTimeAxisView* atav = dynamic_cast<AudioTimeAxisView*> (&arv->get_time_axis_view());
3554 if (atav->track() != 0) {
3555 speed = atav->track()->speed();
3559 boost::shared_ptr<Region> region = arv->region();
3560 boost::shared_ptr<Playlist> playlist (region->playlist());
3562 region->clear_changes ();
3566 next_region = playlist->find_next_region (region->first_frame(), Start, 1);
3572 region->trim_end((framepos_t) ( (next_region->first_frame() - 1) * speed));
3573 arv->region_changed (PropertyChange (ARDOUR::Properties::length));
3577 next_region = playlist->find_next_region (region->first_frame(), Start, 0);
3583 region->trim_front((framepos_t) ((next_region->last_frame() + 1) * speed));
3585 arv->region_changed (ARDOUR::bounds_change);
3588 _session->add_command(new StatefulDiffCommand (region));
3591 commit_reversible_command ();
3595 Editor::unfreeze_route ()
3597 if (clicked_routeview == 0 || !clicked_routeview->is_track()) {
3601 clicked_routeview->track()->unfreeze ();
3605 Editor::_freeze_thread (void* arg)
3607 return static_cast<Editor*>(arg)->freeze_thread ();
3611 Editor::freeze_thread ()
3613 /* create event pool because we may need to talk to the session */
3614 SessionEvent::create_per_thread_pool ("freeze events", 64);
3615 /* create per-thread buffers for process() tree to use */
3616 clicked_routeview->audio_track()->freeze_me (*current_interthread_info);
3617 current_interthread_info->done = true;
3622 Editor::freeze_route ()
3628 /* stop transport before we start. this is important */
3630 _session->request_transport_speed (0.0);
3632 /* wait for just a little while, because the above call is asynchronous */
3634 Glib::usleep (250000);
3636 if (clicked_routeview == 0 || !clicked_routeview->is_audio_track()) {
3640 if (!clicked_routeview->track()->bounceable (clicked_routeview->track()->main_outs(), true)) {
3642 _("This track/bus cannot be frozen because the signal adds or loses channels before reaching the outputs.\n"
3643 "This is typically caused by plugins that generate stereo output from mono input or vice versa.")
3645 d.set_title (_("Cannot freeze"));
3650 if (clicked_routeview->track()->has_external_redirects()) {
3651 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"
3652 "Freezing will only process the signal as far as the first send/insert/return."),
3653 clicked_routeview->track()->name()), true, MESSAGE_INFO, BUTTONS_NONE, true);
3655 d.add_button (_("Freeze anyway"), Gtk::RESPONSE_OK);
3656 d.add_button (_("Don't freeze"), Gtk::RESPONSE_CANCEL);
3657 d.set_title (_("Freeze Limits"));
3659 int response = d.run ();
3662 case Gtk::RESPONSE_CANCEL:
3669 InterThreadInfo itt;
3670 current_interthread_info = &itt;
3672 InterthreadProgressWindow ipw (current_interthread_info, _("Freeze"), _("Cancel Freeze"));
3674 pthread_create_and_store (X_("freezer"), &itt.thread, _freeze_thread, this);
3676 set_canvas_cursor (_cursors->wait);
3678 while (!itt.done && !itt.cancel) {
3679 gtk_main_iteration ();
3682 current_interthread_info = 0;
3683 set_canvas_cursor (current_canvas_cursor);
3687 Editor::bounce_range_selection (bool replace, bool enable_processing)
3689 if (selection->time.empty()) {
3693 TrackSelection views = selection->tracks;
3695 for (TrackViewList::iterator i = views.begin(); i != views.end(); ++i) {
3697 if (enable_processing) {
3699 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*i);
3701 if (rtv && rtv->track() && replace && enable_processing && !rtv->track()->bounceable (rtv->track()->main_outs(), false)) {
3703 _("You can't perform this operation because the processing of the signal "
3704 "will cause one or more of the tracks to end up with a region with more channels than this track has inputs.\n\n"
3705 "You can do this without processing, which is a different operation.")
3707 d.set_title (_("Cannot bounce"));
3714 framepos_t start = selection->time[clicked_selection].start;
3715 framepos_t end = selection->time[clicked_selection].end;
3716 framepos_t cnt = end - start + 1;
3718 begin_reversible_command (_("bounce range"));
3720 for (TrackViewList::iterator i = views.begin(); i != views.end(); ++i) {
3722 RouteTimeAxisView* rtv;
3724 if ((rtv = dynamic_cast<RouteTimeAxisView*> (*i)) == 0) {
3728 boost::shared_ptr<Playlist> playlist;
3730 if ((playlist = rtv->playlist()) == 0) {
3734 InterThreadInfo itt;
3736 playlist->clear_changes ();
3737 playlist->clear_owned_changes ();
3739 boost::shared_ptr<Region> r;
3741 if (enable_processing) {
3742 r = rtv->track()->bounce_range (start, start+cnt, itt, rtv->track()->main_outs(), false);
3744 r = rtv->track()->bounce_range (start, start+cnt, itt, boost::shared_ptr<Processor>(), false);
3752 list<AudioRange> ranges;
3753 ranges.push_back (AudioRange (start, start+cnt, 0));
3754 playlist->cut (ranges); // discard result
3755 playlist->add_region (r, start);
3758 vector<Command*> cmds;
3759 playlist->rdiff (cmds);
3760 _session->add_commands (cmds);
3762 _session->add_command (new StatefulDiffCommand (playlist));
3765 commit_reversible_command ();
3768 /** Delete selected regions, automation points or a time range */
3775 /** Cut selected regions, automation points or a time range */
3782 /** Copy selected regions, automation points or a time range */
3790 /** @return true if a Cut, Copy or Clear is possible */
3792 Editor::can_cut_copy () const
3794 switch (effective_mouse_mode()) {
3797 if (!selection->regions.empty() || !selection->points.empty()) {
3803 if (!selection->time.empty()) {
3816 /** Cut, copy or clear selected regions, automation points or a time range.
3817 * @param op Operation (Cut, Copy or Clear)
3820 Editor::cut_copy (CutCopyOp op)
3822 /* only cancel selection if cut/copy is successful.*/
3828 opname = _("delete");
3837 opname = _("clear");
3841 /* if we're deleting something, and the mouse is still pressed,
3842 the thing we started a drag for will be gone when we release
3843 the mouse button(s). avoid this. see part 2 at the end of
3847 if (op == Delete || op == Cut || op == Clear) {
3848 if (_drags->active ()) {
3853 if ( op != Clear ) //"Delete" doesn't change copy/paste buf
3854 cut_buffer->clear ();
3856 if (entered_marker) {
3858 /* cut/delete op while pointing at a marker */
3861 Location* loc = find_location_from_marker (entered_marker, ignored);
3863 if (_session && loc) {
3864 Glib::signal_idle().connect (sigc::bind (sigc::mem_fun(*this, &Editor::really_remove_marker), loc));
3871 if (internal_editing()) {
3873 switch (effective_mouse_mode()) {
3876 begin_reversible_command (opname + ' ' + X_("MIDI"));
3878 commit_reversible_command ();
3887 bool did_edit = false;
3889 switch (effective_mouse_mode()) {
3891 if (!selection->points.empty()) {
3892 begin_reversible_command (opname + _(" points"));
3894 cut_copy_points (op);
3895 if (op == Cut || op == Delete) {
3896 selection->clear_points ();
3903 if (!selection->regions.empty() || !selection->points.empty()) {
3907 if (selection->regions.empty()) {
3908 thing_name = _("points");
3909 } else if (selection->points.empty()) {
3910 thing_name = _("regions");
3912 thing_name = _("objects");
3915 begin_reversible_command (opname + ' ' + thing_name);
3918 if (!selection->regions.empty()) {
3919 cut_copy_regions (op, selection->regions);
3921 if (op == Cut || op == Delete) {
3922 selection->clear_regions ();
3926 if (!selection->points.empty()) {
3927 cut_copy_points (op);
3929 if (op == Cut || op == Delete) {
3930 selection->clear_points ();
3937 if (selection->time.empty()) {
3938 framepos_t start, end;
3939 /* no time selection, see if we can get an edit range
3942 if (get_edit_op_range (start, end)) {
3943 selection->set (start, end);
3946 if (!selection->time.empty()) {
3947 begin_reversible_command (opname + _(" range"));
3950 cut_copy_ranges (op);
3952 if (op == Cut || op == Delete) {
3953 selection->clear_time ();
3963 commit_reversible_command ();
3966 if (op == Delete || op == Cut || op == Clear) {
3971 struct AutomationRecord {
3972 AutomationRecord () : state (0) {}
3973 AutomationRecord (XMLNode* s) : state (s) {}
3975 XMLNode* state; ///< state before any operation
3976 boost::shared_ptr<Evoral::ControlList> copy; ///< copied events for the cut buffer
3979 /** Cut, copy or clear selected automation points.
3980 * @param op Operation (Cut, Copy or Clear)
3983 Editor::cut_copy_points (CutCopyOp op)
3985 if (selection->points.empty ()) {
3989 /* XXX: not ideal, as there may be more than one track involved in the point selection */
3990 _last_cut_copy_source_track = &selection->points.front()->line().trackview;
3992 /* Keep a record of the AutomationLists that we end up using in this operation */
3993 typedef std::map<boost::shared_ptr<AutomationList>, AutomationRecord> Lists;
3996 /* Go through all selected points, making an AutomationRecord for each distinct AutomationList */
3997 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
3998 boost::shared_ptr<AutomationList> al = (*i)->line().the_list();
3999 if (lists.find (al) == lists.end ()) {
4000 /* We haven't seen this list yet, so make a record for it. This includes
4001 taking a copy of its current state, in case this is needed for undo later.
4003 lists[al] = AutomationRecord (&al->get_state ());
4007 if (op == Cut || op == Copy) {
4008 /* This operation will involve putting things in the cut buffer, so create an empty
4009 ControlList for each of our source lists to put the cut buffer data in.
4011 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
4012 i->second.copy = i->first->create (i->first->parameter ());
4015 /* Add all selected points to the relevant copy ControlLists */
4016 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
4017 boost::shared_ptr<AutomationList> al = (*i)->line().the_list();
4018 AutomationList::const_iterator j = (*i)->model ();
4019 lists[al].copy->add ((*j)->when, (*j)->value);
4022 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
4023 /* Correct this copy list so that it starts at time 0 */
4024 double const start = i->second.copy->front()->when;
4025 for (AutomationList::iterator j = i->second.copy->begin(); j != i->second.copy->end(); ++j) {
4026 (*j)->when -= start;
4029 /* And add it to the cut buffer */
4030 cut_buffer->add (i->second.copy);
4034 if (op == Delete || op == Cut) {
4035 /* This operation needs to remove things from the main AutomationList, so do that now */
4037 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
4038 i->first->freeze ();
4041 /* Remove each selected point from its AutomationList */
4042 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
4043 boost::shared_ptr<AutomationList> al = (*i)->line().the_list();
4044 al->erase ((*i)->model ());
4047 /* Thaw the lists and add undo records for them */
4048 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
4049 boost::shared_ptr<AutomationList> al = i->first;
4051 _session->add_command (new MementoCommand<AutomationList> (*al.get(), i->second.state, &(al->get_state ())));
4056 /** Cut, copy or clear selected automation points.
4057 * @param op Operation (Cut, Copy or Clear)
4060 Editor::cut_copy_midi (CutCopyOp op)
4062 for (MidiRegionSelection::iterator i = selection->midi_regions.begin(); i != selection->midi_regions.end(); ++i) {
4063 MidiRegionView* mrv = *i;
4064 mrv->cut_copy_clear (op);
4070 struct lt_playlist {
4071 bool operator () (const PlaylistState& a, const PlaylistState& b) {
4072 return a.playlist < b.playlist;
4076 struct PlaylistMapping {
4078 boost::shared_ptr<Playlist> pl;
4080 PlaylistMapping (TimeAxisView* tvp) : tv (tvp) {}
4083 /** Remove `clicked_regionview' */
4085 Editor::remove_clicked_region ()
4087 if (clicked_routeview == 0 || clicked_regionview == 0) {
4091 boost::shared_ptr<Playlist> playlist = clicked_routeview->playlist();
4093 begin_reversible_command (_("remove region"));
4094 playlist->clear_changes ();
4095 playlist->clear_owned_changes ();
4096 playlist->remove_region (clicked_regionview->region());
4098 /* We might have removed regions, which alters other regions' layering_index,
4099 so we need to do a recursive diff here.
4101 vector<Command*> cmds;
4102 playlist->rdiff (cmds);
4103 _session->add_commands (cmds);
4105 _session->add_command(new StatefulDiffCommand (playlist));
4106 commit_reversible_command ();
4110 /** Remove the selected regions */
4112 Editor::remove_selected_regions ()
4114 RegionSelection rs = get_regions_from_selection_and_entered ();
4116 if (!_session || rs.empty()) {
4120 begin_reversible_command (_("remove region"));
4122 list<boost::shared_ptr<Region> > regions_to_remove;
4124 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
4125 // we can't just remove the region(s) in this loop because
4126 // this removes them from the RegionSelection, and they thus
4127 // disappear from underneath the iterator, and the ++i above
4128 // SEGVs in a puzzling fashion.
4130 // so, first iterate over the regions to be removed from rs and
4131 // add them to the regions_to_remove list, and then
4132 // iterate over the list to actually remove them.
4134 regions_to_remove.push_back ((*i)->region());
4137 vector<boost::shared_ptr<Playlist> > playlists;
4139 for (list<boost::shared_ptr<Region> >::iterator rl = regions_to_remove.begin(); rl != regions_to_remove.end(); ++rl) {
4141 boost::shared_ptr<Playlist> playlist = (*rl)->playlist();
4144 // is this check necessary?
4148 /* get_regions_from_selection_and_entered() guarantees that
4149 the playlists involved are unique, so there is no need
4153 playlists.push_back (playlist);
4155 playlist->clear_changes ();
4156 playlist->clear_owned_changes ();
4157 playlist->freeze ();
4158 playlist->remove_region (*rl);
4161 vector<boost::shared_ptr<Playlist> >::iterator pl;
4163 for (pl = playlists.begin(); pl != playlists.end(); ++pl) {
4166 /* We might have removed regions, which alters other regions' layering_index,
4167 so we need to do a recursive diff here.
4169 vector<Command*> cmds;
4170 (*pl)->rdiff (cmds);
4171 _session->add_commands (cmds);
4173 _session->add_command(new StatefulDiffCommand (*pl));
4176 commit_reversible_command ();
4179 /** Cut, copy or clear selected regions.
4180 * @param op Operation (Cut, Copy or Clear)
4183 Editor::cut_copy_regions (CutCopyOp op, RegionSelection& rs)
4185 /* we can't use a std::map here because the ordering is important, and we can't trivially sort
4186 a map when we want ordered access to both elements. i think.
4189 vector<PlaylistMapping> pmap;
4191 framepos_t first_position = max_framepos;
4193 typedef set<boost::shared_ptr<Playlist> > FreezeList;
4194 FreezeList freezelist;
4196 /* get ordering correct before we cut/copy */
4198 rs.sort_by_position_and_track ();
4200 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
4202 first_position = min ((framepos_t) (*x)->region()->position(), first_position);
4204 if (op == Cut || op == Clear || op == Delete) {
4205 boost::shared_ptr<Playlist> pl = (*x)->region()->playlist();
4208 FreezeList::iterator fl;
4210 // only take state if this is a new playlist.
4211 for (fl = freezelist.begin(); fl != freezelist.end(); ++fl) {
4217 if (fl == freezelist.end()) {
4218 pl->clear_changes();
4219 pl->clear_owned_changes ();
4221 freezelist.insert (pl);
4226 TimeAxisView* tv = &(*x)->get_time_axis_view();
4227 vector<PlaylistMapping>::iterator z;
4229 for (z = pmap.begin(); z != pmap.end(); ++z) {
4230 if ((*z).tv == tv) {
4235 if (z == pmap.end()) {
4236 pmap.push_back (PlaylistMapping (tv));
4240 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ) {
4242 boost::shared_ptr<Playlist> pl = (*x)->region()->playlist();
4245 /* region not yet associated with a playlist (e.g. unfinished
4252 TimeAxisView& tv = (*x)->get_time_axis_view();
4253 boost::shared_ptr<Playlist> npl;
4254 RegionSelection::iterator tmp;
4261 vector<PlaylistMapping>::iterator z;
4263 for (z = pmap.begin(); z != pmap.end(); ++z) {
4264 if ((*z).tv == &tv) {
4269 assert (z != pmap.end());
4272 npl = PlaylistFactory::create (pl->data_type(), *_session, "cutlist", true);
4280 boost::shared_ptr<Region> r = (*x)->region();
4281 boost::shared_ptr<Region> _xx;
4287 pl->remove_region (r);
4291 _xx = RegionFactory::create (r);
4292 npl->add_region (_xx, r->position() - first_position);
4293 pl->remove_region (r);
4297 /* copy region before adding, so we're not putting same object into two different playlists */
4298 npl->add_region (RegionFactory::create (r), r->position() - first_position);
4302 pl->remove_region (r);
4311 list<boost::shared_ptr<Playlist> > foo;
4313 /* the pmap is in the same order as the tracks in which selected regions occured */
4315 for (vector<PlaylistMapping>::iterator i = pmap.begin(); i != pmap.end(); ++i) {
4318 foo.push_back ((*i).pl);
4323 cut_buffer->set (foo);
4327 _last_cut_copy_source_track = 0;
4329 _last_cut_copy_source_track = pmap.front().tv;
4333 for (FreezeList::iterator pl = freezelist.begin(); pl != freezelist.end(); ++pl) {
4336 /* We might have removed regions, which alters other regions' layering_index,
4337 so we need to do a recursive diff here.
4339 vector<Command*> cmds;
4340 (*pl)->rdiff (cmds);
4341 _session->add_commands (cmds);
4343 _session->add_command (new StatefulDiffCommand (*pl));
4348 Editor::cut_copy_ranges (CutCopyOp op)
4350 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4352 /* Sort the track selection now, so that it if is used, the playlists
4353 selected by the calls below to cut_copy_clear are in the order that
4354 their tracks appear in the editor. This makes things like paste
4355 of ranges work properly.
4358 sort_track_selection (ts);
4361 if (!entered_track) {
4364 ts.push_back (entered_track);
4367 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4368 (*i)->cut_copy_clear (*selection, op);
4373 Editor::paste (float times, bool from_context)
4375 DEBUG_TRACE (DEBUG::CutNPaste, "paste to preferred edit pos\n");
4377 paste_internal (get_preferred_edit_position (false, from_context), times);
4381 Editor::mouse_paste ()
4386 if (!mouse_frame (where, ignored)) {
4391 paste_internal (where, 1);
4395 Editor::paste_internal (framepos_t position, float times)
4397 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("apparent paste position is %1\n", position));
4399 if (internal_editing()) {
4400 if (cut_buffer->midi_notes.empty()) {
4404 if (cut_buffer->empty()) {
4409 if (position == max_framepos) {
4410 position = get_preferred_edit_position();
4411 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("preferred edit position is %1\n", position));
4415 TrackViewList::iterator i;
4418 /* get everything in the correct order */
4420 if (_edit_point == Editing::EditAtMouse && entered_track) {
4421 /* With the mouse edit point, paste onto the track under the mouse */
4422 ts.push_back (entered_track);
4423 } else if (!selection->tracks.empty()) {
4424 /* Otherwise, if there are some selected tracks, paste to them */
4425 ts = selection->tracks.filter_to_unique_playlists ();
4426 sort_track_selection (ts);
4427 } else if (_last_cut_copy_source_track) {
4428 /* Otherwise paste to the track that the cut/copy came from;
4429 see discussion in mantis #3333.
4431 ts.push_back (_last_cut_copy_source_track);
4434 if (internal_editing ()) {
4436 /* undo/redo is handled by individual tracks/regions */
4438 for (nth = 0, i = ts.begin(); i != ts.end(); ++i, ++nth) {
4441 RegionSelection::iterator r;
4442 MidiNoteSelection::iterator cb;
4444 get_regions_at (rs, position, ts);
4446 for (cb = cut_buffer->midi_notes.begin(), r = rs.begin();
4447 cb != cut_buffer->midi_notes.end() && r != rs.end(); ++r) {
4448 MidiRegionView* mrv = dynamic_cast<MidiRegionView*> (*r);
4450 mrv->paste (position, times, **cb);
4458 /* we do redo (do you do voodoo?) */
4460 begin_reversible_command (Operations::paste);
4462 for (nth = 0, i = ts.begin(); i != ts.end(); ++i, ++nth) {
4463 (*i)->paste (position, times, *cut_buffer, nth);
4466 commit_reversible_command ();
4471 Editor::duplicate_some_regions (RegionSelection& regions, float times)
4473 boost::shared_ptr<Playlist> playlist;
4474 RegionSelection sel = regions; // clear (below) may clear the argument list if its the current region selection
4475 RegionSelection foo;
4477 framepos_t const start_frame = regions.start ();
4478 framepos_t const end_frame = regions.end_frame ();
4480 begin_reversible_command (Operations::duplicate_region);
4482 selection->clear_regions ();
4484 for (RegionSelection::iterator i = sel.begin(); i != sel.end(); ++i) {
4486 boost::shared_ptr<Region> r ((*i)->region());
4488 TimeAxisView& tv = (*i)->get_time_axis_view();
4489 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (&tv);
4490 latest_regionviews.clear ();
4491 sigc::connection c = rtv->view()->RegionViewAdded.connect (sigc::mem_fun(*this, &Editor::collect_new_region_view));
4493 playlist = (*i)->region()->playlist();
4494 playlist->clear_changes ();
4495 playlist->duplicate (r, end_frame + (r->first_frame() - start_frame), times);
4496 _session->add_command(new StatefulDiffCommand (playlist));
4500 foo.insert (foo.end(), latest_regionviews.begin(), latest_regionviews.end());
4503 commit_reversible_command ();
4506 selection->set (foo);
4511 Editor::duplicate_selection (float times)
4513 if (selection->time.empty() || selection->tracks.empty()) {
4517 boost::shared_ptr<Playlist> playlist;
4518 vector<boost::shared_ptr<Region> > new_regions;
4519 vector<boost::shared_ptr<Region> >::iterator ri;
4521 create_region_from_selection (new_regions);
4523 if (new_regions.empty()) {
4527 begin_reversible_command (_("duplicate selection"));
4529 ri = new_regions.begin();
4531 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4533 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4534 if ((playlist = (*i)->playlist()) == 0) {
4537 playlist->clear_changes ();
4538 playlist->duplicate (*ri, selection->time[clicked_selection].end, times);
4539 _session->add_command (new StatefulDiffCommand (playlist));
4542 if (ri == new_regions.end()) {
4547 commit_reversible_command ();
4550 /** Reset all selected points to the relevant default value */
4552 Editor::reset_point_selection ()
4554 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
4555 ARDOUR::AutomationList::iterator j = (*i)->model ();
4556 (*j)->value = (*i)->line().the_list()->default_value ();
4561 Editor::center_playhead ()
4563 float const page = _visible_canvas_width * samples_per_pixel;
4564 center_screen_internal (playhead_cursor->current_frame (), page);
4568 Editor::center_edit_point ()
4570 float const page = _visible_canvas_width * samples_per_pixel;
4571 center_screen_internal (get_preferred_edit_position(), page);
4574 /** Caller must begin and commit a reversible command */
4576 Editor::clear_playlist (boost::shared_ptr<Playlist> playlist)
4578 playlist->clear_changes ();
4580 _session->add_command (new StatefulDiffCommand (playlist));
4584 Editor::nudge_track (bool use_edit, bool forwards)
4586 boost::shared_ptr<Playlist> playlist;
4587 framepos_t distance;
4588 framepos_t next_distance;
4592 start = get_preferred_edit_position();
4597 if ((distance = get_nudge_distance (start, next_distance)) == 0) {
4601 if (selection->tracks.empty()) {
4605 begin_reversible_command (_("nudge track"));
4607 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4609 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4611 if ((playlist = (*i)->playlist()) == 0) {
4615 playlist->clear_changes ();
4616 playlist->clear_owned_changes ();
4618 playlist->nudge_after (start, distance, forwards);
4620 vector<Command*> cmds;
4622 playlist->rdiff (cmds);
4623 _session->add_commands (cmds);
4625 _session->add_command (new StatefulDiffCommand (playlist));
4628 commit_reversible_command ();
4632 Editor::remove_last_capture ()
4634 vector<string> choices;
4641 if (Config->get_verify_remove_last_capture()) {
4642 prompt = _("Do you really want to destroy the last capture?"
4643 "\n(This is destructive and cannot be undone)");
4645 choices.push_back (_("No, do nothing."));
4646 choices.push_back (_("Yes, destroy it."));
4648 Gtkmm2ext::Choice prompter (_("Destroy last capture"), prompt, choices);
4650 if (prompter.run () == 1) {
4651 _session->remove_last_capture ();
4652 _regions->redisplay ();
4656 _session->remove_last_capture();
4657 _regions->redisplay ();
4662 Editor::normalize_region ()
4668 RegionSelection rs = get_regions_from_selection_and_entered ();
4674 NormalizeDialog dialog (rs.size() > 1);
4676 if (dialog.run () == RESPONSE_CANCEL) {
4680 set_canvas_cursor (_cursors->wait);
4683 /* XXX: should really only count audio regions here */
4684 int const regions = rs.size ();
4686 /* Make a list of the selected audio regions' maximum amplitudes, and also
4687 obtain the maximum amplitude of them all.
4689 list<double> max_amps;
4691 for (RegionSelection::const_iterator i = rs.begin(); i != rs.end(); ++i) {
4692 AudioRegionView const * arv = dynamic_cast<AudioRegionView const *> (*i);
4694 dialog.descend (1.0 / regions);
4695 double const a = arv->audio_region()->maximum_amplitude (&dialog);
4698 /* the user cancelled the operation */
4699 set_canvas_cursor (current_canvas_cursor);
4703 max_amps.push_back (a);
4704 max_amp = max (max_amp, a);
4709 begin_reversible_command (_("normalize"));
4711 list<double>::const_iterator a = max_amps.begin ();
4713 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
4714 AudioRegionView* const arv = dynamic_cast<AudioRegionView*> (*r);
4719 arv->region()->clear_changes ();
4721 double const amp = dialog.normalize_individually() ? *a : max_amp;
4723 arv->audio_region()->normalize (amp, dialog.target ());
4724 _session->add_command (new StatefulDiffCommand (arv->region()));
4729 commit_reversible_command ();
4730 set_canvas_cursor (current_canvas_cursor);
4735 Editor::reset_region_scale_amplitude ()
4741 RegionSelection rs = get_regions_from_selection_and_entered ();
4747 begin_reversible_command ("reset gain");
4749 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
4750 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
4753 arv->region()->clear_changes ();
4754 arv->audio_region()->set_scale_amplitude (1.0f);
4755 _session->add_command (new StatefulDiffCommand (arv->region()));
4758 commit_reversible_command ();
4762 Editor::adjust_region_gain (bool up)
4764 RegionSelection rs = get_regions_from_selection_and_entered ();
4766 if (!_session || rs.empty()) {
4770 begin_reversible_command ("adjust region gain");
4772 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
4773 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
4778 arv->region()->clear_changes ();
4780 double dB = accurate_coefficient_to_dB (arv->audio_region()->scale_amplitude ());
4788 arv->audio_region()->set_scale_amplitude (dB_to_coefficient (dB));
4789 _session->add_command (new StatefulDiffCommand (arv->region()));
4792 commit_reversible_command ();
4797 Editor::reverse_region ()
4803 Reverse rev (*_session);
4804 apply_filter (rev, _("reverse regions"));
4808 Editor::strip_region_silence ()
4814 RegionSelection rs = get_regions_from_selection_and_entered ();
4820 std::list<RegionView*> audio_only;
4822 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
4823 AudioRegionView* const arv = dynamic_cast<AudioRegionView*> (*i);
4825 audio_only.push_back (arv);
4829 StripSilenceDialog d (_session, audio_only);
4830 int const r = d.run ();
4834 if (r == Gtk::RESPONSE_OK) {
4835 ARDOUR::AudioIntervalMap silences;
4836 d.silences (silences);
4837 StripSilence s (*_session, silences, d.fade_length());
4838 apply_filter (s, _("strip silence"), &d);
4843 Editor::apply_midi_note_edit_op_to_region (MidiOperator& op, MidiRegionView& mrv)
4845 Evoral::Sequence<Evoral::MusicalTime>::Notes selected;
4846 mrv.selection_as_notelist (selected, true);
4848 vector<Evoral::Sequence<Evoral::MusicalTime>::Notes> v;
4849 v.push_back (selected);
4851 framepos_t pos_frames = mrv.midi_region()->position() - mrv.midi_region()->start();
4852 double pos_beats = _session->tempo_map().framewalk_to_beats(0, pos_frames);
4854 return op (mrv.midi_region()->model(), pos_beats, v);
4858 Editor::apply_midi_note_edit_op (MidiOperator& op)
4862 RegionSelection rs = get_regions_from_selection_and_entered ();
4868 begin_reversible_command (op.name ());
4870 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
4871 RegionSelection::iterator tmp = r;
4874 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*r);
4877 cmd = apply_midi_note_edit_op_to_region (op, *mrv);
4880 _session->add_command (cmd);
4887 commit_reversible_command ();
4891 Editor::fork_region ()
4893 RegionSelection rs = get_regions_from_selection_and_entered ();
4899 begin_reversible_command (_("Fork Region(s)"));
4901 set_canvas_cursor (_cursors->wait);
4904 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
4905 RegionSelection::iterator tmp = r;
4908 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*>(*r);
4912 boost::shared_ptr<Playlist> playlist = mrv->region()->playlist();
4913 boost::shared_ptr<MidiSource> new_source = _session->create_midi_source_by_stealing_name (mrv->midi_view()->track());
4914 boost::shared_ptr<MidiRegion> newregion = mrv->midi_region()->clone (new_source);
4916 playlist->clear_changes ();
4917 playlist->replace_region (mrv->region(), newregion, mrv->region()->position());
4918 _session->add_command(new StatefulDiffCommand (playlist));
4920 error << string_compose (_("Could not unlink %1"), mrv->region()->name()) << endmsg;
4927 commit_reversible_command ();
4929 set_canvas_cursor (current_canvas_cursor);
4933 Editor::quantize_region ()
4935 int selected_midi_region_cnt = 0;
4941 RegionSelection rs = get_regions_from_selection_and_entered ();
4947 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
4948 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*r);
4950 selected_midi_region_cnt++;
4954 if (selected_midi_region_cnt == 0) {
4958 QuantizeDialog* qd = new QuantizeDialog (*this);
4961 const int r = qd->run ();
4964 if (r == Gtk::RESPONSE_OK) {
4965 Quantize quant (*_session, qd->snap_start(), qd->snap_end(),
4966 qd->start_grid_size(), qd->end_grid_size(),
4967 qd->strength(), qd->swing(), qd->threshold());
4969 apply_midi_note_edit_op (quant);
4974 Editor::insert_patch_change (bool from_context)
4976 RegionSelection rs = get_regions_from_selection_and_entered ();
4982 const framepos_t p = get_preferred_edit_position (false, from_context);
4984 /* XXX: bit of a hack; use the MIDNAM from the first selected region;
4985 there may be more than one, but the PatchChangeDialog can only offer
4986 one set of patch menus.
4988 MidiRegionView* first = dynamic_cast<MidiRegionView*> (rs.front ());
4990 Evoral::PatchChange<Evoral::MusicalTime> empty (0, 0, 0, 0);
4991 PatchChangeDialog d (0, _session, empty, first->instrument_info(), Gtk::Stock::ADD);
4993 if (d.run() == RESPONSE_CANCEL) {
4997 for (RegionSelection::iterator i = rs.begin (); i != rs.end(); ++i) {
4998 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*i);
5000 if (p >= mrv->region()->first_frame() && p <= mrv->region()->last_frame()) {
5001 mrv->add_patch_change (p - mrv->region()->position(), d.patch ());
5008 Editor::apply_filter (Filter& filter, string command, ProgressReporter* progress)
5010 RegionSelection rs = get_regions_from_selection_and_entered ();
5016 begin_reversible_command (command);
5018 set_canvas_cursor (_cursors->wait);
5022 int const N = rs.size ();
5024 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
5025 RegionSelection::iterator tmp = r;
5028 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
5030 boost::shared_ptr<Playlist> playlist = arv->region()->playlist();
5033 progress->descend (1.0 / N);
5036 if (arv->audio_region()->apply (filter, progress) == 0) {
5038 playlist->clear_changes ();
5039 playlist->clear_owned_changes ();
5041 if (filter.results.empty ()) {
5043 /* no regions returned; remove the old one */
5044 playlist->remove_region (arv->region ());
5048 std::vector<boost::shared_ptr<Region> >::iterator res = filter.results.begin ();
5050 /* first region replaces the old one */
5051 playlist->replace_region (arv->region(), *res, (*res)->position());
5055 while (res != filter.results.end()) {
5056 playlist->add_region (*res, (*res)->position());
5062 /* We might have removed regions, which alters other regions' layering_index,
5063 so we need to do a recursive diff here.
5065 vector<Command*> cmds;
5066 playlist->rdiff (cmds);
5067 _session->add_commands (cmds);
5069 _session->add_command(new StatefulDiffCommand (playlist));
5075 progress->ascend ();
5083 commit_reversible_command ();
5086 set_canvas_cursor (current_canvas_cursor);
5090 Editor::external_edit_region ()
5096 Editor::reset_region_gain_envelopes ()
5098 RegionSelection rs = get_regions_from_selection_and_entered ();
5100 if (!_session || rs.empty()) {
5104 _session->begin_reversible_command (_("reset region gain"));
5106 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5107 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
5109 boost::shared_ptr<AutomationList> alist (arv->audio_region()->envelope());
5110 XMLNode& before (alist->get_state());
5112 arv->audio_region()->set_default_envelope ();
5113 _session->add_command (new MementoCommand<AutomationList>(*arv->audio_region()->envelope().get(), &before, &alist->get_state()));
5117 _session->commit_reversible_command ();
5121 Editor::set_region_gain_visibility (RegionView* rv)
5123 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (rv);
5125 arv->update_envelope_visibility();
5130 Editor::set_gain_envelope_visibility ()
5136 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5137 AudioTimeAxisView* v = dynamic_cast<AudioTimeAxisView*>(*i);
5139 v->audio_view()->foreach_regionview (sigc::mem_fun (this, &Editor::set_region_gain_visibility));
5145 Editor::toggle_gain_envelope_active ()
5147 if (_ignore_region_action) {
5151 RegionSelection rs = get_regions_from_selection_and_entered ();
5153 if (!_session || rs.empty()) {
5157 _session->begin_reversible_command (_("region gain envelope active"));
5159 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5160 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
5162 arv->region()->clear_changes ();
5163 arv->audio_region()->set_envelope_active (!arv->audio_region()->envelope_active());
5164 _session->add_command (new StatefulDiffCommand (arv->region()));
5168 _session->commit_reversible_command ();
5172 Editor::toggle_region_lock ()
5174 if (_ignore_region_action) {
5178 RegionSelection rs = get_regions_from_selection_and_entered ();
5180 if (!_session || rs.empty()) {
5184 _session->begin_reversible_command (_("toggle region lock"));
5186 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5187 (*i)->region()->clear_changes ();
5188 (*i)->region()->set_locked (!(*i)->region()->locked());
5189 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5192 _session->commit_reversible_command ();
5196 Editor::toggle_region_video_lock ()
5198 if (_ignore_region_action) {
5202 RegionSelection rs = get_regions_from_selection_and_entered ();
5204 if (!_session || rs.empty()) {
5208 _session->begin_reversible_command (_("Toggle Video Lock"));
5210 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5211 (*i)->region()->clear_changes ();
5212 (*i)->region()->set_video_locked (!(*i)->region()->video_locked());
5213 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5216 _session->commit_reversible_command ();
5220 Editor::toggle_region_lock_style ()
5222 if (_ignore_region_action) {
5226 RegionSelection rs = get_regions_from_selection_and_entered ();
5228 if (!_session || rs.empty()) {
5232 _session->begin_reversible_command (_("region lock style"));
5234 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5235 (*i)->region()->clear_changes ();
5236 PositionLockStyle const ns = (*i)->region()->position_lock_style() == AudioTime ? MusicTime : AudioTime;
5237 (*i)->region()->set_position_lock_style (ns);
5238 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5241 _session->commit_reversible_command ();
5245 Editor::toggle_opaque_region ()
5247 if (_ignore_region_action) {
5251 RegionSelection rs = get_regions_from_selection_and_entered ();
5253 if (!_session || rs.empty()) {
5257 _session->begin_reversible_command (_("change region opacity"));
5259 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5260 (*i)->region()->clear_changes ();
5261 (*i)->region()->set_opaque (!(*i)->region()->opaque());
5262 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5265 _session->commit_reversible_command ();
5269 Editor::toggle_record_enable ()
5271 bool new_state = false;
5273 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5274 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5277 if (!rtav->is_track())
5281 new_state = !rtav->track()->record_enabled();
5285 rtav->track()->set_record_enabled (new_state, this);
5290 Editor::toggle_solo ()
5292 bool new_state = false;
5294 boost::shared_ptr<RouteList> rl (new RouteList);
5296 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5297 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5304 new_state = !rtav->route()->soloed ();
5308 rl->push_back (rtav->route());
5311 _session->set_solo (rl, new_state, Session::rt_cleanup, true);
5315 Editor::toggle_mute ()
5317 bool new_state = false;
5319 boost::shared_ptr<RouteList> rl (new RouteList);
5321 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5322 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5329 new_state = !rtav->route()->muted();
5333 rl->push_back (rtav->route());
5336 _session->set_mute (rl, new_state, Session::rt_cleanup, true);
5340 Editor::toggle_solo_isolate ()
5345 Editor::set_fade_length (bool in)
5347 RegionSelection rs = get_regions_from_selection_and_entered ();
5353 /* we need a region to measure the offset from the start */
5355 RegionView* rv = rs.front ();
5357 framepos_t pos = get_preferred_edit_position();
5361 if (pos > rv->region()->last_frame() || pos < rv->region()->first_frame()) {
5362 /* edit point is outside the relevant region */
5367 if (pos <= rv->region()->position()) {
5371 len = pos - rv->region()->position();
5372 cmd = _("set fade in length");
5374 if (pos >= rv->region()->last_frame()) {
5378 len = rv->region()->last_frame() - pos;
5379 cmd = _("set fade out length");
5382 begin_reversible_command (cmd);
5384 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5385 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5391 boost::shared_ptr<AutomationList> alist;
5393 alist = tmp->audio_region()->fade_in();
5395 alist = tmp->audio_region()->fade_out();
5398 XMLNode &before = alist->get_state();
5401 tmp->audio_region()->set_fade_in_length (len);
5402 tmp->audio_region()->set_fade_in_active (true);
5404 tmp->audio_region()->set_fade_out_length (len);
5405 tmp->audio_region()->set_fade_out_active (true);
5408 XMLNode &after = alist->get_state();
5409 _session->add_command(new MementoCommand<AutomationList>(*alist, &before, &after));
5412 commit_reversible_command ();
5416 Editor::set_fade_in_shape (FadeShape shape)
5418 RegionSelection rs = get_regions_from_selection_and_entered ();
5424 begin_reversible_command (_("set fade in shape"));
5426 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5427 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5433 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_in();
5434 XMLNode &before = alist->get_state();
5436 tmp->audio_region()->set_fade_in_shape (shape);
5438 XMLNode &after = alist->get_state();
5439 _session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
5442 commit_reversible_command ();
5447 Editor::set_fade_out_shape (FadeShape shape)
5449 RegionSelection rs = get_regions_from_selection_and_entered ();
5455 begin_reversible_command (_("set fade out shape"));
5457 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5458 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5464 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_out();
5465 XMLNode &before = alist->get_state();
5467 tmp->audio_region()->set_fade_out_shape (shape);
5469 XMLNode &after = alist->get_state();
5470 _session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
5473 commit_reversible_command ();
5477 Editor::set_fade_in_active (bool yn)
5479 RegionSelection rs = get_regions_from_selection_and_entered ();
5485 begin_reversible_command (_("set fade in active"));
5487 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5488 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5495 boost::shared_ptr<AudioRegion> ar (tmp->audio_region());
5497 ar->clear_changes ();
5498 ar->set_fade_in_active (yn);
5499 _session->add_command (new StatefulDiffCommand (ar));
5502 commit_reversible_command ();
5506 Editor::set_fade_out_active (bool yn)
5508 RegionSelection rs = get_regions_from_selection_and_entered ();
5514 begin_reversible_command (_("set fade out active"));
5516 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5517 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5523 boost::shared_ptr<AudioRegion> ar (tmp->audio_region());
5525 ar->clear_changes ();
5526 ar->set_fade_out_active (yn);
5527 _session->add_command(new StatefulDiffCommand (ar));
5530 commit_reversible_command ();
5534 Editor::toggle_region_fades (int dir)
5536 if (_ignore_region_action) {
5540 boost::shared_ptr<AudioRegion> ar;
5543 RegionSelection rs = get_regions_from_selection_and_entered ();
5549 RegionSelection::iterator i;
5550 for (i = rs.begin(); i != rs.end(); ++i) {
5551 if ((ar = boost::dynamic_pointer_cast<AudioRegion>((*i)->region())) != 0) {
5553 yn = ar->fade_out_active ();
5555 yn = ar->fade_in_active ();
5561 if (i == rs.end()) {
5565 /* XXX should this undo-able? */
5567 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5568 if ((ar = boost::dynamic_pointer_cast<AudioRegion>((*i)->region())) == 0) {
5571 if (dir == 1 || dir == 0) {
5572 ar->set_fade_in_active (!yn);
5575 if (dir == -1 || dir == 0) {
5576 ar->set_fade_out_active (!yn);
5582 /** Update region fade visibility after its configuration has been changed */
5584 Editor::update_region_fade_visibility ()
5586 bool _fade_visibility = _session->config.get_show_region_fades ();
5588 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5589 AudioTimeAxisView* v = dynamic_cast<AudioTimeAxisView*>(*i);
5591 if (_fade_visibility) {
5592 v->audio_view()->show_all_fades ();
5594 v->audio_view()->hide_all_fades ();
5601 Editor::set_edit_point ()
5606 if (!mouse_frame (where, ignored)) {
5612 if (selection->markers.empty()) {
5614 mouse_add_new_marker (where);
5619 Location* loc = find_location_from_marker (selection->markers.front(), ignored);
5622 loc->move_to (where);
5628 Editor::set_playhead_cursor ()
5630 if (entered_marker) {
5631 _session->request_locate (entered_marker->position(), _session->transport_rolling());
5636 if (!mouse_frame (where, ignored)) {
5643 _session->request_locate (where, _session->transport_rolling());
5647 if ( Config->get_always_play_range() )
5648 cancel_time_selection();
5652 Editor::split_region ()
5654 if ( !selection->time.empty()) {
5655 separate_regions_between (selection->time);
5659 RegionSelection rs = get_regions_from_selection_and_edit_point ();
5661 framepos_t where = get_preferred_edit_position ();
5667 split_regions_at (where, rs);
5670 struct EditorOrderRouteSorter {
5671 bool operator() (boost::shared_ptr<Route> a, boost::shared_ptr<Route> b) {
5672 return a->order_key () < b->order_key ();
5677 Editor::select_next_route()
5679 if (selection->tracks.empty()) {
5680 selection->set (track_views.front());
5684 TimeAxisView* current = selection->tracks.front();
5688 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5689 if (*i == current) {
5691 if (i != track_views.end()) {
5694 current = (*(track_views.begin()));
5695 //selection->set (*(track_views.begin()));
5700 rui = dynamic_cast<RouteUI *>(current);
5701 } while ( current->hidden() || (rui != NULL && !rui->route()->active()));
5703 selection->set(current);
5705 ensure_track_visible(current);
5709 Editor::select_prev_route()
5711 if (selection->tracks.empty()) {
5712 selection->set (track_views.front());
5716 TimeAxisView* current = selection->tracks.front();
5720 for (TrackViewList::reverse_iterator i = track_views.rbegin(); i != track_views.rend(); ++i) {
5721 if (*i == current) {
5723 if (i != track_views.rend()) {
5726 current = *(track_views.rbegin());
5731 rui = dynamic_cast<RouteUI *>(current);
5732 } while ( current->hidden() || (rui != NULL && !rui->route()->active()));
5734 selection->set (current);
5736 ensure_track_visible(current);
5740 Editor::ensure_track_visible(TimeAxisView *track)
5742 if (track->hidden()) {
5746 /* compute visible area of trackview group, as offsets from top of
5750 double const current_view_min_y = vertical_adjustment.get_value();
5751 double const current_view_max_y = current_view_min_y + vertical_adjustment.get_page_size();
5753 double const track_min_y = track->y_position ();
5754 double const track_max_y = track->y_position () + track->effective_height ();
5756 if (track_min_y > current_view_min_y &&
5757 track_max_y <= current_view_max_y) {
5763 if (track_min_y < current_view_min_y) {
5764 // Track is above the current view
5765 new_value = track_min_y;
5767 // Track is below the current view
5768 new_value = track->y_position () + track->effective_height() - vertical_adjustment.get_page_size();
5771 vertical_adjustment.set_value(new_value);
5775 Editor::set_loop_from_selection (bool play)
5777 if (_session == 0 || selection->time.empty()) {
5781 framepos_t start = selection->time[clicked_selection].start;
5782 framepos_t end = selection->time[clicked_selection].end;
5784 set_loop_range (start, end, _("set loop range from selection"));
5787 _session->request_play_loop (true);
5788 _session->request_locate (start, true);
5793 Editor::set_loop_from_edit_range (bool play)
5795 if (_session == 0) {
5802 if (!get_edit_op_range (start, end)) {
5806 set_loop_range (start, end, _("set loop range from edit range"));
5809 _session->request_play_loop (true);
5810 _session->request_locate (start, true);
5815 Editor::set_loop_from_region (bool play)
5817 framepos_t start = max_framepos;
5820 RegionSelection rs = get_regions_from_selection_and_entered ();
5826 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5827 if ((*i)->region()->position() < start) {
5828 start = (*i)->region()->position();
5830 if ((*i)->region()->last_frame() + 1 > end) {
5831 end = (*i)->region()->last_frame() + 1;
5835 set_loop_range (start, end, _("set loop range from region"));
5838 _session->request_play_loop (true);
5839 _session->request_locate (start, true);
5844 Editor::set_punch_from_selection ()
5846 if (_session == 0 || selection->time.empty()) {
5850 framepos_t start = selection->time[clicked_selection].start;
5851 framepos_t end = selection->time[clicked_selection].end;
5853 set_punch_range (start, end, _("set punch range from selection"));
5857 Editor::set_punch_from_edit_range ()
5859 if (_session == 0) {
5866 if (!get_edit_op_range (start, end)) {
5870 set_punch_range (start, end, _("set punch range from edit range"));
5874 Editor::set_punch_from_region ()
5876 framepos_t start = max_framepos;
5879 RegionSelection rs = get_regions_from_selection_and_entered ();
5885 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5886 if ((*i)->region()->position() < start) {
5887 start = (*i)->region()->position();
5889 if ((*i)->region()->last_frame() + 1 > end) {
5890 end = (*i)->region()->last_frame() + 1;
5894 set_punch_range (start, end, _("set punch range from region"));
5898 Editor::pitch_shift_region ()
5900 RegionSelection rs = get_regions_from_selection_and_entered ();
5902 RegionSelection audio_rs;
5903 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5904 if (dynamic_cast<AudioRegionView*> (*i)) {
5905 audio_rs.push_back (*i);
5909 if (audio_rs.empty()) {
5913 pitch_shift (audio_rs, 1.2);
5917 Editor::transpose_region ()
5919 RegionSelection rs = get_regions_from_selection_and_entered ();
5921 list<MidiRegionView*> midi_region_views;
5922 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5923 MidiRegionView* mrv = dynamic_cast<MidiRegionView*> (*i);
5925 midi_region_views.push_back (mrv);
5930 int const r = d.run ();
5931 if (r != RESPONSE_ACCEPT) {
5935 for (list<MidiRegionView*>::iterator i = midi_region_views.begin(); i != midi_region_views.end(); ++i) {
5936 (*i)->midi_region()->transpose (d.semitones ());
5941 Editor::set_tempo_from_region ()
5943 RegionSelection rs = get_regions_from_selection_and_entered ();
5945 if (!_session || rs.empty()) {
5949 RegionView* rv = rs.front();
5951 define_one_bar (rv->region()->position(), rv->region()->last_frame() + 1);
5955 Editor::use_range_as_bar ()
5957 framepos_t start, end;
5958 if (get_edit_op_range (start, end)) {
5959 define_one_bar (start, end);
5964 Editor::define_one_bar (framepos_t start, framepos_t end)
5966 framepos_t length = end - start;
5968 const Meter& m (_session->tempo_map().meter_at (start));
5970 /* length = 1 bar */
5972 /* now we want frames per beat.
5973 we have frames per bar, and beats per bar, so ...
5976 /* XXXX METER MATH */
5978 double frames_per_beat = length / m.divisions_per_bar();
5980 /* beats per minute = */
5982 double beats_per_minute = (_session->frame_rate() * 60.0) / frames_per_beat;
5984 /* now decide whether to:
5986 (a) set global tempo
5987 (b) add a new tempo marker
5991 const TempoSection& t (_session->tempo_map().tempo_section_at (start));
5993 bool do_global = false;
5995 if ((_session->tempo_map().n_tempos() == 1) && (_session->tempo_map().n_meters() == 1)) {
5997 /* only 1 tempo & 1 meter: ask if the user wants to set the tempo
5998 at the start, or create a new marker
6001 vector<string> options;
6002 options.push_back (_("Cancel"));
6003 options.push_back (_("Add new marker"));
6004 options.push_back (_("Set global tempo"));
6007 _("Define one bar"),
6008 _("Do you want to set the global tempo or add a new tempo marker?"),
6012 c.set_default_response (2);
6028 /* more than 1 tempo and/or meter section already, go ahead do the "usual":
6029 if the marker is at the region starter, change it, otherwise add
6034 begin_reversible_command (_("set tempo from region"));
6035 XMLNode& before (_session->tempo_map().get_state());
6038 _session->tempo_map().change_initial_tempo (beats_per_minute, t.note_type());
6039 } else if (t.frame() == start) {
6040 _session->tempo_map().change_existing_tempo_at (start, beats_per_minute, t.note_type());
6042 Timecode::BBT_Time bbt;
6043 _session->tempo_map().bbt_time (start, bbt);
6044 _session->tempo_map().add_tempo (Tempo (beats_per_minute, t.note_type()), bbt);
6047 XMLNode& after (_session->tempo_map().get_state());
6049 _session->add_command (new MementoCommand<TempoMap>(_session->tempo_map(), &before, &after));
6050 commit_reversible_command ();
6054 Editor::split_region_at_transients ()
6056 AnalysisFeatureList positions;
6058 RegionSelection rs = get_regions_from_selection_and_entered ();
6060 if (!_session || rs.empty()) {
6064 _session->begin_reversible_command (_("split regions"));
6066 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ) {
6068 RegionSelection::iterator tmp;
6073 boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion> ((*i)->region());
6075 if (ar && (ar->get_transients (positions) == 0)) {
6076 split_region_at_points ((*i)->region(), positions, true);
6083 _session->commit_reversible_command ();
6088 Editor::split_region_at_points (boost::shared_ptr<Region> r, AnalysisFeatureList& positions, bool can_ferret, bool select_new)
6090 bool use_rhythmic_rodent = false;
6092 boost::shared_ptr<Playlist> pl = r->playlist();
6094 list<boost::shared_ptr<Region> > new_regions;
6100 if (positions.empty()) {
6105 if (positions.size() > 20 && can_ferret) {
6106 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);
6107 MessageDialog msg (msgstr,
6110 Gtk::BUTTONS_OK_CANCEL);
6113 msg.add_button (_("Call for the Ferret!"), RESPONSE_APPLY);
6114 msg.set_secondary_text (_("Press OK to continue with this split operation\nor ask the Ferret dialog to tune the analysis"));
6116 msg.set_secondary_text (_("Press OK to continue with this split operation"));
6119 msg.set_title (_("Excessive split?"));
6122 int response = msg.run();
6128 case RESPONSE_APPLY:
6129 use_rhythmic_rodent = true;
6136 if (use_rhythmic_rodent) {
6137 show_rhythm_ferret ();
6141 AnalysisFeatureList::const_iterator x;
6143 pl->clear_changes ();
6144 pl->clear_owned_changes ();
6146 x = positions.begin();
6148 if (x == positions.end()) {
6153 pl->remove_region (r);
6157 while (x != positions.end()) {
6159 /* deal with positons that are out of scope of present region bounds */
6160 if (*x <= 0 || *x > r->length()) {
6165 /* file start = original start + how far we from the initial position ?
6168 framepos_t file_start = r->start() + pos;
6170 /* length = next position - current position
6173 framepos_t len = (*x) - pos;
6175 /* XXX we do we really want to allow even single-sample regions?
6176 shouldn't we have some kind of lower limit on region size?
6185 if (RegionFactory::region_name (new_name, r->name())) {
6189 /* do NOT announce new regions 1 by one, just wait till they are all done */
6193 plist.add (ARDOUR::Properties::start, file_start);
6194 plist.add (ARDOUR::Properties::length, len);
6195 plist.add (ARDOUR::Properties::name, new_name);
6196 plist.add (ARDOUR::Properties::layer, 0);
6198 boost::shared_ptr<Region> nr = RegionFactory::create (r->sources(), plist, false);
6199 /* because we set annouce to false, manually add the new region to the
6202 RegionFactory::map_add (nr);
6204 pl->add_region (nr, r->position() + pos);
6207 new_regions.push_front(nr);
6216 RegionFactory::region_name (new_name, r->name());
6218 /* Add the final region */
6221 plist.add (ARDOUR::Properties::start, r->start() + pos);
6222 plist.add (ARDOUR::Properties::length, r->last_frame() - (r->position() + pos) + 1);
6223 plist.add (ARDOUR::Properties::name, new_name);
6224 plist.add (ARDOUR::Properties::layer, 0);
6226 boost::shared_ptr<Region> nr = RegionFactory::create (r->sources(), plist, false);
6227 /* because we set annouce to false, manually add the new region to the
6230 RegionFactory::map_add (nr);
6231 pl->add_region (nr, r->position() + pos);
6234 new_regions.push_front(nr);
6239 /* We might have removed regions, which alters other regions' layering_index,
6240 so we need to do a recursive diff here.
6242 vector<Command*> cmds;
6244 _session->add_commands (cmds);
6246 _session->add_command (new StatefulDiffCommand (pl));
6250 for (list<boost::shared_ptr<Region> >::iterator i = new_regions.begin(); i != new_regions.end(); ++i){
6251 set_selected_regionview_from_region_list ((*i), Selection::Add);
6257 Editor::place_transient()
6263 RegionSelection rs = get_regions_from_selection_and_edit_point ();
6269 framepos_t where = get_preferred_edit_position();
6271 _session->begin_reversible_command (_("place transient"));
6273 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6274 framepos_t position = (*r)->region()->position();
6275 (*r)->region()->add_transient(where - position);
6278 _session->commit_reversible_command ();
6282 Editor::remove_transient(ArdourCanvas::Item* item)
6288 ArdourCanvas::Line* _line = reinterpret_cast<ArdourCanvas::Line*> (item);
6291 AudioRegionView* _arv = reinterpret_cast<AudioRegionView*> (item->get_data ("regionview"));
6292 _arv->remove_transient (*(float*) _line->get_data ("position"));
6296 Editor::snap_regions_to_grid ()
6298 list <boost::shared_ptr<Playlist > > used_playlists;
6300 RegionSelection rs = get_regions_from_selection_and_entered ();
6302 if (!_session || rs.empty()) {
6306 _session->begin_reversible_command (_("snap regions to grid"));
6308 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6310 boost::shared_ptr<Playlist> pl = (*r)->region()->playlist();
6312 if (!pl->frozen()) {
6313 /* we haven't seen this playlist before */
6315 /* remember used playlists so we can thaw them later */
6316 used_playlists.push_back(pl);
6320 framepos_t start_frame = (*r)->region()->first_frame ();
6321 snap_to (start_frame);
6322 (*r)->region()->set_position (start_frame);
6325 while (used_playlists.size() > 0) {
6326 list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
6328 used_playlists.pop_front();
6331 _session->commit_reversible_command ();
6335 Editor::close_region_gaps ()
6337 list <boost::shared_ptr<Playlist > > used_playlists;
6339 RegionSelection rs = get_regions_from_selection_and_entered ();
6341 if (!_session || rs.empty()) {
6345 Dialog dialog (_("Close Region Gaps"));
6348 table.set_spacings (12);
6349 table.set_border_width (12);
6350 Label* l = manage (left_aligned_label (_("Crossfade length")));
6351 table.attach (*l, 0, 1, 0, 1);
6353 SpinButton spin_crossfade (1, 0);
6354 spin_crossfade.set_range (0, 15);
6355 spin_crossfade.set_increments (1, 1);
6356 spin_crossfade.set_value (5);
6357 table.attach (spin_crossfade, 1, 2, 0, 1);
6359 table.attach (*manage (new Label (_("ms"))), 2, 3, 0, 1);
6361 l = manage (left_aligned_label (_("Pull-back length")));
6362 table.attach (*l, 0, 1, 1, 2);
6364 SpinButton spin_pullback (1, 0);
6365 spin_pullback.set_range (0, 100);
6366 spin_pullback.set_increments (1, 1);
6367 spin_pullback.set_value(30);
6368 table.attach (spin_pullback, 1, 2, 1, 2);
6370 table.attach (*manage (new Label (_("ms"))), 2, 3, 1, 2);
6372 dialog.get_vbox()->pack_start (table);
6373 dialog.add_button (Stock::CANCEL, RESPONSE_CANCEL);
6374 dialog.add_button (_("Ok"), RESPONSE_ACCEPT);
6377 if (dialog.run () == RESPONSE_CANCEL) {
6381 framepos_t crossfade_len = spin_crossfade.get_value();
6382 framepos_t pull_back_frames = spin_pullback.get_value();
6384 crossfade_len = lrintf (crossfade_len * _session->frame_rate()/1000);
6385 pull_back_frames = lrintf (pull_back_frames * _session->frame_rate()/1000);
6387 /* Iterate over the region list and make adjacent regions overlap by crossfade_len_ms */
6389 _session->begin_reversible_command (_("close region gaps"));
6392 boost::shared_ptr<Region> last_region;
6394 rs.sort_by_position_and_track();
6396 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6398 boost::shared_ptr<Playlist> pl = (*r)->region()->playlist();
6400 if (!pl->frozen()) {
6401 /* we haven't seen this playlist before */
6403 /* remember used playlists so we can thaw them later */
6404 used_playlists.push_back(pl);
6408 framepos_t position = (*r)->region()->position();
6410 if (idx == 0 || position < last_region->position()){
6411 last_region = (*r)->region();
6416 (*r)->region()->trim_front( (position - pull_back_frames));
6417 last_region->trim_end( (position - pull_back_frames + crossfade_len));
6419 last_region = (*r)->region();
6424 while (used_playlists.size() > 0) {
6425 list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
6427 used_playlists.pop_front();
6430 _session->commit_reversible_command ();
6434 Editor::tab_to_transient (bool forward)
6436 AnalysisFeatureList positions;
6438 RegionSelection rs = get_regions_from_selection_and_entered ();
6444 framepos_t pos = _session->audible_frame ();
6446 if (!selection->tracks.empty()) {
6448 /* don't waste time searching for transients in duplicate playlists.
6451 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
6453 for (TrackViewList::iterator t = ts.begin(); t != ts.end(); ++t) {
6455 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*t);
6458 boost::shared_ptr<Track> tr = rtv->track();
6460 boost::shared_ptr<Playlist> pl = tr->playlist ();
6462 framepos_t result = pl->find_next_transient (pos, forward ? 1 : -1);
6465 positions.push_back (result);
6478 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6479 (*r)->region()->get_transients (positions);
6483 TransientDetector::cleanup_transients (positions, _session->frame_rate(), 3.0);
6486 AnalysisFeatureList::iterator x;
6488 for (x = positions.begin(); x != positions.end(); ++x) {
6494 if (x != positions.end ()) {
6495 _session->request_locate (*x);
6499 AnalysisFeatureList::reverse_iterator x;
6501 for (x = positions.rbegin(); x != positions.rend(); ++x) {
6507 if (x != positions.rend ()) {
6508 _session->request_locate (*x);
6514 Editor::playhead_forward_to_grid ()
6520 framepos_t pos = playhead_cursor->current_frame ();
6521 if (pos < max_framepos - 1) {
6523 snap_to_internal (pos, 1, false);
6524 _session->request_locate (pos);
6530 Editor::playhead_backward_to_grid ()
6536 framepos_t pos = playhead_cursor->current_frame ();
6539 snap_to_internal (pos, -1, false);
6540 _session->request_locate (pos);
6545 Editor::set_track_height (Height h)
6547 TrackSelection& ts (selection->tracks);
6549 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
6550 (*x)->set_height_enum (h);
6555 Editor::toggle_tracks_active ()
6557 TrackSelection& ts (selection->tracks);
6559 bool target = false;
6565 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
6566 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*x);
6570 target = !rtv->_route->active();
6573 rtv->_route->set_active (target, this);
6579 Editor::remove_tracks ()
6581 TrackSelection& ts (selection->tracks);
6587 vector<string> choices;
6591 const char* trackstr;
6593 vector<boost::shared_ptr<Route> > routes;
6594 bool special_bus = false;
6596 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
6597 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*x);
6601 if (rtv->is_track()) {
6606 routes.push_back (rtv->_route);
6608 if (rtv->route()->is_master() || rtv->route()->is_monitor()) {
6613 if (special_bus && !Config->get_allow_special_bus_removal()) {
6614 MessageDialog msg (_("That would be bad news ...."),
6618 msg.set_secondary_text (string_compose (_(
6619 "Removing the master or monitor bus is such a bad idea\n\
6620 that %1 is not going to allow it.\n\
6622 If you really want to do this sort of thing\n\
6623 edit your ardour.rc file to set the\n\
6624 \"allow-special-bus-removal\" option to be \"yes\""), PROGRAM_NAME));
6631 if (ntracks + nbusses == 0) {
6636 trackstr = _("tracks");
6638 trackstr = _("track");
6642 busstr = _("busses");
6649 prompt = string_compose (_("Do you really want to remove %1 %2 and %3 %4?\n"
6650 "(You may also lose the playlists associated with the %2)\n\n"
6651 "This action cannot be undone, and the session file will be overwritten!"),
6652 ntracks, trackstr, nbusses, busstr);
6654 prompt = string_compose (_("Do you really want to remove %1 %2?\n"
6655 "(You may also lose the playlists associated with the %2)\n\n"
6656 "This action cannot be undone, and the session file will be overwritten!"),
6659 } else if (nbusses) {
6660 prompt = string_compose (_("Do you really want to remove %1 %2?\n\n"
6661 "This action cannot be undon, and the session file will be overwritten"),
6665 choices.push_back (_("No, do nothing."));
6666 if (ntracks + nbusses > 1) {
6667 choices.push_back (_("Yes, remove them."));
6669 choices.push_back (_("Yes, remove it."));
6674 title = string_compose (_("Remove %1"), trackstr);
6676 title = string_compose (_("Remove %1"), busstr);
6679 Choice prompter (title, prompt, choices);
6681 if (prompter.run () != 1) {
6685 for (vector<boost::shared_ptr<Route> >::iterator x = routes.begin(); x != routes.end(); ++x) {
6686 _session->remove_route (*x);
6691 Editor::do_insert_time ()
6693 if (selection->tracks.empty()) {
6697 InsertTimeDialog d (*this);
6698 int response = d.run ();
6700 if (response != RESPONSE_OK) {
6704 if (d.distance() == 0) {
6708 InsertTimeOption opt = d.intersected_region_action ();
6711 get_preferred_edit_position(),
6717 d.move_glued_markers(),
6718 d.move_locked_markers(),
6724 Editor::insert_time (
6725 framepos_t pos, framecnt_t frames, InsertTimeOption opt,
6726 bool all_playlists, bool ignore_music_glue, bool markers_too, bool glued_markers_too, bool locked_markers_too, bool tempo_too
6729 bool commit = false;
6731 if (Config->get_edit_mode() == Lock) {
6735 begin_reversible_command (_("insert time"));
6737 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
6739 for (TrackViewList::iterator x = ts.begin(); x != ts.end(); ++x) {
6743 /* don't operate on any playlist more than once, which could
6744 * happen if "all playlists" is enabled, but there is more
6745 * than 1 track using playlists "from" a given track.
6748 set<boost::shared_ptr<Playlist> > pl;
6750 if (all_playlists) {
6751 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*x);
6753 vector<boost::shared_ptr<Playlist> > all = _session->playlists->playlists_for_track (rtav->track ());
6754 for (vector<boost::shared_ptr<Playlist> >::iterator p = all.begin(); p != all.end(); ++p) {
6759 if ((*x)->playlist ()) {
6760 pl.insert ((*x)->playlist ());
6764 for (set<boost::shared_ptr<Playlist> >::iterator i = pl.begin(); i != pl.end(); ++i) {
6766 (*i)->clear_changes ();
6767 (*i)->clear_owned_changes ();
6769 if (opt == SplitIntersected) {
6773 (*i)->shift (pos, frames, (opt == MoveIntersected), ignore_music_glue);
6775 vector<Command*> cmds;
6777 _session->add_commands (cmds);
6779 _session->add_command (new StatefulDiffCommand (*i));
6784 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*x);
6786 rtav->route ()->shift (pos, frames);
6794 XMLNode& before (_session->locations()->get_state());
6795 Locations::LocationList copy (_session->locations()->list());
6797 for (Locations::LocationList::iterator i = copy.begin(); i != copy.end(); ++i) {
6799 Locations::LocationList::const_iterator tmp;
6801 bool const was_locked = (*i)->locked ();
6802 if (locked_markers_too) {
6806 if ((*i)->position_lock_style() == AudioTime || glued_markers_too) {
6808 if ((*i)->start() >= pos) {
6809 (*i)->set_start ((*i)->start() + frames);
6810 if (!(*i)->is_mark()) {
6811 (*i)->set_end ((*i)->end() + frames);
6824 XMLNode& after (_session->locations()->get_state());
6825 _session->add_command (new MementoCommand<Locations>(*_session->locations(), &before, &after));
6830 _session->tempo_map().insert_time (pos, frames);
6834 commit_reversible_command ();
6839 Editor::fit_selected_tracks ()
6841 if (!selection->tracks.empty()) {
6842 fit_tracks (selection->tracks);
6846 /* no selected tracks - use tracks with selected regions */
6848 if (!selection->regions.empty()) {
6849 for (RegionSelection::iterator r = selection->regions.begin(); r != selection->regions.end(); ++r) {
6850 tvl.push_back (&(*r)->get_time_axis_view ());
6856 } else if (internal_editing()) {
6857 /* no selected tracks, or regions, but in internal edit mode, so follow the mouse and use
6860 if (entered_track) {
6861 tvl.push_back (entered_track);
6869 Editor::fit_tracks (TrackViewList & tracks)
6871 if (tracks.empty()) {
6875 uint32_t child_heights = 0;
6876 int visible_tracks = 0;
6878 for (TrackSelection::iterator t = tracks.begin(); t != tracks.end(); ++t) {
6880 if (!(*t)->marked_for_display()) {
6884 child_heights += (*t)->effective_height() - (*t)->current_height();
6888 /* compute the per-track height from:
6890 total canvas visible height -
6891 height that will be taken by visible children of selected
6892 tracks - height of the ruler/hscroll area
6894 uint32_t h = (uint32_t) floor ((_visible_canvas_height - (child_heights + _trackview_group->canvas_origin().y)) / visible_tracks);
6895 double first_y_pos = DBL_MAX;
6897 if (h < TimeAxisView::preset_height (HeightSmall)) {
6898 MessageDialog msg (*this, _("There are too many tracks to fit in the current window"));
6899 /* too small to be displayed */
6903 undo_visual_stack.push_back (current_visual_state (true));
6904 no_save_visual = true;
6906 /* build a list of all tracks, including children */
6909 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
6911 TimeAxisView::Children c = (*i)->get_child_list ();
6912 for (TimeAxisView::Children::iterator j = c.begin(); j != c.end(); ++j) {
6913 all.push_back (j->get());
6917 /* operate on all tracks, hide unselected ones that are in the middle of selected ones */
6919 bool within_selected = false;
6921 for (TrackViewList::iterator t = all.begin(); t != all.end(); ++t) {
6923 TrackViewList::iterator next;
6928 if ((*t)->marked_for_display ()) {
6929 if (tracks.contains (*t)) {
6930 (*t)->set_height (h);
6931 first_y_pos = std::min ((*t)->y_position (), first_y_pos);
6932 within_selected = true;
6933 } else if (within_selected) {
6934 hide_track_in_display (*t);
6940 set the controls_layout height now, because waiting for its size
6941 request signal handler will cause the vertical adjustment setting to fail
6944 controls_layout.property_height () = _full_canvas_height;
6945 vertical_adjustment.set_value (first_y_pos);
6947 redo_visual_stack.push_back (current_visual_state (true));
6951 Editor::save_visual_state (uint32_t n)
6953 while (visual_states.size() <= n) {
6954 visual_states.push_back (0);
6957 if (visual_states[n] != 0) {
6958 delete visual_states[n];
6961 visual_states[n] = current_visual_state (true);
6966 Editor::goto_visual_state (uint32_t n)
6968 if (visual_states.size() <= n) {
6972 if (visual_states[n] == 0) {
6976 use_visual_state (*visual_states[n]);
6980 Editor::start_visual_state_op (uint32_t n)
6982 save_visual_state (n);
6984 PopUp* pup = new PopUp (WIN_POS_MOUSE, 1000, true);
6986 snprintf (buf, sizeof (buf), _("Saved view %u"), n+1);
6987 pup->set_text (buf);
6992 Editor::cancel_visual_state_op (uint32_t n)
6994 goto_visual_state (n);
6998 Editor::toggle_region_mute ()
7000 if (_ignore_region_action) {
7004 RegionSelection rs = get_regions_from_selection_and_entered ();
7010 if (rs.size() > 1) {
7011 begin_reversible_command (_("mute regions"));
7013 begin_reversible_command (_("mute region"));
7016 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
7018 (*i)->region()->playlist()->clear_changes ();
7019 (*i)->region()->set_muted (!(*i)->region()->muted ());
7020 _session->add_command (new StatefulDiffCommand ((*i)->region()->playlist()));
7024 commit_reversible_command ();
7028 Editor::combine_regions ()
7030 /* foreach track with selected regions, take all selected regions
7031 and join them into a new region containing the subregions (as a
7035 typedef set<RouteTimeAxisView*> RTVS;
7038 if (selection->regions.empty()) {
7042 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
7043 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(&(*i)->get_time_axis_view());
7046 tracks.insert (rtv);
7050 begin_reversible_command (_("combine regions"));
7052 vector<RegionView*> new_selection;
7054 for (RTVS::iterator i = tracks.begin(); i != tracks.end(); ++i) {
7057 if ((rv = (*i)->combine_regions ()) != 0) {
7058 new_selection.push_back (rv);
7062 selection->clear_regions ();
7063 for (vector<RegionView*>::iterator i = new_selection.begin(); i != new_selection.end(); ++i) {
7064 selection->add (*i);
7067 commit_reversible_command ();
7071 Editor::uncombine_regions ()
7073 typedef set<RouteTimeAxisView*> RTVS;
7076 if (selection->regions.empty()) {
7080 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
7081 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(&(*i)->get_time_axis_view());
7084 tracks.insert (rtv);
7088 begin_reversible_command (_("uncombine regions"));
7090 for (RTVS::iterator i = tracks.begin(); i != tracks.end(); ++i) {
7091 (*i)->uncombine_regions ();
7094 commit_reversible_command ();
7098 Editor::toggle_midi_input_active (bool flip_others)
7101 boost::shared_ptr<RouteList> rl (new RouteList);
7103 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
7104 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
7110 boost::shared_ptr<MidiTrack> mt = rtav->midi_track();
7113 rl->push_back (rtav->route());
7114 onoff = !mt->input_active();
7118 _session->set_exclusive_input_active (rl, onoff, flip_others);
7125 lock_dialog = new ArdourDialog (string_compose (_("%1 is Locked"), PROGRAM_NAME), true);
7126 Gtk::Button* b = manage (new Gtk::Button (_("Click me to unlock")));
7127 b->signal_clicked().connect (sigc::mem_fun (*this, &Editor::unlock));
7129 lock_dialog->get_vbox()->pack_start (*b);
7130 lock_dialog->get_vbox()->show_all ();
7133 ActionManager::disable_all_actions ();
7134 lock_dialog->present ();
7140 lock_dialog->hide ();
7141 ActionManager::pop_action_state ();