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);
2121 Editor::insert_region_list_selection (float times)
2123 RouteTimeAxisView *tv = 0;
2124 boost::shared_ptr<Playlist> playlist;
2126 if (clicked_routeview != 0) {
2127 tv = clicked_routeview;
2128 } else if (!selection->tracks.empty()) {
2129 if ((tv = dynamic_cast<RouteTimeAxisView*>(selection->tracks.front())) == 0) {
2132 } else if (entered_track != 0) {
2133 if ((tv = dynamic_cast<RouteTimeAxisView*>(entered_track)) == 0) {
2140 if ((playlist = tv->playlist()) == 0) {
2144 boost::shared_ptr<Region> region = _regions->get_single_selection ();
2149 begin_reversible_command (_("insert region"));
2150 playlist->clear_changes ();
2151 playlist->add_region ((RegionFactory::create (region, true)), get_preferred_edit_position(), times);
2152 _session->add_command(new StatefulDiffCommand (playlist));
2153 commit_reversible_command ();
2156 /* BUILT-IN EFFECTS */
2159 Editor::reverse_selection ()
2164 /* GAIN ENVELOPE EDITING */
2167 Editor::edit_envelope ()
2174 Editor::transition_to_rolling (bool fwd)
2180 if (_session->config.get_external_sync()) {
2181 switch (Config->get_sync_source()) {
2185 /* transport controlled by the master */
2190 if (_session->is_auditioning()) {
2191 _session->cancel_audition ();
2195 _session->request_transport_speed (fwd ? 1.0f : -1.0f);
2199 Editor::play_from_start ()
2201 _session->request_locate (_session->current_start_frame(), true);
2205 Editor::play_from_edit_point ()
2207 _session->request_locate (get_preferred_edit_position(), true);
2211 Editor::play_from_edit_point_and_return ()
2213 framepos_t start_frame;
2214 framepos_t return_frame;
2216 start_frame = get_preferred_edit_position (true);
2218 if (_session->transport_rolling()) {
2219 _session->request_locate (start_frame, false);
2223 /* don't reset the return frame if its already set */
2225 if ((return_frame = _session->requested_return_frame()) < 0) {
2226 return_frame = _session->audible_frame();
2229 if (start_frame >= 0) {
2230 _session->request_roll_at_and_return (start_frame, return_frame);
2235 Editor::play_selection ()
2237 if (selection->time.empty()) {
2241 _session->request_play_range (&selection->time, true);
2245 Editor::get_preroll ()
2247 return 1.0 /*Config->get_edit_preroll_seconds()*/ * _session->frame_rate();
2252 Editor::maybe_locate_with_edit_preroll ( framepos_t location )
2254 if ( _session->transport_rolling() || !Config->get_always_play_range() )
2257 location -= get_preroll();
2259 //don't try to locate before the beginning of time
2263 //if follow_playhead is on, keep the playhead on the screen
2264 if ( _follow_playhead )
2265 if ( location < leftmost_frame )
2266 location = leftmost_frame;
2268 _session->request_locate( location );
2272 Editor::play_with_preroll ()
2274 if (selection->time.empty()) {
2277 framepos_t preroll = get_preroll();
2279 framepos_t start = 0;
2280 if (selection->time[clicked_selection].start > preroll)
2281 start = selection->time[clicked_selection].start - preroll;
2283 framepos_t end = selection->time[clicked_selection].end + preroll;
2285 AudioRange ar (start, end, 0);
2286 list<AudioRange> lar;
2289 _session->request_play_range (&lar, true);
2294 Editor::play_location (Location& location)
2296 if (location.start() <= location.end()) {
2300 _session->request_bounded_roll (location.start(), location.end());
2304 Editor::loop_location (Location& location)
2306 if (location.start() <= location.end()) {
2312 if ((tll = transport_loop_location()) != 0) {
2313 tll->set (location.start(), location.end());
2315 // enable looping, reposition and start rolling
2316 _session->request_play_loop (true);
2317 _session->request_locate (tll->start(), true);
2322 Editor::do_layer_operation (LayerOperation op)
2324 if (selection->regions.empty ()) {
2328 bool const multiple = selection->regions.size() > 1;
2332 begin_reversible_command (_("raise regions"));
2334 begin_reversible_command (_("raise region"));
2340 begin_reversible_command (_("raise regions to top"));
2342 begin_reversible_command (_("raise region to top"));
2348 begin_reversible_command (_("lower regions"));
2350 begin_reversible_command (_("lower region"));
2356 begin_reversible_command (_("lower regions to bottom"));
2358 begin_reversible_command (_("lower region"));
2363 set<boost::shared_ptr<Playlist> > playlists = selection->regions.playlists ();
2364 for (set<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
2365 (*i)->clear_owned_changes ();
2368 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
2369 boost::shared_ptr<Region> r = (*i)->region ();
2381 r->lower_to_bottom ();
2385 for (set<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
2386 vector<Command*> cmds;
2388 _session->add_commands (cmds);
2391 commit_reversible_command ();
2395 Editor::raise_region ()
2397 do_layer_operation (Raise);
2401 Editor::raise_region_to_top ()
2403 do_layer_operation (RaiseToTop);
2407 Editor::lower_region ()
2409 do_layer_operation (Lower);
2413 Editor::lower_region_to_bottom ()
2415 do_layer_operation (LowerToBottom);
2418 /** Show the region editor for the selected regions */
2420 Editor::show_region_properties ()
2422 selection->foreach_regionview (&RegionView::show_region_editor);
2425 /** Show the midi list editor for the selected MIDI regions */
2427 Editor::show_midi_list_editor ()
2429 selection->foreach_midi_regionview (&MidiRegionView::show_list_editor);
2433 Editor::rename_region ()
2435 RegionSelection rs = get_regions_from_selection_and_entered ();
2441 ArdourDialog d (*this, _("Rename Region"), true, false);
2443 Label label (_("New name:"));
2446 hbox.set_spacing (6);
2447 hbox.pack_start (label, false, false);
2448 hbox.pack_start (entry, true, true);
2450 d.get_vbox()->set_border_width (12);
2451 d.get_vbox()->pack_start (hbox, false, false);
2453 d.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
2454 d.add_button(Gtk::Stock::OK, Gtk::RESPONSE_OK);
2456 d.set_size_request (300, -1);
2458 entry.set_text (rs.front()->region()->name());
2459 entry.select_region (0, -1);
2461 entry.signal_activate().connect (sigc::bind (sigc::mem_fun (d, &Dialog::response), RESPONSE_OK));
2467 int const ret = d.run();
2471 if (ret != RESPONSE_OK) {
2475 std::string str = entry.get_text();
2476 strip_whitespace_edges (str);
2478 rs.front()->region()->set_name (str);
2479 _regions->redisplay ();
2484 Editor::audition_playlist_region_via_route (boost::shared_ptr<Region> region, Route& route)
2486 if (_session->is_auditioning()) {
2487 _session->cancel_audition ();
2490 // note: some potential for creativity here, because region doesn't
2491 // have to belong to the playlist that Route is handling
2493 // bool was_soloed = route.soloed();
2495 route.set_solo (true, this);
2497 _session->request_bounded_roll (region->position(), region->position() + region->length());
2499 /* XXX how to unset the solo state ? */
2502 /** Start an audition of the first selected region */
2504 Editor::play_edit_range ()
2506 framepos_t start, end;
2508 if (get_edit_op_range (start, end)) {
2509 _session->request_bounded_roll (start, end);
2514 Editor::play_selected_region ()
2516 framepos_t start = max_framepos;
2519 RegionSelection rs = get_regions_from_selection_and_entered ();
2525 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
2526 if ((*i)->region()->position() < start) {
2527 start = (*i)->region()->position();
2529 if ((*i)->region()->last_frame() + 1 > end) {
2530 end = (*i)->region()->last_frame() + 1;
2534 _session->request_bounded_roll (start, end);
2538 Editor::audition_playlist_region_standalone (boost::shared_ptr<Region> region)
2540 _session->audition_region (region);
2544 Editor::region_from_selection ()
2546 if (clicked_axisview == 0) {
2550 if (selection->time.empty()) {
2554 framepos_t start = selection->time[clicked_selection].start;
2555 framepos_t end = selection->time[clicked_selection].end;
2557 TrackViewList tracks = get_tracks_for_range_action ();
2559 framepos_t selection_cnt = end - start + 1;
2561 for (TrackSelection::iterator i = tracks.begin(); i != tracks.end(); ++i) {
2562 boost::shared_ptr<Region> current;
2563 boost::shared_ptr<Playlist> pl;
2564 framepos_t internal_start;
2567 if ((pl = (*i)->playlist()) == 0) {
2571 if ((current = pl->top_region_at (start)) == 0) {
2575 internal_start = start - current->position();
2576 RegionFactory::region_name (new_name, current->name(), true);
2580 plist.add (ARDOUR::Properties::start, current->start() + internal_start);
2581 plist.add (ARDOUR::Properties::length, selection_cnt);
2582 plist.add (ARDOUR::Properties::name, new_name);
2583 plist.add (ARDOUR::Properties::layer, 0);
2585 boost::shared_ptr<Region> region (RegionFactory::create (current, plist));
2590 Editor::create_region_from_selection (vector<boost::shared_ptr<Region> >& new_regions)
2592 if (selection->time.empty() || selection->tracks.empty()) {
2596 framepos_t start = selection->time[clicked_selection].start;
2597 framepos_t end = selection->time[clicked_selection].end;
2599 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
2600 sort_track_selection (ts);
2602 for (TrackSelection::iterator i = ts.begin(); i != ts.end(); ++i) {
2603 boost::shared_ptr<Region> current;
2604 boost::shared_ptr<Playlist> playlist;
2605 framepos_t internal_start;
2608 if ((playlist = (*i)->playlist()) == 0) {
2612 if ((current = playlist->top_region_at(start)) == 0) {
2616 internal_start = start - current->position();
2617 RegionFactory::region_name (new_name, current->name(), true);
2621 plist.add (ARDOUR::Properties::start, current->start() + internal_start);
2622 plist.add (ARDOUR::Properties::length, end - start + 1);
2623 plist.add (ARDOUR::Properties::name, new_name);
2625 new_regions.push_back (RegionFactory::create (current, plist));
2630 Editor::split_multichannel_region ()
2632 RegionSelection rs = get_regions_from_selection_and_entered ();
2638 vector< boost::shared_ptr<Region> > v;
2640 for (list<RegionView*>::iterator x = rs.begin(); x != rs.end(); ++x) {
2641 (*x)->region()->separate_by_channel (*_session, v);
2646 Editor::new_region_from_selection ()
2648 region_from_selection ();
2649 cancel_selection ();
2653 add_if_covered (RegionView* rv, const AudioRange* ar, RegionSelection* rs)
2655 switch (rv->region()->coverage (ar->start, ar->end - 1)) {
2656 case Evoral::OverlapNone:
2664 * - selected tracks, or if there are none...
2665 * - tracks containing selected regions, or if there are none...
2670 Editor::get_tracks_for_range_action () const
2674 if (selection->tracks.empty()) {
2676 /* use tracks with selected regions */
2678 RegionSelection rs = selection->regions;
2680 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
2681 TimeAxisView* tv = &(*i)->get_time_axis_view();
2683 if (!t.contains (tv)) {
2689 /* no regions and no tracks: use all tracks */
2695 t = selection->tracks;
2698 return t.filter_to_unique_playlists();
2702 Editor::separate_regions_between (const TimeSelection& ts)
2704 bool in_command = false;
2705 boost::shared_ptr<Playlist> playlist;
2706 RegionSelection new_selection;
2708 TrackViewList tmptracks = get_tracks_for_range_action ();
2709 sort_track_selection (tmptracks);
2711 for (TrackSelection::iterator i = tmptracks.begin(); i != tmptracks.end(); ++i) {
2713 RouteTimeAxisView* rtv;
2715 if ((rtv = dynamic_cast<RouteTimeAxisView*> ((*i))) != 0) {
2717 if (rtv->is_track()) {
2719 /* no edits to destructive tracks */
2721 if (rtv->track()->destructive()) {
2725 if ((playlist = rtv->playlist()) != 0) {
2727 playlist->clear_changes ();
2729 /* XXX need to consider musical time selections here at some point */
2731 double speed = rtv->track()->speed();
2734 for (list<AudioRange>::const_iterator t = ts.begin(); t != ts.end(); ++t) {
2736 sigc::connection c = rtv->view()->RegionViewAdded.connect (
2737 sigc::mem_fun(*this, &Editor::collect_new_region_view));
2739 latest_regionviews.clear ();
2741 playlist->partition ((framepos_t)((*t).start * speed),
2742 (framepos_t)((*t).end * speed), false);
2746 if (!latest_regionviews.empty()) {
2748 rtv->view()->foreach_regionview (sigc::bind (
2749 sigc::ptr_fun (add_if_covered),
2750 &(*t), &new_selection));
2753 begin_reversible_command (_("separate"));
2757 /* pick up changes to existing regions */
2759 vector<Command*> cmds;
2760 playlist->rdiff (cmds);
2761 _session->add_commands (cmds);
2763 /* pick up changes to the playlist itself (adds/removes)
2766 _session->add_command(new StatefulDiffCommand (playlist));
2775 selection->set (new_selection);
2776 set_mouse_mode (MouseObject);
2778 commit_reversible_command ();
2782 struct PlaylistState {
2783 boost::shared_ptr<Playlist> playlist;
2787 /** Take tracks from get_tracks_for_range_action and cut any regions
2788 * on those tracks so that the tracks are empty over the time
2792 Editor::separate_region_from_selection ()
2794 /* preferentially use *all* ranges in the time selection if we're in range mode
2795 to allow discontiguous operation, since get_edit_op_range() currently
2796 returns a single range.
2799 if (!selection->time.empty()) {
2801 separate_regions_between (selection->time);
2808 if (get_edit_op_range (start, end)) {
2810 AudioRange ar (start, end, 1);
2814 separate_regions_between (ts);
2820 Editor::separate_region_from_punch ()
2822 Location* loc = _session->locations()->auto_punch_location();
2824 separate_regions_using_location (*loc);
2829 Editor::separate_region_from_loop ()
2831 Location* loc = _session->locations()->auto_loop_location();
2833 separate_regions_using_location (*loc);
2838 Editor::separate_regions_using_location (Location& loc)
2840 if (loc.is_mark()) {
2844 AudioRange ar (loc.start(), loc.end(), 1);
2849 separate_regions_between (ts);
2852 /** Separate regions under the selected region */
2854 Editor::separate_under_selected_regions ()
2856 vector<PlaylistState> playlists;
2860 rs = get_regions_from_selection_and_entered();
2862 if (!_session || rs.empty()) {
2866 begin_reversible_command (_("separate region under"));
2868 list<boost::shared_ptr<Region> > regions_to_remove;
2870 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
2871 // we can't just remove the region(s) in this loop because
2872 // this removes them from the RegionSelection, and they thus
2873 // disappear from underneath the iterator, and the ++i above
2874 // SEGVs in a puzzling fashion.
2876 // so, first iterate over the regions to be removed from rs and
2877 // add them to the regions_to_remove list, and then
2878 // iterate over the list to actually remove them.
2880 regions_to_remove.push_back ((*i)->region());
2883 for (list<boost::shared_ptr<Region> >::iterator rl = regions_to_remove.begin(); rl != regions_to_remove.end(); ++rl) {
2885 boost::shared_ptr<Playlist> playlist = (*rl)->playlist();
2888 // is this check necessary?
2892 vector<PlaylistState>::iterator i;
2894 //only take state if this is a new playlist.
2895 for (i = playlists.begin(); i != playlists.end(); ++i) {
2896 if ((*i).playlist == playlist) {
2901 if (i == playlists.end()) {
2903 PlaylistState before;
2904 before.playlist = playlist;
2905 before.before = &playlist->get_state();
2907 playlist->freeze ();
2908 playlists.push_back(before);
2911 //Partition on the region bounds
2912 playlist->partition ((*rl)->first_frame() - 1, (*rl)->last_frame() + 1, true);
2914 //Re-add region that was just removed due to the partition operation
2915 playlist->add_region( (*rl), (*rl)->first_frame() );
2918 vector<PlaylistState>::iterator pl;
2920 for (pl = playlists.begin(); pl != playlists.end(); ++pl) {
2921 (*pl).playlist->thaw ();
2922 _session->add_command(new MementoCommand<Playlist>(*(*pl).playlist, (*pl).before, &(*pl).playlist->get_state()));
2925 commit_reversible_command ();
2929 Editor::crop_region_to_selection ()
2931 if (!selection->time.empty()) {
2933 crop_region_to (selection->time.start(), selection->time.end_frame());
2940 if (get_edit_op_range (start, end)) {
2941 crop_region_to (start, end);
2948 Editor::crop_region_to (framepos_t start, framepos_t end)
2950 vector<boost::shared_ptr<Playlist> > playlists;
2951 boost::shared_ptr<Playlist> playlist;
2954 if (selection->tracks.empty()) {
2955 ts = track_views.filter_to_unique_playlists();
2957 ts = selection->tracks.filter_to_unique_playlists ();
2960 sort_track_selection (ts);
2962 for (TrackSelection::iterator i = ts.begin(); i != ts.end(); ++i) {
2964 RouteTimeAxisView* rtv;
2966 if ((rtv = dynamic_cast<RouteTimeAxisView*> ((*i))) != 0) {
2968 boost::shared_ptr<Track> t = rtv->track();
2970 if (t != 0 && ! t->destructive()) {
2972 if ((playlist = rtv->playlist()) != 0) {
2973 playlists.push_back (playlist);
2979 if (playlists.empty()) {
2983 framepos_t the_start;
2987 begin_reversible_command (_("trim to selection"));
2989 for (vector<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
2991 boost::shared_ptr<Region> region;
2995 if ((region = (*i)->top_region_at(the_start)) == 0) {
2999 /* now adjust lengths to that we do the right thing
3000 if the selection extends beyond the region
3003 the_start = max (the_start, (framepos_t) region->position());
3004 if (max_framepos - the_start < region->length()) {
3005 the_end = the_start + region->length() - 1;
3007 the_end = max_framepos;
3009 the_end = min (end, the_end);
3010 cnt = the_end - the_start + 1;
3012 region->clear_changes ();
3013 region->trim_to (the_start, cnt);
3014 _session->add_command (new StatefulDiffCommand (region));
3017 commit_reversible_command ();
3021 Editor::region_fill_track ()
3023 RegionSelection rs = get_regions_from_selection_and_entered ();
3025 if (!_session || rs.empty()) {
3029 framepos_t const end = _session->current_end_frame ();
3031 begin_reversible_command (Operations::region_fill);
3033 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3035 boost::shared_ptr<Region> region ((*i)->region());
3037 boost::shared_ptr<Playlist> pl = region->playlist();
3039 if (end <= region->last_frame()) {
3043 double times = (double) (end - region->last_frame()) / (double) region->length();
3049 pl->clear_changes ();
3050 pl->add_region (RegionFactory::create (region, true), region->last_frame(), times);
3051 _session->add_command (new StatefulDiffCommand (pl));
3054 commit_reversible_command ();
3058 Editor::region_fill_selection ()
3060 if (clicked_routeview == 0 || !clicked_routeview->is_audio_track()) {
3064 if (selection->time.empty()) {
3068 boost::shared_ptr<Region> region = _regions->get_single_selection ();
3073 framepos_t start = selection->time[clicked_selection].start;
3074 framepos_t end = selection->time[clicked_selection].end;
3076 boost::shared_ptr<Playlist> playlist;
3078 if (selection->tracks.empty()) {
3082 framepos_t selection_length = end - start;
3083 float times = (float)selection_length / region->length();
3085 begin_reversible_command (Operations::fill_selection);
3087 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
3089 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
3091 if ((playlist = (*i)->playlist()) == 0) {
3095 playlist->clear_changes ();
3096 playlist->add_region (RegionFactory::create (region, true), start, times);
3097 _session->add_command (new StatefulDiffCommand (playlist));
3100 commit_reversible_command ();
3104 Editor::set_region_sync_position ()
3106 set_sync_point (get_preferred_edit_position (), get_regions_from_selection_and_edit_point ());
3110 Editor::set_sync_point (framepos_t where, const RegionSelection& rs)
3112 bool in_command = false;
3114 for (RegionSelection::const_iterator r = rs.begin(); r != rs.end(); ++r) {
3116 if (!(*r)->region()->covers (where)) {
3120 boost::shared_ptr<Region> region ((*r)->region());
3123 begin_reversible_command (_("set sync point"));
3127 region->clear_changes ();
3128 region->set_sync_position (where);
3129 _session->add_command(new StatefulDiffCommand (region));
3133 commit_reversible_command ();
3137 /** Remove the sync positions of the selection */
3139 Editor::remove_region_sync ()
3141 RegionSelection rs = get_regions_from_selection_and_entered ();
3147 begin_reversible_command (_("remove region sync"));
3149 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3151 (*i)->region()->clear_changes ();
3152 (*i)->region()->clear_sync_position ();
3153 _session->add_command(new StatefulDiffCommand ((*i)->region()));
3156 commit_reversible_command ();
3160 Editor::naturalize_region ()
3162 RegionSelection rs = get_regions_from_selection_and_entered ();
3168 if (rs.size() > 1) {
3169 begin_reversible_command (_("move regions to original position"));
3171 begin_reversible_command (_("move region to original position"));
3174 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3175 (*i)->region()->clear_changes ();
3176 (*i)->region()->move_to_natural_position ();
3177 _session->add_command (new StatefulDiffCommand ((*i)->region()));
3180 commit_reversible_command ();
3184 Editor::align_regions (RegionPoint what)
3186 RegionSelection const rs = get_regions_from_selection_and_edit_point ();
3192 begin_reversible_command (_("align selection"));
3194 framepos_t const position = get_preferred_edit_position ();
3196 for (RegionSelection::const_iterator i = rs.begin(); i != rs.end(); ++i) {
3197 align_region_internal ((*i)->region(), what, position);
3200 commit_reversible_command ();
3203 struct RegionSortByTime {
3204 bool operator() (const RegionView* a, const RegionView* b) {
3205 return a->region()->position() < b->region()->position();
3210 Editor::align_regions_relative (RegionPoint point)
3212 RegionSelection const rs = get_regions_from_selection_and_edit_point ();
3218 framepos_t const position = get_preferred_edit_position ();
3220 framepos_t distance = 0;
3224 list<RegionView*> sorted;
3225 rs.by_position (sorted);
3227 boost::shared_ptr<Region> r ((*sorted.begin())->region());
3232 if (position > r->position()) {
3233 distance = position - r->position();
3235 distance = r->position() - position;
3241 if (position > r->last_frame()) {
3242 distance = position - r->last_frame();
3243 pos = r->position() + distance;
3245 distance = r->last_frame() - position;
3246 pos = r->position() - distance;
3252 pos = r->adjust_to_sync (position);
3253 if (pos > r->position()) {
3254 distance = pos - r->position();
3256 distance = r->position() - pos;
3262 if (pos == r->position()) {
3266 begin_reversible_command (_("align selection (relative)"));
3268 /* move first one specially */
3270 r->clear_changes ();
3271 r->set_position (pos);
3272 _session->add_command(new StatefulDiffCommand (r));
3274 /* move rest by the same amount */
3278 for (list<RegionView*>::iterator i = sorted.begin(); i != sorted.end(); ++i) {
3280 boost::shared_ptr<Region> region ((*i)->region());
3282 region->clear_changes ();
3285 region->set_position (region->position() + distance);
3287 region->set_position (region->position() - distance);
3290 _session->add_command(new StatefulDiffCommand (region));
3294 commit_reversible_command ();
3298 Editor::align_region (boost::shared_ptr<Region> region, RegionPoint point, framepos_t position)
3300 begin_reversible_command (_("align region"));
3301 align_region_internal (region, point, position);
3302 commit_reversible_command ();
3306 Editor::align_region_internal (boost::shared_ptr<Region> region, RegionPoint point, framepos_t position)
3308 region->clear_changes ();
3312 region->set_position (region->adjust_to_sync (position));
3316 if (position > region->length()) {
3317 region->set_position (position - region->length());
3322 region->set_position (position);
3326 _session->add_command(new StatefulDiffCommand (region));
3330 Editor::trim_region_front ()
3336 Editor::trim_region_back ()
3338 trim_region (false);
3342 Editor::trim_region (bool front)
3344 framepos_t where = get_preferred_edit_position();
3345 RegionSelection rs = get_regions_from_selection_and_edit_point ();
3351 begin_reversible_command (front ? _("trim front") : _("trim back"));
3353 for (list<RegionView*>::const_iterator i = rs.by_layer().begin(); i != rs.by_layer().end(); ++i) {
3354 if (!(*i)->region()->locked()) {
3356 (*i)->region()->clear_changes ();
3359 (*i)->region()->trim_front (where);
3360 maybe_locate_with_edit_preroll ( where );
3362 (*i)->region()->trim_end (where);
3363 maybe_locate_with_edit_preroll ( where );
3366 _session->add_command (new StatefulDiffCommand ((*i)->region()));
3370 commit_reversible_command ();
3373 /** Trim the end of the selected regions to the position of the edit cursor */
3375 Editor::trim_region_to_loop ()
3377 Location* loc = _session->locations()->auto_loop_location();
3381 trim_region_to_location (*loc, _("trim to loop"));
3385 Editor::trim_region_to_punch ()
3387 Location* loc = _session->locations()->auto_punch_location();
3391 trim_region_to_location (*loc, _("trim to punch"));
3395 Editor::trim_region_to_location (const Location& loc, const char* str)
3397 RegionSelection rs = get_regions_from_selection_and_entered ();
3399 begin_reversible_command (str);
3401 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
3402 RegionView* rv = (*x);
3404 /* require region to span proposed trim */
3405 switch (rv->region()->coverage (loc.start(), loc.end())) {
3406 case Evoral::OverlapInternal:
3412 RouteTimeAxisView* tav = dynamic_cast<RouteTimeAxisView*> (&rv->get_time_axis_view());
3421 if (tav->track() != 0) {
3422 speed = tav->track()->speed();
3425 start = session_frame_to_track_frame (loc.start(), speed);
3426 end = session_frame_to_track_frame (loc.end(), speed);
3428 rv->region()->clear_changes ();
3429 rv->region()->trim_to (start, (end - start));
3430 _session->add_command(new StatefulDiffCommand (rv->region()));
3433 commit_reversible_command ();
3437 Editor::trim_region_to_previous_region_end ()
3439 return trim_to_region(false);
3443 Editor::trim_region_to_next_region_start ()
3445 return trim_to_region(true);
3449 Editor::trim_to_region(bool forward)
3451 RegionSelection rs = get_regions_from_selection_and_entered ();
3453 begin_reversible_command (_("trim to region"));
3455 boost::shared_ptr<Region> next_region;
3457 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
3459 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*x);
3465 AudioTimeAxisView* atav = dynamic_cast<AudioTimeAxisView*> (&arv->get_time_axis_view());
3473 if (atav->track() != 0) {
3474 speed = atav->track()->speed();
3478 boost::shared_ptr<Region> region = arv->region();
3479 boost::shared_ptr<Playlist> playlist (region->playlist());
3481 region->clear_changes ();
3485 next_region = playlist->find_next_region (region->first_frame(), Start, 1);
3491 region->trim_end((framepos_t) ( (next_region->first_frame() - 1) * speed));
3492 arv->region_changed (PropertyChange (ARDOUR::Properties::length));
3496 next_region = playlist->find_next_region (region->first_frame(), Start, 0);
3502 region->trim_front((framepos_t) ((next_region->last_frame() + 1) * speed));
3504 arv->region_changed (ARDOUR::bounds_change);
3507 _session->add_command(new StatefulDiffCommand (region));
3510 commit_reversible_command ();
3514 Editor::unfreeze_route ()
3516 if (clicked_routeview == 0 || !clicked_routeview->is_track()) {
3520 clicked_routeview->track()->unfreeze ();
3524 Editor::_freeze_thread (void* arg)
3526 return static_cast<Editor*>(arg)->freeze_thread ();
3530 Editor::freeze_thread ()
3532 /* create event pool because we may need to talk to the session */
3533 SessionEvent::create_per_thread_pool ("freeze events", 64);
3534 /* create per-thread buffers for process() tree to use */
3535 clicked_routeview->audio_track()->freeze_me (*current_interthread_info);
3536 current_interthread_info->done = true;
3541 Editor::freeze_route ()
3547 /* stop transport before we start. this is important */
3549 _session->request_transport_speed (0.0);
3551 /* wait for just a little while, because the above call is asynchronous */
3553 Glib::usleep (250000);
3555 if (clicked_routeview == 0 || !clicked_routeview->is_audio_track()) {
3559 if (!clicked_routeview->track()->bounceable (clicked_routeview->track()->main_outs(), true)) {
3561 _("This track/bus cannot be frozen because the signal adds or loses channels before reaching the outputs.\n"
3562 "This is typically caused by plugins that generate stereo output from mono input or vice versa.")
3564 d.set_title (_("Cannot freeze"));
3569 if (clicked_routeview->track()->has_external_redirects()) {
3570 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"
3571 "Freezing will only process the signal as far as the first send/insert/return."),
3572 clicked_routeview->track()->name()), true, MESSAGE_INFO, BUTTONS_NONE, true);
3574 d.add_button (_("Freeze anyway"), Gtk::RESPONSE_OK);
3575 d.add_button (_("Don't freeze"), Gtk::RESPONSE_CANCEL);
3576 d.set_title (_("Freeze Limits"));
3578 int response = d.run ();
3581 case Gtk::RESPONSE_CANCEL:
3588 InterThreadInfo itt;
3589 current_interthread_info = &itt;
3591 InterthreadProgressWindow ipw (current_interthread_info, _("Freeze"), _("Cancel Freeze"));
3593 pthread_create_and_store (X_("freezer"), &itt.thread, _freeze_thread, this);
3595 set_canvas_cursor (_cursors->wait);
3597 while (!itt.done && !itt.cancel) {
3598 gtk_main_iteration ();
3601 current_interthread_info = 0;
3602 set_canvas_cursor (current_canvas_cursor);
3606 Editor::bounce_range_selection (bool replace, bool enable_processing)
3608 if (selection->time.empty()) {
3612 TrackSelection views = selection->tracks;
3614 for (TrackViewList::iterator i = views.begin(); i != views.end(); ++i) {
3616 if (enable_processing) {
3618 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*i);
3620 if (rtv && rtv->track() && replace && enable_processing && !rtv->track()->bounceable (rtv->track()->main_outs(), false)) {
3622 _("You can't perform this operation because the processing of the signal "
3623 "will cause one or more of the tracks to end up with a region with more channels than this track has inputs.\n\n"
3624 "You can do this without processing, which is a different operation.")
3626 d.set_title (_("Cannot bounce"));
3633 framepos_t start = selection->time[clicked_selection].start;
3634 framepos_t end = selection->time[clicked_selection].end;
3635 framepos_t cnt = end - start + 1;
3637 begin_reversible_command (_("bounce range"));
3639 for (TrackViewList::iterator i = views.begin(); i != views.end(); ++i) {
3641 RouteTimeAxisView* rtv;
3643 if ((rtv = dynamic_cast<RouteTimeAxisView*> (*i)) == 0) {
3647 boost::shared_ptr<Playlist> playlist;
3649 if ((playlist = rtv->playlist()) == 0) {
3653 InterThreadInfo itt;
3655 playlist->clear_changes ();
3656 playlist->clear_owned_changes ();
3658 boost::shared_ptr<Region> r;
3660 if (enable_processing) {
3661 r = rtv->track()->bounce_range (start, start+cnt, itt, rtv->track()->main_outs(), false);
3663 r = rtv->track()->bounce_range (start, start+cnt, itt, boost::shared_ptr<Processor>(), false);
3671 list<AudioRange> ranges;
3672 ranges.push_back (AudioRange (start, start+cnt, 0));
3673 playlist->cut (ranges); // discard result
3674 playlist->add_region (r, start);
3677 vector<Command*> cmds;
3678 playlist->rdiff (cmds);
3679 _session->add_commands (cmds);
3681 _session->add_command (new StatefulDiffCommand (playlist));
3684 commit_reversible_command ();
3687 /** Delete selected regions, automation points or a time range */
3694 /** Cut selected regions, automation points or a time range */
3701 /** Copy selected regions, automation points or a time range */
3709 /** @return true if a Cut, Copy or Clear is possible */
3711 Editor::can_cut_copy () const
3713 switch (effective_mouse_mode()) {
3716 if (!selection->regions.empty() || !selection->points.empty()) {
3722 if (!selection->time.empty()) {
3735 /** Cut, copy or clear selected regions, automation points or a time range.
3736 * @param op Operation (Cut, Copy or Clear)
3739 Editor::cut_copy (CutCopyOp op)
3741 /* only cancel selection if cut/copy is successful.*/
3747 opname = _("delete");
3756 opname = _("clear");
3760 /* if we're deleting something, and the mouse is still pressed,
3761 the thing we started a drag for will be gone when we release
3762 the mouse button(s). avoid this. see part 2 at the end of
3766 if (op == Delete || op == Cut || op == Clear) {
3767 if (_drags->active ()) {
3772 if ( op != Clear ) //"Delete" doesn't change copy/paste buf
3773 cut_buffer->clear ();
3775 if (entered_marker) {
3777 /* cut/delete op while pointing at a marker */
3780 Location* loc = find_location_from_marker (entered_marker, ignored);
3782 if (_session && loc) {
3783 Glib::signal_idle().connect (sigc::bind (sigc::mem_fun(*this, &Editor::really_remove_marker), loc));
3790 if (internal_editing()) {
3792 switch (effective_mouse_mode()) {
3795 begin_reversible_command (opname + ' ' + X_("MIDI"));
3797 commit_reversible_command ();
3806 bool did_edit = false;
3808 switch (effective_mouse_mode()) {
3810 if (!selection->points.empty()) {
3811 begin_reversible_command (opname + _(" points"));
3813 cut_copy_points (op);
3814 if (op == Cut || op == Delete) {
3815 selection->clear_points ();
3822 if (!selection->regions.empty() || !selection->points.empty()) {
3826 if (selection->regions.empty()) {
3827 thing_name = _("points");
3828 } else if (selection->points.empty()) {
3829 thing_name = _("regions");
3831 thing_name = _("objects");
3834 begin_reversible_command (opname + ' ' + thing_name);
3837 if (!selection->regions.empty()) {
3838 cut_copy_regions (op, selection->regions);
3840 if (op == Cut || op == Delete) {
3841 selection->clear_regions ();
3845 if (!selection->points.empty()) {
3846 cut_copy_points (op);
3848 if (op == Cut || op == Delete) {
3849 selection->clear_points ();
3856 if (selection->time.empty()) {
3857 framepos_t start, end;
3858 /* no time selection, see if we can get an edit range
3861 if (get_edit_op_range (start, end)) {
3862 selection->set (start, end);
3865 if (!selection->time.empty()) {
3866 begin_reversible_command (opname + _(" range"));
3869 cut_copy_ranges (op);
3871 if (op == Cut || op == Delete) {
3872 selection->clear_time ();
3882 commit_reversible_command ();
3885 if (op == Delete || op == Cut || op == Clear) {
3890 struct AutomationRecord {
3891 AutomationRecord () : state (0) {}
3892 AutomationRecord (XMLNode* s) : state (s) {}
3894 XMLNode* state; ///< state before any operation
3895 boost::shared_ptr<Evoral::ControlList> copy; ///< copied events for the cut buffer
3898 /** Cut, copy or clear selected automation points.
3899 * @param op Operation (Cut, Copy or Clear)
3902 Editor::cut_copy_points (CutCopyOp op)
3904 if (selection->points.empty ()) {
3908 /* XXX: not ideal, as there may be more than one track involved in the point selection */
3909 _last_cut_copy_source_track = &selection->points.front()->line().trackview;
3911 /* Keep a record of the AutomationLists that we end up using in this operation */
3912 typedef std::map<boost::shared_ptr<AutomationList>, AutomationRecord> Lists;
3915 /* Go through all selected points, making an AutomationRecord for each distinct AutomationList */
3916 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
3917 boost::shared_ptr<AutomationList> al = (*i)->line().the_list();
3918 if (lists.find (al) == lists.end ()) {
3919 /* We haven't seen this list yet, so make a record for it. This includes
3920 taking a copy of its current state, in case this is needed for undo later.
3922 lists[al] = AutomationRecord (&al->get_state ());
3926 if (op == Cut || op == Copy) {
3927 /* This operation will involve putting things in the cut buffer, so create an empty
3928 ControlList for each of our source lists to put the cut buffer data in.
3930 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
3931 i->second.copy = i->first->create (i->first->parameter ());
3934 /* Add all selected points to the relevant copy ControlLists */
3935 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
3936 boost::shared_ptr<AutomationList> al = (*i)->line().the_list();
3937 AutomationList::const_iterator j = (*i)->model ();
3938 lists[al].copy->add ((*j)->when, (*j)->value);
3941 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
3942 /* Correct this copy list so that it starts at time 0 */
3943 double const start = i->second.copy->front()->when;
3944 for (AutomationList::iterator j = i->second.copy->begin(); j != i->second.copy->end(); ++j) {
3945 (*j)->when -= start;
3948 /* And add it to the cut buffer */
3949 cut_buffer->add (i->second.copy);
3953 if (op == Delete || op == Cut) {
3954 /* This operation needs to remove things from the main AutomationList, so do that now */
3956 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
3957 i->first->freeze ();
3960 /* Remove each selected point from its AutomationList */
3961 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
3962 boost::shared_ptr<AutomationList> al = (*i)->line().the_list();
3963 al->erase ((*i)->model ());
3966 /* Thaw the lists and add undo records for them */
3967 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
3968 boost::shared_ptr<AutomationList> al = i->first;
3970 _session->add_command (new MementoCommand<AutomationList> (*al.get(), i->second.state, &(al->get_state ())));
3975 /** Cut, copy or clear selected automation points.
3976 * @param op Operation (Cut, Copy or Clear)
3979 Editor::cut_copy_midi (CutCopyOp op)
3981 for (MidiRegionSelection::iterator i = selection->midi_regions.begin(); i != selection->midi_regions.end(); ++i) {
3982 MidiRegionView* mrv = *i;
3983 mrv->cut_copy_clear (op);
3989 struct lt_playlist {
3990 bool operator () (const PlaylistState& a, const PlaylistState& b) {
3991 return a.playlist < b.playlist;
3995 struct PlaylistMapping {
3997 boost::shared_ptr<Playlist> pl;
3999 PlaylistMapping (TimeAxisView* tvp) : tv (tvp) {}
4002 /** Remove `clicked_regionview' */
4004 Editor::remove_clicked_region ()
4006 if (clicked_routeview == 0 || clicked_regionview == 0) {
4010 boost::shared_ptr<Playlist> playlist = clicked_routeview->playlist();
4012 begin_reversible_command (_("remove region"));
4013 playlist->clear_changes ();
4014 playlist->clear_owned_changes ();
4015 playlist->remove_region (clicked_regionview->region());
4017 /* We might have removed regions, which alters other regions' layering_index,
4018 so we need to do a recursive diff here.
4020 vector<Command*> cmds;
4021 playlist->rdiff (cmds);
4022 _session->add_commands (cmds);
4024 _session->add_command(new StatefulDiffCommand (playlist));
4025 commit_reversible_command ();
4029 /** Remove the selected regions */
4031 Editor::remove_selected_regions ()
4033 RegionSelection rs = get_regions_from_selection_and_entered ();
4035 if (!_session || rs.empty()) {
4039 begin_reversible_command (_("remove region"));
4041 list<boost::shared_ptr<Region> > regions_to_remove;
4043 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
4044 // we can't just remove the region(s) in this loop because
4045 // this removes them from the RegionSelection, and they thus
4046 // disappear from underneath the iterator, and the ++i above
4047 // SEGVs in a puzzling fashion.
4049 // so, first iterate over the regions to be removed from rs and
4050 // add them to the regions_to_remove list, and then
4051 // iterate over the list to actually remove them.
4053 regions_to_remove.push_back ((*i)->region());
4056 vector<boost::shared_ptr<Playlist> > playlists;
4058 for (list<boost::shared_ptr<Region> >::iterator rl = regions_to_remove.begin(); rl != regions_to_remove.end(); ++rl) {
4060 boost::shared_ptr<Playlist> playlist = (*rl)->playlist();
4063 // is this check necessary?
4067 /* get_regions_from_selection_and_entered() guarantees that
4068 the playlists involved are unique, so there is no need
4072 playlists.push_back (playlist);
4074 playlist->clear_changes ();
4075 playlist->clear_owned_changes ();
4076 playlist->freeze ();
4077 playlist->remove_region (*rl);
4080 vector<boost::shared_ptr<Playlist> >::iterator pl;
4082 for (pl = playlists.begin(); pl != playlists.end(); ++pl) {
4085 /* We might have removed regions, which alters other regions' layering_index,
4086 so we need to do a recursive diff here.
4088 vector<Command*> cmds;
4089 (*pl)->rdiff (cmds);
4090 _session->add_commands (cmds);
4092 _session->add_command(new StatefulDiffCommand (*pl));
4095 commit_reversible_command ();
4098 /** Cut, copy or clear selected regions.
4099 * @param op Operation (Cut, Copy or Clear)
4102 Editor::cut_copy_regions (CutCopyOp op, RegionSelection& rs)
4104 /* we can't use a std::map here because the ordering is important, and we can't trivially sort
4105 a map when we want ordered access to both elements. i think.
4108 vector<PlaylistMapping> pmap;
4110 framepos_t first_position = max_framepos;
4112 typedef set<boost::shared_ptr<Playlist> > FreezeList;
4113 FreezeList freezelist;
4115 /* get ordering correct before we cut/copy */
4117 rs.sort_by_position_and_track ();
4119 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
4121 first_position = min ((framepos_t) (*x)->region()->position(), first_position);
4123 if (op == Cut || op == Clear || op == Delete) {
4124 boost::shared_ptr<Playlist> pl = (*x)->region()->playlist();
4127 FreezeList::iterator fl;
4129 // only take state if this is a new playlist.
4130 for (fl = freezelist.begin(); fl != freezelist.end(); ++fl) {
4136 if (fl == freezelist.end()) {
4137 pl->clear_changes();
4138 pl->clear_owned_changes ();
4140 freezelist.insert (pl);
4145 TimeAxisView* tv = &(*x)->get_time_axis_view();
4146 vector<PlaylistMapping>::iterator z;
4148 for (z = pmap.begin(); z != pmap.end(); ++z) {
4149 if ((*z).tv == tv) {
4154 if (z == pmap.end()) {
4155 pmap.push_back (PlaylistMapping (tv));
4159 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ) {
4161 boost::shared_ptr<Playlist> pl = (*x)->region()->playlist();
4164 /* region not yet associated with a playlist (e.g. unfinished
4171 TimeAxisView& tv = (*x)->get_time_axis_view();
4172 boost::shared_ptr<Playlist> npl;
4173 RegionSelection::iterator tmp;
4180 vector<PlaylistMapping>::iterator z;
4182 for (z = pmap.begin(); z != pmap.end(); ++z) {
4183 if ((*z).tv == &tv) {
4188 assert (z != pmap.end());
4191 npl = PlaylistFactory::create (pl->data_type(), *_session, "cutlist", true);
4199 boost::shared_ptr<Region> r = (*x)->region();
4200 boost::shared_ptr<Region> _xx;
4206 pl->remove_region (r);
4210 _xx = RegionFactory::create (r);
4211 npl->add_region (_xx, r->position() - first_position);
4212 pl->remove_region (r);
4216 /* copy region before adding, so we're not putting same object into two different playlists */
4217 npl->add_region (RegionFactory::create (r), r->position() - first_position);
4221 pl->remove_region (r);
4230 list<boost::shared_ptr<Playlist> > foo;
4232 /* the pmap is in the same order as the tracks in which selected regions occured */
4234 for (vector<PlaylistMapping>::iterator i = pmap.begin(); i != pmap.end(); ++i) {
4237 foo.push_back ((*i).pl);
4242 cut_buffer->set (foo);
4246 _last_cut_copy_source_track = 0;
4248 _last_cut_copy_source_track = pmap.front().tv;
4252 for (FreezeList::iterator pl = freezelist.begin(); pl != freezelist.end(); ++pl) {
4255 /* We might have removed regions, which alters other regions' layering_index,
4256 so we need to do a recursive diff here.
4258 vector<Command*> cmds;
4259 (*pl)->rdiff (cmds);
4260 _session->add_commands (cmds);
4262 _session->add_command (new StatefulDiffCommand (*pl));
4267 Editor::cut_copy_ranges (CutCopyOp op)
4269 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4271 /* Sort the track selection now, so that it if is used, the playlists
4272 selected by the calls below to cut_copy_clear are in the order that
4273 their tracks appear in the editor. This makes things like paste
4274 of ranges work properly.
4277 sort_track_selection (ts);
4280 if (!entered_track) {
4283 ts.push_back (entered_track);
4286 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4287 (*i)->cut_copy_clear (*selection, op);
4292 Editor::paste (float times, bool from_context)
4294 DEBUG_TRACE (DEBUG::CutNPaste, "paste to preferred edit pos\n");
4296 paste_internal (get_preferred_edit_position (false, from_context), times);
4300 Editor::mouse_paste ()
4305 if (!mouse_frame (where, ignored)) {
4310 paste_internal (where, 1);
4314 Editor::paste_internal (framepos_t position, float times)
4316 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("apparent paste position is %1\n", position));
4318 if (internal_editing()) {
4319 if (cut_buffer->midi_notes.empty()) {
4323 if (cut_buffer->empty()) {
4328 if (position == max_framepos) {
4329 position = get_preferred_edit_position();
4330 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("preferred edit position is %1\n", position));
4334 TrackViewList::iterator i;
4337 /* get everything in the correct order */
4339 if (_edit_point == Editing::EditAtMouse && entered_track) {
4340 /* With the mouse edit point, paste onto the track under the mouse */
4341 ts.push_back (entered_track);
4342 } else if (!selection->tracks.empty()) {
4343 /* Otherwise, if there are some selected tracks, paste to them */
4344 ts = selection->tracks.filter_to_unique_playlists ();
4345 sort_track_selection (ts);
4346 } else if (_last_cut_copy_source_track) {
4347 /* Otherwise paste to the track that the cut/copy came from;
4348 see discussion in mantis #3333.
4350 ts.push_back (_last_cut_copy_source_track);
4353 if (internal_editing ()) {
4355 /* undo/redo is handled by individual tracks/regions */
4357 for (nth = 0, i = ts.begin(); i != ts.end(); ++i, ++nth) {
4360 RegionSelection::iterator r;
4361 MidiNoteSelection::iterator cb;
4363 get_regions_at (rs, position, ts);
4365 for (cb = cut_buffer->midi_notes.begin(), r = rs.begin();
4366 cb != cut_buffer->midi_notes.end() && r != rs.end(); ++r) {
4367 MidiRegionView* mrv = dynamic_cast<MidiRegionView*> (*r);
4369 mrv->paste (position, times, **cb);
4377 /* we do redo (do you do voodoo?) */
4379 begin_reversible_command (Operations::paste);
4381 for (nth = 0, i = ts.begin(); i != ts.end(); ++i, ++nth) {
4382 (*i)->paste (position, times, *cut_buffer, nth);
4385 commit_reversible_command ();
4390 Editor::duplicate_some_regions (RegionSelection& regions, float times)
4392 boost::shared_ptr<Playlist> playlist;
4393 RegionSelection sel = regions; // clear (below) may clear the argument list if its the current region selection
4394 RegionSelection foo;
4396 framepos_t const start_frame = regions.start ();
4397 framepos_t const end_frame = regions.end_frame ();
4399 begin_reversible_command (Operations::duplicate_region);
4401 selection->clear_regions ();
4403 for (RegionSelection::iterator i = sel.begin(); i != sel.end(); ++i) {
4405 boost::shared_ptr<Region> r ((*i)->region());
4407 TimeAxisView& tv = (*i)->get_time_axis_view();
4408 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (&tv);
4409 latest_regionviews.clear ();
4410 sigc::connection c = rtv->view()->RegionViewAdded.connect (sigc::mem_fun(*this, &Editor::collect_new_region_view));
4412 playlist = (*i)->region()->playlist();
4413 playlist->clear_changes ();
4414 playlist->duplicate (r, end_frame + (r->first_frame() - start_frame), times);
4415 _session->add_command(new StatefulDiffCommand (playlist));
4419 foo.insert (foo.end(), latest_regionviews.begin(), latest_regionviews.end());
4422 commit_reversible_command ();
4425 selection->set (foo);
4430 Editor::duplicate_selection (float times)
4432 if (selection->time.empty() || selection->tracks.empty()) {
4436 boost::shared_ptr<Playlist> playlist;
4437 vector<boost::shared_ptr<Region> > new_regions;
4438 vector<boost::shared_ptr<Region> >::iterator ri;
4440 create_region_from_selection (new_regions);
4442 if (new_regions.empty()) {
4446 begin_reversible_command (_("duplicate selection"));
4448 ri = new_regions.begin();
4450 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4452 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4453 if ((playlist = (*i)->playlist()) == 0) {
4456 playlist->clear_changes ();
4457 playlist->duplicate (*ri, selection->time[clicked_selection].end, times);
4458 _session->add_command (new StatefulDiffCommand (playlist));
4461 if (ri == new_regions.end()) {
4466 commit_reversible_command ();
4469 /** Reset all selected points to the relevant default value */
4471 Editor::reset_point_selection ()
4473 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
4474 ARDOUR::AutomationList::iterator j = (*i)->model ();
4475 (*j)->value = (*i)->line().the_list()->default_value ();
4480 Editor::center_playhead ()
4482 float const page = _visible_canvas_width * samples_per_pixel;
4483 center_screen_internal (playhead_cursor->current_frame (), page);
4487 Editor::center_edit_point ()
4489 float const page = _visible_canvas_width * samples_per_pixel;
4490 center_screen_internal (get_preferred_edit_position(), page);
4493 /** Caller must begin and commit a reversible command */
4495 Editor::clear_playlist (boost::shared_ptr<Playlist> playlist)
4497 playlist->clear_changes ();
4499 _session->add_command (new StatefulDiffCommand (playlist));
4503 Editor::nudge_track (bool use_edit, bool forwards)
4505 boost::shared_ptr<Playlist> playlist;
4506 framepos_t distance;
4507 framepos_t next_distance;
4511 start = get_preferred_edit_position();
4516 if ((distance = get_nudge_distance (start, next_distance)) == 0) {
4520 if (selection->tracks.empty()) {
4524 begin_reversible_command (_("nudge track"));
4526 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4528 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4530 if ((playlist = (*i)->playlist()) == 0) {
4534 playlist->clear_changes ();
4535 playlist->clear_owned_changes ();
4537 playlist->nudge_after (start, distance, forwards);
4539 vector<Command*> cmds;
4541 playlist->rdiff (cmds);
4542 _session->add_commands (cmds);
4544 _session->add_command (new StatefulDiffCommand (playlist));
4547 commit_reversible_command ();
4551 Editor::remove_last_capture ()
4553 vector<string> choices;
4560 if (Config->get_verify_remove_last_capture()) {
4561 prompt = _("Do you really want to destroy the last capture?"
4562 "\n(This is destructive and cannot be undone)");
4564 choices.push_back (_("No, do nothing."));
4565 choices.push_back (_("Yes, destroy it."));
4567 Gtkmm2ext::Choice prompter (_("Destroy last capture"), prompt, choices);
4569 if (prompter.run () == 1) {
4570 _session->remove_last_capture ();
4571 _regions->redisplay ();
4575 _session->remove_last_capture();
4576 _regions->redisplay ();
4581 Editor::normalize_region ()
4587 RegionSelection rs = get_regions_from_selection_and_entered ();
4593 NormalizeDialog dialog (rs.size() > 1);
4595 if (dialog.run () == RESPONSE_CANCEL) {
4599 set_canvas_cursor (_cursors->wait);
4602 /* XXX: should really only count audio regions here */
4603 int const regions = rs.size ();
4605 /* Make a list of the selected audio regions' maximum amplitudes, and also
4606 obtain the maximum amplitude of them all.
4608 list<double> max_amps;
4610 for (RegionSelection::const_iterator i = rs.begin(); i != rs.end(); ++i) {
4611 AudioRegionView const * arv = dynamic_cast<AudioRegionView const *> (*i);
4613 dialog.descend (1.0 / regions);
4614 double const a = arv->audio_region()->maximum_amplitude (&dialog);
4617 /* the user cancelled the operation */
4618 set_canvas_cursor (current_canvas_cursor);
4622 max_amps.push_back (a);
4623 max_amp = max (max_amp, a);
4628 begin_reversible_command (_("normalize"));
4630 list<double>::const_iterator a = max_amps.begin ();
4632 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
4633 AudioRegionView* const arv = dynamic_cast<AudioRegionView*> (*r);
4638 arv->region()->clear_changes ();
4640 double const amp = dialog.normalize_individually() ? *a : max_amp;
4642 arv->audio_region()->normalize (amp, dialog.target ());
4643 _session->add_command (new StatefulDiffCommand (arv->region()));
4648 commit_reversible_command ();
4649 set_canvas_cursor (current_canvas_cursor);
4654 Editor::reset_region_scale_amplitude ()
4660 RegionSelection rs = get_regions_from_selection_and_entered ();
4666 begin_reversible_command ("reset gain");
4668 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
4669 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
4672 arv->region()->clear_changes ();
4673 arv->audio_region()->set_scale_amplitude (1.0f);
4674 _session->add_command (new StatefulDiffCommand (arv->region()));
4677 commit_reversible_command ();
4681 Editor::adjust_region_gain (bool up)
4683 RegionSelection rs = get_regions_from_selection_and_entered ();
4685 if (!_session || rs.empty()) {
4689 begin_reversible_command ("adjust region gain");
4691 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
4692 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
4697 arv->region()->clear_changes ();
4699 double dB = accurate_coefficient_to_dB (arv->audio_region()->scale_amplitude ());
4707 arv->audio_region()->set_scale_amplitude (dB_to_coefficient (dB));
4708 _session->add_command (new StatefulDiffCommand (arv->region()));
4711 commit_reversible_command ();
4716 Editor::reverse_region ()
4722 Reverse rev (*_session);
4723 apply_filter (rev, _("reverse regions"));
4727 Editor::strip_region_silence ()
4733 RegionSelection rs = get_regions_from_selection_and_entered ();
4739 std::list<RegionView*> audio_only;
4741 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
4742 AudioRegionView* const arv = dynamic_cast<AudioRegionView*> (*i);
4744 audio_only.push_back (arv);
4748 StripSilenceDialog d (_session, audio_only);
4749 int const r = d.run ();
4753 if (r == Gtk::RESPONSE_OK) {
4754 ARDOUR::AudioIntervalMap silences;
4755 d.silences (silences);
4756 StripSilence s (*_session, silences, d.fade_length());
4757 apply_filter (s, _("strip silence"), &d);
4762 Editor::apply_midi_note_edit_op_to_region (MidiOperator& op, MidiRegionView& mrv)
4764 Evoral::Sequence<Evoral::MusicalTime>::Notes selected;
4765 mrv.selection_as_notelist (selected, true);
4767 vector<Evoral::Sequence<Evoral::MusicalTime>::Notes> v;
4768 v.push_back (selected);
4770 framepos_t pos_frames = mrv.midi_region()->position() - mrv.midi_region()->start();
4771 double pos_beats = _session->tempo_map().framewalk_to_beats(0, pos_frames);
4773 return op (mrv.midi_region()->model(), pos_beats, v);
4777 Editor::apply_midi_note_edit_op (MidiOperator& op)
4781 RegionSelection rs = get_regions_from_selection_and_entered ();
4787 begin_reversible_command (op.name ());
4789 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
4790 RegionSelection::iterator tmp = r;
4793 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*r);
4796 cmd = apply_midi_note_edit_op_to_region (op, *mrv);
4799 _session->add_command (cmd);
4806 commit_reversible_command ();
4810 Editor::fork_region ()
4812 RegionSelection rs = get_regions_from_selection_and_entered ();
4818 begin_reversible_command (_("Fork Region(s)"));
4820 set_canvas_cursor (_cursors->wait);
4823 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
4824 RegionSelection::iterator tmp = r;
4827 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*>(*r);
4831 boost::shared_ptr<Playlist> playlist = mrv->region()->playlist();
4832 boost::shared_ptr<MidiSource> new_source = _session->create_midi_source_by_stealing_name (mrv->midi_view()->track());
4833 boost::shared_ptr<MidiRegion> newregion = mrv->midi_region()->clone (new_source);
4835 playlist->clear_changes ();
4836 playlist->replace_region (mrv->region(), newregion, mrv->region()->position());
4837 _session->add_command(new StatefulDiffCommand (playlist));
4839 error << string_compose (_("Could not unlink %1"), mrv->region()->name()) << endmsg;
4846 commit_reversible_command ();
4848 set_canvas_cursor (current_canvas_cursor);
4852 Editor::quantize_region ()
4854 int selected_midi_region_cnt = 0;
4860 RegionSelection rs = get_regions_from_selection_and_entered ();
4866 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
4867 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*r);
4869 selected_midi_region_cnt++;
4873 if (selected_midi_region_cnt == 0) {
4877 QuantizeDialog* qd = new QuantizeDialog (*this);
4880 const int r = qd->run ();
4883 if (r == Gtk::RESPONSE_OK) {
4884 Quantize quant (*_session, qd->snap_start(), qd->snap_end(),
4885 qd->start_grid_size(), qd->end_grid_size(),
4886 qd->strength(), qd->swing(), qd->threshold());
4888 apply_midi_note_edit_op (quant);
4893 Editor::insert_patch_change (bool from_context)
4895 RegionSelection rs = get_regions_from_selection_and_entered ();
4901 const framepos_t p = get_preferred_edit_position (false, from_context);
4903 /* XXX: bit of a hack; use the MIDNAM from the first selected region;
4904 there may be more than one, but the PatchChangeDialog can only offer
4905 one set of patch menus.
4907 MidiRegionView* first = dynamic_cast<MidiRegionView*> (rs.front ());
4909 Evoral::PatchChange<Evoral::MusicalTime> empty (0, 0, 0, 0);
4910 PatchChangeDialog d (0, _session, empty, first->instrument_info(), Gtk::Stock::ADD);
4912 if (d.run() == RESPONSE_CANCEL) {
4916 for (RegionSelection::iterator i = rs.begin (); i != rs.end(); ++i) {
4917 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*i);
4919 if (p >= mrv->region()->first_frame() && p <= mrv->region()->last_frame()) {
4920 mrv->add_patch_change (p - mrv->region()->position(), d.patch ());
4927 Editor::apply_filter (Filter& filter, string command, ProgressReporter* progress)
4929 RegionSelection rs = get_regions_from_selection_and_entered ();
4935 begin_reversible_command (command);
4937 set_canvas_cursor (_cursors->wait);
4941 int const N = rs.size ();
4943 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
4944 RegionSelection::iterator tmp = r;
4947 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
4949 boost::shared_ptr<Playlist> playlist = arv->region()->playlist();
4952 progress->descend (1.0 / N);
4955 if (arv->audio_region()->apply (filter, progress) == 0) {
4957 playlist->clear_changes ();
4958 playlist->clear_owned_changes ();
4960 if (filter.results.empty ()) {
4962 /* no regions returned; remove the old one */
4963 playlist->remove_region (arv->region ());
4967 std::vector<boost::shared_ptr<Region> >::iterator res = filter.results.begin ();
4969 /* first region replaces the old one */
4970 playlist->replace_region (arv->region(), *res, (*res)->position());
4974 while (res != filter.results.end()) {
4975 playlist->add_region (*res, (*res)->position());
4981 /* We might have removed regions, which alters other regions' layering_index,
4982 so we need to do a recursive diff here.
4984 vector<Command*> cmds;
4985 playlist->rdiff (cmds);
4986 _session->add_commands (cmds);
4988 _session->add_command(new StatefulDiffCommand (playlist));
4994 progress->ascend ();
5002 commit_reversible_command ();
5005 set_canvas_cursor (current_canvas_cursor);
5009 Editor::external_edit_region ()
5015 Editor::reset_region_gain_envelopes ()
5017 RegionSelection rs = get_regions_from_selection_and_entered ();
5019 if (!_session || rs.empty()) {
5023 _session->begin_reversible_command (_("reset region gain"));
5025 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5026 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
5028 boost::shared_ptr<AutomationList> alist (arv->audio_region()->envelope());
5029 XMLNode& before (alist->get_state());
5031 arv->audio_region()->set_default_envelope ();
5032 _session->add_command (new MementoCommand<AutomationList>(*arv->audio_region()->envelope().get(), &before, &alist->get_state()));
5036 _session->commit_reversible_command ();
5040 Editor::set_region_gain_visibility (RegionView* rv)
5042 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (rv);
5044 arv->update_envelope_visibility();
5049 Editor::set_gain_envelope_visibility ()
5055 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5056 AudioTimeAxisView* v = dynamic_cast<AudioTimeAxisView*>(*i);
5058 v->audio_view()->foreach_regionview (sigc::mem_fun (this, &Editor::set_region_gain_visibility));
5064 Editor::toggle_gain_envelope_active ()
5066 if (_ignore_region_action) {
5070 RegionSelection rs = get_regions_from_selection_and_entered ();
5072 if (!_session || rs.empty()) {
5076 _session->begin_reversible_command (_("region gain envelope active"));
5078 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5079 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
5081 arv->region()->clear_changes ();
5082 arv->audio_region()->set_envelope_active (!arv->audio_region()->envelope_active());
5083 _session->add_command (new StatefulDiffCommand (arv->region()));
5087 _session->commit_reversible_command ();
5091 Editor::toggle_region_lock ()
5093 if (_ignore_region_action) {
5097 RegionSelection rs = get_regions_from_selection_and_entered ();
5099 if (!_session || rs.empty()) {
5103 _session->begin_reversible_command (_("toggle region lock"));
5105 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5106 (*i)->region()->clear_changes ();
5107 (*i)->region()->set_locked (!(*i)->region()->locked());
5108 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5111 _session->commit_reversible_command ();
5115 Editor::toggle_region_video_lock ()
5117 if (_ignore_region_action) {
5121 RegionSelection rs = get_regions_from_selection_and_entered ();
5123 if (!_session || rs.empty()) {
5127 _session->begin_reversible_command (_("Toggle Video Lock"));
5129 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5130 (*i)->region()->clear_changes ();
5131 (*i)->region()->set_video_locked (!(*i)->region()->video_locked());
5132 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5135 _session->commit_reversible_command ();
5139 Editor::toggle_region_lock_style ()
5141 if (_ignore_region_action) {
5145 RegionSelection rs = get_regions_from_selection_and_entered ();
5147 if (!_session || rs.empty()) {
5151 _session->begin_reversible_command (_("region lock style"));
5153 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5154 (*i)->region()->clear_changes ();
5155 PositionLockStyle const ns = (*i)->region()->position_lock_style() == AudioTime ? MusicTime : AudioTime;
5156 (*i)->region()->set_position_lock_style (ns);
5157 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5160 _session->commit_reversible_command ();
5164 Editor::toggle_opaque_region ()
5166 if (_ignore_region_action) {
5170 RegionSelection rs = get_regions_from_selection_and_entered ();
5172 if (!_session || rs.empty()) {
5176 _session->begin_reversible_command (_("change region opacity"));
5178 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5179 (*i)->region()->clear_changes ();
5180 (*i)->region()->set_opaque (!(*i)->region()->opaque());
5181 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5184 _session->commit_reversible_command ();
5188 Editor::toggle_record_enable ()
5190 bool new_state = false;
5192 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5193 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5196 if (!rtav->is_track())
5200 new_state = !rtav->track()->record_enabled();
5204 rtav->track()->set_record_enabled (new_state, this);
5209 Editor::toggle_solo ()
5211 bool new_state = false;
5213 boost::shared_ptr<RouteList> rl (new RouteList);
5215 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5216 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5223 new_state = !rtav->route()->soloed ();
5227 rl->push_back (rtav->route());
5230 _session->set_solo (rl, new_state, Session::rt_cleanup, true);
5234 Editor::toggle_mute ()
5236 bool new_state = false;
5238 boost::shared_ptr<RouteList> rl (new RouteList);
5240 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5241 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5248 new_state = !rtav->route()->muted();
5252 rl->push_back (rtav->route());
5255 _session->set_mute (rl, new_state, Session::rt_cleanup, true);
5259 Editor::toggle_solo_isolate ()
5264 Editor::set_fade_length (bool in)
5266 RegionSelection rs = get_regions_from_selection_and_entered ();
5272 /* we need a region to measure the offset from the start */
5274 RegionView* rv = rs.front ();
5276 framepos_t pos = get_preferred_edit_position();
5280 if (pos > rv->region()->last_frame() || pos < rv->region()->first_frame()) {
5281 /* edit point is outside the relevant region */
5286 if (pos <= rv->region()->position()) {
5290 len = pos - rv->region()->position();
5291 cmd = _("set fade in length");
5293 if (pos >= rv->region()->last_frame()) {
5297 len = rv->region()->last_frame() - pos;
5298 cmd = _("set fade out length");
5301 begin_reversible_command (cmd);
5303 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5304 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5310 boost::shared_ptr<AutomationList> alist;
5312 alist = tmp->audio_region()->fade_in();
5314 alist = tmp->audio_region()->fade_out();
5317 XMLNode &before = alist->get_state();
5320 tmp->audio_region()->set_fade_in_length (len);
5321 tmp->audio_region()->set_fade_in_active (true);
5323 tmp->audio_region()->set_fade_out_length (len);
5324 tmp->audio_region()->set_fade_out_active (true);
5327 XMLNode &after = alist->get_state();
5328 _session->add_command(new MementoCommand<AutomationList>(*alist, &before, &after));
5331 commit_reversible_command ();
5335 Editor::set_fade_in_shape (FadeShape shape)
5337 RegionSelection rs = get_regions_from_selection_and_entered ();
5343 begin_reversible_command (_("set fade in shape"));
5345 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5346 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5352 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_in();
5353 XMLNode &before = alist->get_state();
5355 tmp->audio_region()->set_fade_in_shape (shape);
5357 XMLNode &after = alist->get_state();
5358 _session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
5361 commit_reversible_command ();
5366 Editor::set_fade_out_shape (FadeShape shape)
5368 RegionSelection rs = get_regions_from_selection_and_entered ();
5374 begin_reversible_command (_("set fade out shape"));
5376 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5377 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5383 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_out();
5384 XMLNode &before = alist->get_state();
5386 tmp->audio_region()->set_fade_out_shape (shape);
5388 XMLNode &after = alist->get_state();
5389 _session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
5392 commit_reversible_command ();
5396 Editor::set_fade_in_active (bool yn)
5398 RegionSelection rs = get_regions_from_selection_and_entered ();
5404 begin_reversible_command (_("set fade in active"));
5406 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5407 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5414 boost::shared_ptr<AudioRegion> ar (tmp->audio_region());
5416 ar->clear_changes ();
5417 ar->set_fade_in_active (yn);
5418 _session->add_command (new StatefulDiffCommand (ar));
5421 commit_reversible_command ();
5425 Editor::set_fade_out_active (bool yn)
5427 RegionSelection rs = get_regions_from_selection_and_entered ();
5433 begin_reversible_command (_("set fade out active"));
5435 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5436 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5442 boost::shared_ptr<AudioRegion> ar (tmp->audio_region());
5444 ar->clear_changes ();
5445 ar->set_fade_out_active (yn);
5446 _session->add_command(new StatefulDiffCommand (ar));
5449 commit_reversible_command ();
5453 Editor::toggle_region_fades (int dir)
5455 if (_ignore_region_action) {
5459 boost::shared_ptr<AudioRegion> ar;
5462 RegionSelection rs = get_regions_from_selection_and_entered ();
5468 RegionSelection::iterator i;
5469 for (i = rs.begin(); i != rs.end(); ++i) {
5470 if ((ar = boost::dynamic_pointer_cast<AudioRegion>((*i)->region())) != 0) {
5472 yn = ar->fade_out_active ();
5474 yn = ar->fade_in_active ();
5480 if (i == rs.end()) {
5484 /* XXX should this undo-able? */
5486 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5487 if ((ar = boost::dynamic_pointer_cast<AudioRegion>((*i)->region())) == 0) {
5490 if (dir == 1 || dir == 0) {
5491 ar->set_fade_in_active (!yn);
5494 if (dir == -1 || dir == 0) {
5495 ar->set_fade_out_active (!yn);
5501 /** Update region fade visibility after its configuration has been changed */
5503 Editor::update_region_fade_visibility ()
5505 bool _fade_visibility = _session->config.get_show_region_fades ();
5507 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5508 AudioTimeAxisView* v = dynamic_cast<AudioTimeAxisView*>(*i);
5510 if (_fade_visibility) {
5511 v->audio_view()->show_all_fades ();
5513 v->audio_view()->hide_all_fades ();
5520 Editor::set_edit_point ()
5525 if (!mouse_frame (where, ignored)) {
5531 if (selection->markers.empty()) {
5533 mouse_add_new_marker (where);
5538 Location* loc = find_location_from_marker (selection->markers.front(), ignored);
5541 loc->move_to (where);
5547 Editor::set_playhead_cursor ()
5549 if (entered_marker) {
5550 _session->request_locate (entered_marker->position(), _session->transport_rolling());
5555 if (!mouse_frame (where, ignored)) {
5562 _session->request_locate (where, _session->transport_rolling());
5566 if ( Config->get_always_play_range() )
5567 cancel_time_selection();
5571 Editor::split_region ()
5573 if ( !selection->time.empty()) {
5574 separate_regions_between (selection->time);
5578 RegionSelection rs = get_regions_from_selection_and_edit_point ();
5580 framepos_t where = get_preferred_edit_position ();
5586 split_regions_at (where, rs);
5589 struct EditorOrderRouteSorter {
5590 bool operator() (boost::shared_ptr<Route> a, boost::shared_ptr<Route> b) {
5591 return a->order_key () < b->order_key ();
5596 Editor::select_next_route()
5598 if (selection->tracks.empty()) {
5599 selection->set (track_views.front());
5603 TimeAxisView* current = selection->tracks.front();
5607 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5608 if (*i == current) {
5610 if (i != track_views.end()) {
5613 current = (*(track_views.begin()));
5614 //selection->set (*(track_views.begin()));
5619 rui = dynamic_cast<RouteUI *>(current);
5620 } while ( current->hidden() || (rui != NULL && !rui->route()->active()));
5622 selection->set(current);
5624 ensure_track_visible(current);
5628 Editor::select_prev_route()
5630 if (selection->tracks.empty()) {
5631 selection->set (track_views.front());
5635 TimeAxisView* current = selection->tracks.front();
5639 for (TrackViewList::reverse_iterator i = track_views.rbegin(); i != track_views.rend(); ++i) {
5640 if (*i == current) {
5642 if (i != track_views.rend()) {
5645 current = *(track_views.rbegin());
5650 rui = dynamic_cast<RouteUI *>(current);
5651 } while ( current->hidden() || (rui != NULL && !rui->route()->active()));
5653 selection->set (current);
5655 ensure_track_visible(current);
5659 Editor::ensure_track_visible(TimeAxisView *track)
5661 if (track->hidden()) {
5665 /* compute visible area of trackview group, as offsets from top of
5669 double const current_view_min_y = vertical_adjustment.get_value();
5670 double const current_view_max_y = current_view_min_y + vertical_adjustment.get_page_size();
5672 double const track_min_y = track->y_position ();
5673 double const track_max_y = track->y_position () + track->effective_height ();
5675 if (track_min_y > current_view_min_y &&
5676 track_max_y <= current_view_max_y) {
5682 if (track_min_y < current_view_min_y) {
5683 // Track is above the current view
5684 new_value = track_min_y;
5686 // Track is below the current view
5687 new_value = track->y_position () + track->effective_height() - vertical_adjustment.get_page_size();
5690 vertical_adjustment.set_value(new_value);
5694 Editor::set_loop_from_selection (bool play)
5696 if (_session == 0 || selection->time.empty()) {
5700 framepos_t start = selection->time[clicked_selection].start;
5701 framepos_t end = selection->time[clicked_selection].end;
5703 set_loop_range (start, end, _("set loop range from selection"));
5706 _session->request_play_loop (true);
5707 _session->request_locate (start, true);
5712 Editor::set_loop_from_edit_range (bool play)
5714 if (_session == 0) {
5721 if (!get_edit_op_range (start, end)) {
5725 set_loop_range (start, end, _("set loop range from edit range"));
5728 _session->request_play_loop (true);
5729 _session->request_locate (start, true);
5734 Editor::set_loop_from_region (bool play)
5736 framepos_t start = max_framepos;
5739 RegionSelection rs = get_regions_from_selection_and_entered ();
5745 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5746 if ((*i)->region()->position() < start) {
5747 start = (*i)->region()->position();
5749 if ((*i)->region()->last_frame() + 1 > end) {
5750 end = (*i)->region()->last_frame() + 1;
5754 set_loop_range (start, end, _("set loop range from region"));
5757 _session->request_play_loop (true);
5758 _session->request_locate (start, true);
5763 Editor::set_punch_from_selection ()
5765 if (_session == 0 || selection->time.empty()) {
5769 framepos_t start = selection->time[clicked_selection].start;
5770 framepos_t end = selection->time[clicked_selection].end;
5772 set_punch_range (start, end, _("set punch range from selection"));
5776 Editor::set_punch_from_edit_range ()
5778 if (_session == 0) {
5785 if (!get_edit_op_range (start, end)) {
5789 set_punch_range (start, end, _("set punch range from edit range"));
5793 Editor::set_punch_from_region ()
5795 framepos_t start = max_framepos;
5798 RegionSelection rs = get_regions_from_selection_and_entered ();
5804 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5805 if ((*i)->region()->position() < start) {
5806 start = (*i)->region()->position();
5808 if ((*i)->region()->last_frame() + 1 > end) {
5809 end = (*i)->region()->last_frame() + 1;
5813 set_punch_range (start, end, _("set punch range from region"));
5817 Editor::pitch_shift_region ()
5819 RegionSelection rs = get_regions_from_selection_and_entered ();
5821 RegionSelection audio_rs;
5822 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5823 if (dynamic_cast<AudioRegionView*> (*i)) {
5824 audio_rs.push_back (*i);
5828 if (audio_rs.empty()) {
5832 pitch_shift (audio_rs, 1.2);
5836 Editor::transpose_region ()
5838 RegionSelection rs = get_regions_from_selection_and_entered ();
5840 list<MidiRegionView*> midi_region_views;
5841 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5842 MidiRegionView* mrv = dynamic_cast<MidiRegionView*> (*i);
5844 midi_region_views.push_back (mrv);
5849 int const r = d.run ();
5850 if (r != RESPONSE_ACCEPT) {
5854 for (list<MidiRegionView*>::iterator i = midi_region_views.begin(); i != midi_region_views.end(); ++i) {
5855 (*i)->midi_region()->transpose (d.semitones ());
5860 Editor::set_tempo_from_region ()
5862 RegionSelection rs = get_regions_from_selection_and_entered ();
5864 if (!_session || rs.empty()) {
5868 RegionView* rv = rs.front();
5870 define_one_bar (rv->region()->position(), rv->region()->last_frame() + 1);
5874 Editor::use_range_as_bar ()
5876 framepos_t start, end;
5877 if (get_edit_op_range (start, end)) {
5878 define_one_bar (start, end);
5883 Editor::define_one_bar (framepos_t start, framepos_t end)
5885 framepos_t length = end - start;
5887 const Meter& m (_session->tempo_map().meter_at (start));
5889 /* length = 1 bar */
5891 /* now we want frames per beat.
5892 we have frames per bar, and beats per bar, so ...
5895 /* XXXX METER MATH */
5897 double frames_per_beat = length / m.divisions_per_bar();
5899 /* beats per minute = */
5901 double beats_per_minute = (_session->frame_rate() * 60.0) / frames_per_beat;
5903 /* now decide whether to:
5905 (a) set global tempo
5906 (b) add a new tempo marker
5910 const TempoSection& t (_session->tempo_map().tempo_section_at (start));
5912 bool do_global = false;
5914 if ((_session->tempo_map().n_tempos() == 1) && (_session->tempo_map().n_meters() == 1)) {
5916 /* only 1 tempo & 1 meter: ask if the user wants to set the tempo
5917 at the start, or create a new marker
5920 vector<string> options;
5921 options.push_back (_("Cancel"));
5922 options.push_back (_("Add new marker"));
5923 options.push_back (_("Set global tempo"));
5926 _("Define one bar"),
5927 _("Do you want to set the global tempo or add a new tempo marker?"),
5931 c.set_default_response (2);
5947 /* more than 1 tempo and/or meter section already, go ahead do the "usual":
5948 if the marker is at the region starter, change it, otherwise add
5953 begin_reversible_command (_("set tempo from region"));
5954 XMLNode& before (_session->tempo_map().get_state());
5957 _session->tempo_map().change_initial_tempo (beats_per_minute, t.note_type());
5958 } else if (t.frame() == start) {
5959 _session->tempo_map().change_existing_tempo_at (start, beats_per_minute, t.note_type());
5961 Timecode::BBT_Time bbt;
5962 _session->tempo_map().bbt_time (start, bbt);
5963 _session->tempo_map().add_tempo (Tempo (beats_per_minute, t.note_type()), bbt);
5966 XMLNode& after (_session->tempo_map().get_state());
5968 _session->add_command (new MementoCommand<TempoMap>(_session->tempo_map(), &before, &after));
5969 commit_reversible_command ();
5973 Editor::split_region_at_transients ()
5975 AnalysisFeatureList positions;
5977 RegionSelection rs = get_regions_from_selection_and_entered ();
5979 if (!_session || rs.empty()) {
5983 _session->begin_reversible_command (_("split regions"));
5985 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ) {
5987 RegionSelection::iterator tmp;
5992 boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion> ((*i)->region());
5994 if (ar && (ar->get_transients (positions) == 0)) {
5995 split_region_at_points ((*i)->region(), positions, true);
6002 _session->commit_reversible_command ();
6007 Editor::split_region_at_points (boost::shared_ptr<Region> r, AnalysisFeatureList& positions, bool can_ferret, bool select_new)
6009 bool use_rhythmic_rodent = false;
6011 boost::shared_ptr<Playlist> pl = r->playlist();
6013 list<boost::shared_ptr<Region> > new_regions;
6019 if (positions.empty()) {
6024 if (positions.size() > 20 && can_ferret) {
6025 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);
6026 MessageDialog msg (msgstr,
6029 Gtk::BUTTONS_OK_CANCEL);
6032 msg.add_button (_("Call for the Ferret!"), RESPONSE_APPLY);
6033 msg.set_secondary_text (_("Press OK to continue with this split operation\nor ask the Ferret dialog to tune the analysis"));
6035 msg.set_secondary_text (_("Press OK to continue with this split operation"));
6038 msg.set_title (_("Excessive split?"));
6041 int response = msg.run();
6047 case RESPONSE_APPLY:
6048 use_rhythmic_rodent = true;
6055 if (use_rhythmic_rodent) {
6056 show_rhythm_ferret ();
6060 AnalysisFeatureList::const_iterator x;
6062 pl->clear_changes ();
6063 pl->clear_owned_changes ();
6065 x = positions.begin();
6067 if (x == positions.end()) {
6072 pl->remove_region (r);
6076 while (x != positions.end()) {
6078 /* deal with positons that are out of scope of present region bounds */
6079 if (*x <= 0 || *x > r->length()) {
6084 /* file start = original start + how far we from the initial position ?
6087 framepos_t file_start = r->start() + pos;
6089 /* length = next position - current position
6092 framepos_t len = (*x) - pos;
6094 /* XXX we do we really want to allow even single-sample regions?
6095 shouldn't we have some kind of lower limit on region size?
6104 if (RegionFactory::region_name (new_name, r->name())) {
6108 /* do NOT announce new regions 1 by one, just wait till they are all done */
6112 plist.add (ARDOUR::Properties::start, file_start);
6113 plist.add (ARDOUR::Properties::length, len);
6114 plist.add (ARDOUR::Properties::name, new_name);
6115 plist.add (ARDOUR::Properties::layer, 0);
6117 boost::shared_ptr<Region> nr = RegionFactory::create (r->sources(), plist, false);
6118 /* because we set annouce to false, manually add the new region to the
6121 RegionFactory::map_add (nr);
6123 pl->add_region (nr, r->position() + pos);
6126 new_regions.push_front(nr);
6135 RegionFactory::region_name (new_name, r->name());
6137 /* Add the final region */
6140 plist.add (ARDOUR::Properties::start, r->start() + pos);
6141 plist.add (ARDOUR::Properties::length, r->last_frame() - (r->position() + pos) + 1);
6142 plist.add (ARDOUR::Properties::name, new_name);
6143 plist.add (ARDOUR::Properties::layer, 0);
6145 boost::shared_ptr<Region> nr = RegionFactory::create (r->sources(), plist, false);
6146 /* because we set annouce to false, manually add the new region to the
6149 RegionFactory::map_add (nr);
6150 pl->add_region (nr, r->position() + pos);
6153 new_regions.push_front(nr);
6158 /* We might have removed regions, which alters other regions' layering_index,
6159 so we need to do a recursive diff here.
6161 vector<Command*> cmds;
6163 _session->add_commands (cmds);
6165 _session->add_command (new StatefulDiffCommand (pl));
6169 for (list<boost::shared_ptr<Region> >::iterator i = new_regions.begin(); i != new_regions.end(); ++i){
6170 set_selected_regionview_from_region_list ((*i), Selection::Add);
6176 Editor::place_transient()
6182 RegionSelection rs = get_regions_from_selection_and_edit_point ();
6188 framepos_t where = get_preferred_edit_position();
6190 _session->begin_reversible_command (_("place transient"));
6192 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6193 framepos_t position = (*r)->region()->position();
6194 (*r)->region()->add_transient(where - position);
6197 _session->commit_reversible_command ();
6201 Editor::remove_transient(ArdourCanvas::Item* item)
6207 ArdourCanvas::Line* _line = reinterpret_cast<ArdourCanvas::Line*> (item);
6210 AudioRegionView* _arv = reinterpret_cast<AudioRegionView*> (item->get_data ("regionview"));
6211 _arv->remove_transient (*(float*) _line->get_data ("position"));
6215 Editor::snap_regions_to_grid ()
6217 list <boost::shared_ptr<Playlist > > used_playlists;
6219 RegionSelection rs = get_regions_from_selection_and_entered ();
6221 if (!_session || rs.empty()) {
6225 _session->begin_reversible_command (_("snap regions to grid"));
6227 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6229 boost::shared_ptr<Playlist> pl = (*r)->region()->playlist();
6231 if (!pl->frozen()) {
6232 /* we haven't seen this playlist before */
6234 /* remember used playlists so we can thaw them later */
6235 used_playlists.push_back(pl);
6239 framepos_t start_frame = (*r)->region()->first_frame ();
6240 snap_to (start_frame);
6241 (*r)->region()->set_position (start_frame);
6244 while (used_playlists.size() > 0) {
6245 list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
6247 used_playlists.pop_front();
6250 _session->commit_reversible_command ();
6254 Editor::close_region_gaps ()
6256 list <boost::shared_ptr<Playlist > > used_playlists;
6258 RegionSelection rs = get_regions_from_selection_and_entered ();
6260 if (!_session || rs.empty()) {
6264 Dialog dialog (_("Close Region Gaps"));
6267 table.set_spacings (12);
6268 table.set_border_width (12);
6269 Label* l = manage (left_aligned_label (_("Crossfade length")));
6270 table.attach (*l, 0, 1, 0, 1);
6272 SpinButton spin_crossfade (1, 0);
6273 spin_crossfade.set_range (0, 15);
6274 spin_crossfade.set_increments (1, 1);
6275 spin_crossfade.set_value (5);
6276 table.attach (spin_crossfade, 1, 2, 0, 1);
6278 table.attach (*manage (new Label (_("ms"))), 2, 3, 0, 1);
6280 l = manage (left_aligned_label (_("Pull-back length")));
6281 table.attach (*l, 0, 1, 1, 2);
6283 SpinButton spin_pullback (1, 0);
6284 spin_pullback.set_range (0, 100);
6285 spin_pullback.set_increments (1, 1);
6286 spin_pullback.set_value(30);
6287 table.attach (spin_pullback, 1, 2, 1, 2);
6289 table.attach (*manage (new Label (_("ms"))), 2, 3, 1, 2);
6291 dialog.get_vbox()->pack_start (table);
6292 dialog.add_button (Stock::CANCEL, RESPONSE_CANCEL);
6293 dialog.add_button (_("Ok"), RESPONSE_ACCEPT);
6296 if (dialog.run () == RESPONSE_CANCEL) {
6300 framepos_t crossfade_len = spin_crossfade.get_value();
6301 framepos_t pull_back_frames = spin_pullback.get_value();
6303 crossfade_len = lrintf (crossfade_len * _session->frame_rate()/1000);
6304 pull_back_frames = lrintf (pull_back_frames * _session->frame_rate()/1000);
6306 /* Iterate over the region list and make adjacent regions overlap by crossfade_len_ms */
6308 _session->begin_reversible_command (_("close region gaps"));
6311 boost::shared_ptr<Region> last_region;
6313 rs.sort_by_position_and_track();
6315 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6317 boost::shared_ptr<Playlist> pl = (*r)->region()->playlist();
6319 if (!pl->frozen()) {
6320 /* we haven't seen this playlist before */
6322 /* remember used playlists so we can thaw them later */
6323 used_playlists.push_back(pl);
6327 framepos_t position = (*r)->region()->position();
6329 if (idx == 0 || position < last_region->position()){
6330 last_region = (*r)->region();
6335 (*r)->region()->trim_front( (position - pull_back_frames));
6336 last_region->trim_end( (position - pull_back_frames + crossfade_len));
6338 last_region = (*r)->region();
6343 while (used_playlists.size() > 0) {
6344 list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
6346 used_playlists.pop_front();
6349 _session->commit_reversible_command ();
6353 Editor::tab_to_transient (bool forward)
6355 AnalysisFeatureList positions;
6357 RegionSelection rs = get_regions_from_selection_and_entered ();
6363 framepos_t pos = _session->audible_frame ();
6365 if (!selection->tracks.empty()) {
6367 /* don't waste time searching for transients in duplicate playlists.
6370 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
6372 for (TrackViewList::iterator t = ts.begin(); t != ts.end(); ++t) {
6374 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*t);
6377 boost::shared_ptr<Track> tr = rtv->track();
6379 boost::shared_ptr<Playlist> pl = tr->playlist ();
6381 framepos_t result = pl->find_next_transient (pos, forward ? 1 : -1);
6384 positions.push_back (result);
6397 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6398 (*r)->region()->get_transients (positions);
6402 TransientDetector::cleanup_transients (positions, _session->frame_rate(), 3.0);
6405 AnalysisFeatureList::iterator x;
6407 for (x = positions.begin(); x != positions.end(); ++x) {
6413 if (x != positions.end ()) {
6414 _session->request_locate (*x);
6418 AnalysisFeatureList::reverse_iterator x;
6420 for (x = positions.rbegin(); x != positions.rend(); ++x) {
6426 if (x != positions.rend ()) {
6427 _session->request_locate (*x);
6433 Editor::playhead_forward_to_grid ()
6439 framepos_t pos = playhead_cursor->current_frame ();
6440 if (pos < max_framepos - 1) {
6442 snap_to_internal (pos, 1, false);
6443 _session->request_locate (pos);
6449 Editor::playhead_backward_to_grid ()
6455 framepos_t pos = playhead_cursor->current_frame ();
6458 snap_to_internal (pos, -1, false);
6459 _session->request_locate (pos);
6464 Editor::set_track_height (Height h)
6466 TrackSelection& ts (selection->tracks);
6468 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
6469 (*x)->set_height_enum (h);
6474 Editor::toggle_tracks_active ()
6476 TrackSelection& ts (selection->tracks);
6478 bool target = false;
6484 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
6485 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*x);
6489 target = !rtv->_route->active();
6492 rtv->_route->set_active (target, this);
6498 Editor::remove_tracks ()
6500 TrackSelection& ts (selection->tracks);
6506 vector<string> choices;
6510 const char* trackstr;
6512 vector<boost::shared_ptr<Route> > routes;
6513 bool special_bus = false;
6515 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
6516 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*x);
6520 if (rtv->is_track()) {
6525 routes.push_back (rtv->_route);
6527 if (rtv->route()->is_master() || rtv->route()->is_monitor()) {
6532 if (special_bus && !Config->get_allow_special_bus_removal()) {
6533 MessageDialog msg (_("That would be bad news ...."),
6537 msg.set_secondary_text (string_compose (_(
6538 "Removing the master or monitor bus is such a bad idea\n\
6539 that %1 is not going to allow it.\n\
6541 If you really want to do this sort of thing\n\
6542 edit your ardour.rc file to set the\n\
6543 \"allow-special-bus-removal\" option to be \"yes\""), PROGRAM_NAME));
6550 if (ntracks + nbusses == 0) {
6555 trackstr = _("tracks");
6557 trackstr = _("track");
6561 busstr = _("busses");
6568 prompt = string_compose (_("Do you really want to remove %1 %2 and %3 %4?\n"
6569 "(You may also lose the playlists associated with the %2)\n\n"
6570 "This action cannot be undone, and the session file will be overwritten!"),
6571 ntracks, trackstr, nbusses, busstr);
6573 prompt = string_compose (_("Do you really want to remove %1 %2?\n"
6574 "(You may also lose the playlists associated with the %2)\n\n"
6575 "This action cannot be undone, and the session file will be overwritten!"),
6578 } else if (nbusses) {
6579 prompt = string_compose (_("Do you really want to remove %1 %2?\n\n"
6580 "This action cannot be undon, and the session file will be overwritten"),
6584 choices.push_back (_("No, do nothing."));
6585 if (ntracks + nbusses > 1) {
6586 choices.push_back (_("Yes, remove them."));
6588 choices.push_back (_("Yes, remove it."));
6593 title = string_compose (_("Remove %1"), trackstr);
6595 title = string_compose (_("Remove %1"), busstr);
6598 Choice prompter (title, prompt, choices);
6600 if (prompter.run () != 1) {
6604 for (vector<boost::shared_ptr<Route> >::iterator x = routes.begin(); x != routes.end(); ++x) {
6605 _session->remove_route (*x);
6610 Editor::do_insert_time ()
6612 if (selection->tracks.empty()) {
6616 InsertTimeDialog d (*this);
6617 int response = d.run ();
6619 if (response != RESPONSE_OK) {
6623 if (d.distance() == 0) {
6627 InsertTimeOption opt = d.intersected_region_action ();
6630 get_preferred_edit_position(),
6636 d.move_glued_markers(),
6637 d.move_locked_markers(),
6643 Editor::insert_time (
6644 framepos_t pos, framecnt_t frames, InsertTimeOption opt,
6645 bool all_playlists, bool ignore_music_glue, bool markers_too, bool glued_markers_too, bool locked_markers_too, bool tempo_too
6648 bool commit = false;
6650 if (Config->get_edit_mode() == Lock) {
6654 begin_reversible_command (_("insert time"));
6656 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
6658 for (TrackViewList::iterator x = ts.begin(); x != ts.end(); ++x) {
6662 /* don't operate on any playlist more than once, which could
6663 * happen if "all playlists" is enabled, but there is more
6664 * than 1 track using playlists "from" a given track.
6667 set<boost::shared_ptr<Playlist> > pl;
6669 if (all_playlists) {
6670 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*x);
6672 vector<boost::shared_ptr<Playlist> > all = _session->playlists->playlists_for_track (rtav->track ());
6673 for (vector<boost::shared_ptr<Playlist> >::iterator p = all.begin(); p != all.end(); ++p) {
6678 if ((*x)->playlist ()) {
6679 pl.insert ((*x)->playlist ());
6683 for (set<boost::shared_ptr<Playlist> >::iterator i = pl.begin(); i != pl.end(); ++i) {
6685 (*i)->clear_changes ();
6686 (*i)->clear_owned_changes ();
6688 if (opt == SplitIntersected) {
6692 (*i)->shift (pos, frames, (opt == MoveIntersected), ignore_music_glue);
6694 vector<Command*> cmds;
6696 _session->add_commands (cmds);
6698 _session->add_command (new StatefulDiffCommand (*i));
6703 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*x);
6705 rtav->route ()->shift (pos, frames);
6713 XMLNode& before (_session->locations()->get_state());
6714 Locations::LocationList copy (_session->locations()->list());
6716 for (Locations::LocationList::iterator i = copy.begin(); i != copy.end(); ++i) {
6718 Locations::LocationList::const_iterator tmp;
6720 bool const was_locked = (*i)->locked ();
6721 if (locked_markers_too) {
6725 if ((*i)->position_lock_style() == AudioTime || glued_markers_too) {
6727 if ((*i)->start() >= pos) {
6728 (*i)->set_start ((*i)->start() + frames);
6729 if (!(*i)->is_mark()) {
6730 (*i)->set_end ((*i)->end() + frames);
6743 XMLNode& after (_session->locations()->get_state());
6744 _session->add_command (new MementoCommand<Locations>(*_session->locations(), &before, &after));
6749 _session->tempo_map().insert_time (pos, frames);
6753 commit_reversible_command ();
6758 Editor::fit_selected_tracks ()
6760 if (!selection->tracks.empty()) {
6761 fit_tracks (selection->tracks);
6765 /* no selected tracks - use tracks with selected regions */
6767 if (!selection->regions.empty()) {
6768 for (RegionSelection::iterator r = selection->regions.begin(); r != selection->regions.end(); ++r) {
6769 tvl.push_back (&(*r)->get_time_axis_view ());
6775 } else if (internal_editing()) {
6776 /* no selected tracks, or regions, but in internal edit mode, so follow the mouse and use
6779 if (entered_track) {
6780 tvl.push_back (entered_track);
6788 Editor::fit_tracks (TrackViewList & tracks)
6790 if (tracks.empty()) {
6794 uint32_t child_heights = 0;
6795 int visible_tracks = 0;
6797 for (TrackSelection::iterator t = tracks.begin(); t != tracks.end(); ++t) {
6799 if (!(*t)->marked_for_display()) {
6803 child_heights += (*t)->effective_height() - (*t)->current_height();
6807 /* compute the per-track height from:
6809 total canvas visible height -
6810 height that will be taken by visible children of selected
6811 tracks - height of the ruler/hscroll area
6813 uint32_t h = (uint32_t) floor ((_visible_canvas_height - (child_heights + _trackview_group->canvas_origin().y)) / visible_tracks);
6814 double first_y_pos = DBL_MAX;
6816 if (h < TimeAxisView::preset_height (HeightSmall)) {
6817 MessageDialog msg (*this, _("There are too many tracks to fit in the current window"));
6818 /* too small to be displayed */
6822 undo_visual_stack.push_back (current_visual_state (true));
6823 no_save_visual = true;
6825 /* build a list of all tracks, including children */
6828 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
6830 TimeAxisView::Children c = (*i)->get_child_list ();
6831 for (TimeAxisView::Children::iterator j = c.begin(); j != c.end(); ++j) {
6832 all.push_back (j->get());
6836 /* operate on all tracks, hide unselected ones that are in the middle of selected ones */
6838 bool within_selected = false;
6840 for (TrackViewList::iterator t = all.begin(); t != all.end(); ++t) {
6842 TrackViewList::iterator next;
6847 if ((*t)->marked_for_display ()) {
6848 if (tracks.contains (*t)) {
6849 (*t)->set_height (h);
6850 first_y_pos = std::min ((*t)->y_position (), first_y_pos);
6851 within_selected = true;
6852 } else if (within_selected) {
6853 hide_track_in_display (*t);
6859 set the controls_layout height now, because waiting for its size
6860 request signal handler will cause the vertical adjustment setting to fail
6863 controls_layout.property_height () = _full_canvas_height;
6864 vertical_adjustment.set_value (first_y_pos);
6866 redo_visual_stack.push_back (current_visual_state (true));
6870 Editor::save_visual_state (uint32_t n)
6872 while (visual_states.size() <= n) {
6873 visual_states.push_back (0);
6876 if (visual_states[n] != 0) {
6877 delete visual_states[n];
6880 visual_states[n] = current_visual_state (true);
6885 Editor::goto_visual_state (uint32_t n)
6887 if (visual_states.size() <= n) {
6891 if (visual_states[n] == 0) {
6895 use_visual_state (*visual_states[n]);
6899 Editor::start_visual_state_op (uint32_t n)
6901 save_visual_state (n);
6903 PopUp* pup = new PopUp (WIN_POS_MOUSE, 1000, true);
6905 snprintf (buf, sizeof (buf), _("Saved view %u"), n+1);
6906 pup->set_text (buf);
6911 Editor::cancel_visual_state_op (uint32_t n)
6913 goto_visual_state (n);
6917 Editor::toggle_region_mute ()
6919 if (_ignore_region_action) {
6923 RegionSelection rs = get_regions_from_selection_and_entered ();
6929 if (rs.size() > 1) {
6930 begin_reversible_command (_("mute regions"));
6932 begin_reversible_command (_("mute region"));
6935 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
6937 (*i)->region()->playlist()->clear_changes ();
6938 (*i)->region()->set_muted (!(*i)->region()->muted ());
6939 _session->add_command (new StatefulDiffCommand ((*i)->region()->playlist()));
6943 commit_reversible_command ();
6947 Editor::combine_regions ()
6949 /* foreach track with selected regions, take all selected regions
6950 and join them into a new region containing the subregions (as a
6954 typedef set<RouteTimeAxisView*> RTVS;
6957 if (selection->regions.empty()) {
6961 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
6962 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(&(*i)->get_time_axis_view());
6965 tracks.insert (rtv);
6969 begin_reversible_command (_("combine regions"));
6971 vector<RegionView*> new_selection;
6973 for (RTVS::iterator i = tracks.begin(); i != tracks.end(); ++i) {
6976 if ((rv = (*i)->combine_regions ()) != 0) {
6977 new_selection.push_back (rv);
6981 selection->clear_regions ();
6982 for (vector<RegionView*>::iterator i = new_selection.begin(); i != new_selection.end(); ++i) {
6983 selection->add (*i);
6986 commit_reversible_command ();
6990 Editor::uncombine_regions ()
6992 typedef set<RouteTimeAxisView*> RTVS;
6995 if (selection->regions.empty()) {
6999 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
7000 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(&(*i)->get_time_axis_view());
7003 tracks.insert (rtv);
7007 begin_reversible_command (_("uncombine regions"));
7009 for (RTVS::iterator i = tracks.begin(); i != tracks.end(); ++i) {
7010 (*i)->uncombine_regions ();
7013 commit_reversible_command ();
7017 Editor::toggle_midi_input_active (bool flip_others)
7020 boost::shared_ptr<RouteList> rl (new RouteList);
7022 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
7023 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
7029 boost::shared_ptr<MidiTrack> mt = rtav->midi_track();
7032 rl->push_back (rtav->route());
7033 onoff = !mt->input_active();
7037 _session->set_exclusive_input_active (rl, onoff, flip_others);
7044 lock_dialog = new Gtk::Dialog (string_compose (_("%1: Locked"), PROGRAM_NAME), true);
7046 Gtk::Image* padlock = manage (new Gtk::Image (::get_icon ("padlock_closed")));
7047 lock_dialog->get_vbox()->pack_start (*padlock);
7049 ArdourButton* b = manage (new ArdourButton);
7050 b->set_name ("lock button");
7051 b->set_markup (string_compose ("<span size=\"large\" weight=\"bold\">%1</span>", _("Click to unlock")));
7052 b->signal_clicked.connect (sigc::mem_fun (*this, &Editor::unlock));
7053 lock_dialog->get_vbox()->pack_start (*b);
7055 lock_dialog->get_vbox()->show_all ();
7056 lock_dialog->set_size_request (200, 200);
7060 /* The global menu bar continues to be accessible to applications
7061 with modal dialogs, which means that we need to desensitize
7062 all items in the menu bar. Since those items are really just
7063 proxies for actions, that means disabling all actions.
7065 ActionManager::disable_all_actions ();
7067 lock_dialog->present ();
7073 lock_dialog->hide ();
7076 ActionManager::pop_action_state ();
7079 if (ARDOUR_UI::config()->get_lock_gui_after_seconds()) {
7080 start_lock_event_timing ();