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"
96 using namespace ARDOUR;
99 using namespace Gtkmm2ext;
100 using namespace Editing;
101 using Gtkmm2ext::Keyboard;
103 /***********************************************************************
105 ***********************************************************************/
108 Editor::undo (uint32_t n)
110 if (_drags->active ()) {
120 Editor::redo (uint32_t n)
122 if (_drags->active ()) {
132 Editor::split_regions_at (framepos_t where, RegionSelection& regions)
136 list<boost::shared_ptr<Playlist> > used_playlists;
137 list<RouteTimeAxisView*> used_trackviews;
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);
193 TimeAxisView& tv = (*a)->get_time_axis_view();
194 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (&tv);
196 used_trackviews.push_back (rtv);
203 pl->clear_changes ();
204 pl->split_region ((*a)->region(), where);
205 _session->add_command (new StatefulDiffCommand (pl));
211 vector<sigc::connection> region_added_connections;
213 for (list<RouteTimeAxisView*>::iterator i = used_trackviews.begin(); i != used_trackviews.end(); ++i) {
214 region_added_connections.push_back ((*i)->view()->RegionViewAdded.connect (sigc::mem_fun(*this, &Editor::collect_new_region_view)));
217 latest_regionviews.clear ();
219 while (used_playlists.size() > 0) {
220 list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
222 used_playlists.pop_front();
225 for (vector<sigc::connection>::iterator c = region_added_connections.begin(); c != region_added_connections.end(); ++c) {
229 commit_reversible_command ();
232 EditorThaw(); /* Emit Signal */
235 if (!latest_regionviews.empty()) {
236 selection->add (latest_regionviews);
241 /** Move one extreme of the current range selection. If more than one range is selected,
242 * the start of the earliest range or the end of the latest range is moved.
244 * @param move_end true to move the end of the current range selection, false to move
246 * @param next true to move the extreme to the next region boundary, false to move to
250 Editor::move_range_selection_start_or_end_to_region_boundary (bool move_end, bool next)
252 if (selection->time.start() == selection->time.end_frame()) {
256 framepos_t start = selection->time.start ();
257 framepos_t end = selection->time.end_frame ();
259 /* the position of the thing we may move */
260 framepos_t pos = move_end ? end : start;
261 int dir = next ? 1 : -1;
263 /* so we don't find the current region again */
264 if (dir > 0 || pos > 0) {
268 framepos_t const target = get_region_boundary (pos, dir, true, false);
283 begin_reversible_command (_("alter selection"));
284 selection->set_preserving_all_ranges (start, end);
285 commit_reversible_command ();
289 Editor::nudge_forward_release (GdkEventButton* ev)
291 if (ev->state & Keyboard::PrimaryModifier) {
292 nudge_forward (false, true);
294 nudge_forward (false, false);
300 Editor::nudge_backward_release (GdkEventButton* ev)
302 if (ev->state & Keyboard::PrimaryModifier) {
303 nudge_backward (false, true);
305 nudge_backward (false, false);
312 Editor::nudge_forward (bool next, bool force_playhead)
315 framepos_t next_distance;
321 RegionSelection rs = get_regions_from_selection_and_entered ();
323 if (!force_playhead && !rs.empty()) {
325 begin_reversible_command (_("nudge regions forward"));
327 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
328 boost::shared_ptr<Region> r ((*i)->region());
330 distance = get_nudge_distance (r->position(), next_distance);
333 distance = next_distance;
337 r->set_position (r->position() + distance);
338 _session->add_command (new StatefulDiffCommand (r));
341 commit_reversible_command ();
344 } else if (!force_playhead && !selection->markers.empty()) {
348 begin_reversible_command (_("nudge location forward"));
350 for (MarkerSelection::iterator i = selection->markers.begin(); i != selection->markers.end(); ++i) {
352 Location* loc = find_location_from_marker ((*i), is_start);
356 XMLNode& before (loc->get_state());
359 distance = get_nudge_distance (loc->start(), next_distance);
361 distance = next_distance;
363 if (max_framepos - distance > loc->start() + loc->length()) {
364 loc->set_start (loc->start() + distance);
366 loc->set_start (max_framepos - loc->length());
369 distance = get_nudge_distance (loc->end(), next_distance);
371 distance = next_distance;
373 if (max_framepos - distance > loc->end()) {
374 loc->set_end (loc->end() + distance);
376 loc->set_end (max_framepos);
379 XMLNode& after (loc->get_state());
380 _session->add_command (new MementoCommand<Location>(*loc, &before, &after));
384 commit_reversible_command ();
387 distance = get_nudge_distance (playhead_cursor->current_frame (), next_distance);
388 _session->request_locate (playhead_cursor->current_frame () + distance);
393 Editor::nudge_backward (bool next, bool force_playhead)
396 framepos_t next_distance;
402 RegionSelection rs = get_regions_from_selection_and_entered ();
404 if (!force_playhead && !rs.empty()) {
406 begin_reversible_command (_("nudge regions backward"));
408 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
409 boost::shared_ptr<Region> r ((*i)->region());
411 distance = get_nudge_distance (r->position(), next_distance);
414 distance = next_distance;
419 if (r->position() > distance) {
420 r->set_position (r->position() - distance);
424 _session->add_command (new StatefulDiffCommand (r));
427 commit_reversible_command ();
429 } else if (!force_playhead && !selection->markers.empty()) {
433 begin_reversible_command (_("nudge location forward"));
435 for (MarkerSelection::iterator i = selection->markers.begin(); i != selection->markers.end(); ++i) {
437 Location* loc = find_location_from_marker ((*i), is_start);
441 XMLNode& before (loc->get_state());
444 distance = get_nudge_distance (loc->start(), next_distance);
446 distance = next_distance;
448 if (distance < loc->start()) {
449 loc->set_start (loc->start() - distance);
454 distance = get_nudge_distance (loc->end(), next_distance);
457 distance = next_distance;
460 if (distance < loc->end() - loc->length()) {
461 loc->set_end (loc->end() - distance);
463 loc->set_end (loc->length());
467 XMLNode& after (loc->get_state());
468 _session->add_command (new MementoCommand<Location>(*loc, &before, &after));
472 commit_reversible_command ();
476 distance = get_nudge_distance (playhead_cursor->current_frame (), next_distance);
478 if (playhead_cursor->current_frame () > distance) {
479 _session->request_locate (playhead_cursor->current_frame () - distance);
481 _session->goto_start();
487 Editor::nudge_forward_capture_offset ()
489 RegionSelection rs = get_regions_from_selection_and_entered ();
491 if (!_session || rs.empty()) {
495 begin_reversible_command (_("nudge forward"));
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());
503 r->set_position (r->position() + distance);
504 _session->add_command(new StatefulDiffCommand (r));
507 commit_reversible_command ();
511 Editor::nudge_backward_capture_offset ()
513 RegionSelection rs = get_regions_from_selection_and_entered ();
515 if (!_session || rs.empty()) {
519 begin_reversible_command (_("nudge backward"));
521 framepos_t const distance = _session->worst_output_latency();
523 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
524 boost::shared_ptr<Region> r ((*i)->region());
528 if (r->position() > distance) {
529 r->set_position (r->position() - distance);
533 _session->add_command(new StatefulDiffCommand (r));
536 commit_reversible_command ();
539 struct RegionSelectionPositionSorter {
540 bool operator() (RegionView* a, RegionView* b) {
541 return a->region()->position() < b->region()->position();
546 Editor::sequence_regions ()
549 framepos_t r_end_prev;
557 RegionSelection rs = get_regions_from_selection_and_entered ();
558 rs.sort(RegionSelectionPositionSorter());
562 begin_reversible_command (_("sequence regions"));
563 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
564 boost::shared_ptr<Region> r ((*i)->region());
572 if(r->position_locked())
579 r->set_position(r_end_prev);
582 _session->add_command (new StatefulDiffCommand (r));
584 r_end=r->position() + r->length();
588 commit_reversible_command ();
596 Editor::move_to_start ()
598 _session->goto_start ();
602 Editor::move_to_end ()
605 _session->request_locate (_session->current_end_frame());
609 Editor::build_region_boundary_cache ()
612 vector<RegionPoint> interesting_points;
613 boost::shared_ptr<Region> r;
614 TrackViewList tracks;
617 region_boundary_cache.clear ();
623 switch (_snap_type) {
624 case SnapToRegionStart:
625 interesting_points.push_back (Start);
627 case SnapToRegionEnd:
628 interesting_points.push_back (End);
630 case SnapToRegionSync:
631 interesting_points.push_back (SyncPoint);
633 case SnapToRegionBoundary:
634 interesting_points.push_back (Start);
635 interesting_points.push_back (End);
638 fatal << string_compose (_("build_region_boundary_cache called with snap_type = %1"), _snap_type) << endmsg;
643 TimeAxisView *ontrack = 0;
646 if (!selection->tracks.empty()) {
647 tlist = selection->tracks.filter_to_unique_playlists ();
649 tlist = track_views.filter_to_unique_playlists ();
652 while (pos < _session->current_end_frame() && !at_end) {
655 framepos_t lpos = max_framepos;
657 for (vector<RegionPoint>::iterator p = interesting_points.begin(); p != interesting_points.end(); ++p) {
659 if ((r = find_next_region (pos, *p, 1, tlist, &ontrack)) == 0) {
660 if (*p == interesting_points.back()) {
663 /* move to next point type */
669 rpos = r->first_frame();
673 rpos = r->last_frame();
677 rpos = r->sync_position ();
685 RouteTimeAxisView *rtav;
687 if (ontrack != 0 && (rtav = dynamic_cast<RouteTimeAxisView*>(ontrack)) != 0 ) {
688 if (rtav->track() != 0) {
689 speed = rtav->track()->speed();
693 rpos = track_frame_to_session_frame (rpos, speed);
699 /* prevent duplicates, but we don't use set<> because we want to be able
703 vector<framepos_t>::iterator ri;
705 for (ri = region_boundary_cache.begin(); ri != region_boundary_cache.end(); ++ri) {
711 if (ri == region_boundary_cache.end()) {
712 region_boundary_cache.push_back (rpos);
719 /* finally sort to be sure that the order is correct */
721 sort (region_boundary_cache.begin(), region_boundary_cache.end());
724 boost::shared_ptr<Region>
725 Editor::find_next_region (framepos_t frame, RegionPoint point, int32_t dir, TrackViewList& tracks, TimeAxisView **ontrack)
727 TrackViewList::iterator i;
728 framepos_t closest = max_framepos;
729 boost::shared_ptr<Region> ret;
733 framepos_t track_frame;
734 RouteTimeAxisView *rtav;
736 for (i = tracks.begin(); i != tracks.end(); ++i) {
739 boost::shared_ptr<Region> r;
742 if ( (rtav = dynamic_cast<RouteTimeAxisView*>(*i)) != 0 ) {
743 if (rtav->track()!=0)
744 track_speed = rtav->track()->speed();
747 track_frame = session_frame_to_track_frame(frame, track_speed);
749 if ((r = (*i)->find_next_region (track_frame, point, dir)) == 0) {
755 rpos = r->first_frame ();
759 rpos = r->last_frame ();
763 rpos = r->sync_position ();
767 // rpos is a "track frame", converting it to "_session frame"
768 rpos = track_frame_to_session_frame(rpos, track_speed);
771 distance = rpos - frame;
773 distance = frame - rpos;
776 if (distance < closest) {
788 Editor::find_next_region_boundary (framepos_t pos, int32_t dir, const TrackViewList& tracks)
790 framecnt_t distance = max_framepos;
791 framepos_t current_nearest = -1;
793 for (TrackViewList::const_iterator i = tracks.begin(); i != tracks.end(); ++i) {
794 framepos_t contender;
797 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*i);
803 if ((contender = rtv->find_next_region_boundary (pos, dir)) < 0) {
807 d = ::llabs (pos - contender);
810 current_nearest = contender;
815 return current_nearest;
819 Editor::get_region_boundary (framepos_t pos, int32_t dir, bool with_selection, bool only_onscreen)
824 if (with_selection && Config->get_region_boundaries_from_selected_tracks()) {
826 if (!selection->tracks.empty()) {
828 target = find_next_region_boundary (pos, dir, selection->tracks);
832 if (only_onscreen || Config->get_region_boundaries_from_onscreen_tracks()) {
833 get_onscreen_tracks (tvl);
834 target = find_next_region_boundary (pos, dir, tvl);
836 target = find_next_region_boundary (pos, dir, track_views);
842 if (only_onscreen || Config->get_region_boundaries_from_onscreen_tracks()) {
843 get_onscreen_tracks (tvl);
844 target = find_next_region_boundary (pos, dir, tvl);
846 target = find_next_region_boundary (pos, dir, track_views);
854 Editor::cursor_to_region_boundary (bool with_selection, int32_t dir)
856 framepos_t pos = playhead_cursor->current_frame ();
863 // so we don't find the current region again..
864 if (dir > 0 || pos > 0) {
868 if ((target = get_region_boundary (pos, dir, with_selection, false)) < 0) {
872 _session->request_locate (target);
876 Editor::cursor_to_next_region_boundary (bool with_selection)
878 cursor_to_region_boundary (with_selection, 1);
882 Editor::cursor_to_previous_region_boundary (bool with_selection)
884 cursor_to_region_boundary (with_selection, -1);
888 Editor::cursor_to_region_point (EditorCursor* cursor, RegionPoint point, int32_t dir)
890 boost::shared_ptr<Region> r;
891 framepos_t pos = cursor->current_frame ();
897 TimeAxisView *ontrack = 0;
899 // so we don't find the current region again..
903 if (!selection->tracks.empty()) {
905 r = find_next_region (pos, point, dir, selection->tracks, &ontrack);
907 } else if (clicked_axisview) {
910 t.push_back (clicked_axisview);
912 r = find_next_region (pos, point, dir, t, &ontrack);
916 r = find_next_region (pos, point, dir, track_views, &ontrack);
925 pos = r->first_frame ();
929 pos = r->last_frame ();
933 pos = r->sync_position ();
938 RouteTimeAxisView *rtav;
940 if ( ontrack != 0 && (rtav = dynamic_cast<RouteTimeAxisView*>(ontrack)) != 0 ) {
941 if (rtav->track() != 0) {
942 speed = rtav->track()->speed();
946 pos = track_frame_to_session_frame(pos, speed);
948 if (cursor == playhead_cursor) {
949 _session->request_locate (pos);
951 cursor->set_position (pos);
956 Editor::cursor_to_next_region_point (EditorCursor* cursor, RegionPoint point)
958 cursor_to_region_point (cursor, point, 1);
962 Editor::cursor_to_previous_region_point (EditorCursor* cursor, RegionPoint point)
964 cursor_to_region_point (cursor, point, -1);
968 Editor::cursor_to_selection_start (EditorCursor *cursor)
972 switch (mouse_mode) {
974 if (!selection->regions.empty()) {
975 pos = selection->regions.start();
980 if (!selection->time.empty()) {
981 pos = selection->time.start ();
989 if (cursor == playhead_cursor) {
990 _session->request_locate (pos);
992 cursor->set_position (pos);
997 Editor::cursor_to_selection_end (EditorCursor *cursor)
1001 switch (mouse_mode) {
1003 if (!selection->regions.empty()) {
1004 pos = selection->regions.end_frame();
1009 if (!selection->time.empty()) {
1010 pos = selection->time.end_frame ();
1018 if (cursor == playhead_cursor) {
1019 _session->request_locate (pos);
1021 cursor->set_position (pos);
1026 Editor::selected_marker_to_region_boundary (bool with_selection, int32_t dir)
1036 if (selection->markers.empty()) {
1040 if (!mouse_frame (mouse, ignored)) {
1044 add_location_mark (mouse);
1047 if ((loc = find_location_from_marker (selection->markers.front(), ignored)) == 0) {
1051 framepos_t pos = loc->start();
1053 // so we don't find the current region again..
1054 if (dir > 0 || pos > 0) {
1058 if ((target = get_region_boundary (pos, dir, with_selection, false)) < 0) {
1062 loc->move_to (target);
1066 Editor::selected_marker_to_next_region_boundary (bool with_selection)
1068 selected_marker_to_region_boundary (with_selection, 1);
1072 Editor::selected_marker_to_previous_region_boundary (bool with_selection)
1074 selected_marker_to_region_boundary (with_selection, -1);
1078 Editor::selected_marker_to_region_point (RegionPoint point, int32_t dir)
1080 boost::shared_ptr<Region> r;
1085 if (!_session || selection->markers.empty()) {
1089 if ((loc = find_location_from_marker (selection->markers.front(), ignored)) == 0) {
1093 TimeAxisView *ontrack = 0;
1097 // so we don't find the current region again..
1101 if (!selection->tracks.empty()) {
1103 r = find_next_region (pos, point, dir, selection->tracks, &ontrack);
1107 r = find_next_region (pos, point, dir, track_views, &ontrack);
1116 pos = r->first_frame ();
1120 pos = r->last_frame ();
1124 pos = r->adjust_to_sync (r->first_frame());
1129 RouteTimeAxisView *rtav;
1131 if (ontrack != 0 && (rtav = dynamic_cast<RouteTimeAxisView*>(ontrack)) != 0) {
1132 if (rtav->track() != 0) {
1133 speed = rtav->track()->speed();
1137 pos = track_frame_to_session_frame(pos, speed);
1143 Editor::selected_marker_to_next_region_point (RegionPoint point)
1145 selected_marker_to_region_point (point, 1);
1149 Editor::selected_marker_to_previous_region_point (RegionPoint point)
1151 selected_marker_to_region_point (point, -1);
1155 Editor::selected_marker_to_selection_start ()
1161 if (!_session || selection->markers.empty()) {
1165 if ((loc = find_location_from_marker (selection->markers.front(), ignored)) == 0) {
1169 switch (mouse_mode) {
1171 if (!selection->regions.empty()) {
1172 pos = selection->regions.start();
1177 if (!selection->time.empty()) {
1178 pos = selection->time.start ();
1190 Editor::selected_marker_to_selection_end ()
1196 if (!_session || selection->markers.empty()) {
1200 if ((loc = find_location_from_marker (selection->markers.front(), ignored)) == 0) {
1204 switch (mouse_mode) {
1206 if (!selection->regions.empty()) {
1207 pos = selection->regions.end_frame();
1212 if (!selection->time.empty()) {
1213 pos = selection->time.end_frame ();
1225 Editor::scroll_playhead (bool forward)
1227 framepos_t pos = playhead_cursor->current_frame ();
1228 framecnt_t delta = (framecnt_t) floor (current_page_samples() / 0.8);
1231 if (pos == max_framepos) {
1235 if (pos < max_framepos - delta) {
1254 _session->request_locate (pos);
1258 Editor::cursor_align (bool playhead_to_edit)
1264 if (playhead_to_edit) {
1266 if (selection->markers.empty()) {
1270 _session->request_locate (selection->markers.front()->position(), _session->transport_rolling());
1273 /* move selected markers to playhead */
1275 for (MarkerSelection::iterator i = selection->markers.begin(); i != selection->markers.end(); ++i) {
1278 Location* loc = find_location_from_marker (*i, ignored);
1280 if (loc->is_mark()) {
1281 loc->set_start (playhead_cursor->current_frame ());
1283 loc->set (playhead_cursor->current_frame (),
1284 playhead_cursor->current_frame () + loc->length());
1291 Editor::scroll_backward (float pages)
1293 framepos_t const one_page = (framepos_t) rint (_visible_canvas_width * samples_per_pixel);
1294 framepos_t const cnt = (framepos_t) floor (pages * one_page);
1297 if (leftmost_frame < cnt) {
1300 frame = leftmost_frame - cnt;
1303 reset_x_origin (frame);
1307 Editor::scroll_forward (float pages)
1309 framepos_t const one_page = (framepos_t) rint (_visible_canvas_width * samples_per_pixel);
1310 framepos_t const cnt = (framepos_t) floor (pages * one_page);
1313 if (max_framepos - cnt < leftmost_frame) {
1314 frame = max_framepos - cnt;
1316 frame = leftmost_frame + cnt;
1319 reset_x_origin (frame);
1323 Editor::scroll_tracks_down ()
1325 double vert_value = vertical_adjustment.get_value() + vertical_adjustment.get_page_size();
1326 if (vert_value > vertical_adjustment.get_upper() - _visible_canvas_height) {
1327 vert_value = vertical_adjustment.get_upper() - _visible_canvas_height;
1330 vertical_adjustment.set_value (vert_value);
1334 Editor::scroll_tracks_up ()
1336 vertical_adjustment.set_value (vertical_adjustment.get_value() - vertical_adjustment.get_page_size());
1340 Editor::scroll_tracks_down_line ()
1342 double vert_value = vertical_adjustment.get_value() + 60;
1344 if (vert_value > vertical_adjustment.get_upper() - _visible_canvas_height) {
1345 vert_value = vertical_adjustment.get_upper() - _visible_canvas_height;
1348 vertical_adjustment.set_value (vert_value);
1352 Editor::scroll_tracks_up_line ()
1354 reset_y_origin (vertical_adjustment.get_value() - 60);
1358 Editor::scroll_down_one_track ()
1360 TrackViewList::reverse_iterator next = track_views.rend();
1361 std::pair<TimeAxisView*,double> res;
1362 const double bottom_of_trackviews = vertical_adjustment.get_value() + vertical_adjustment.get_page_size() - 1;
1364 for (TrackViewList::reverse_iterator t = track_views.rbegin(); t != track_views.rend(); ++t) {
1365 if ((*t)->hidden()) {
1369 /* If this is the bottom visible trackview, we want to display
1373 res = (*t)->covers_y_position (bottom_of_trackviews);
1379 ++next; // moves "next" towards the "front" since it is a reverse iterator
1382 /* move to the track below the first one that covers the */
1384 if (next != track_views.rend()) {
1385 ensure_time_axis_view_is_visible (**next);
1393 Editor::scroll_up_one_track ()
1395 double vertical_pos = vertical_adjustment.get_value ();
1397 TrackViewList::iterator prev = track_views.end();
1398 std::pair<TimeAxisView*,double> res;
1400 for (TrackViewList::iterator t = track_views.begin(); t != track_views.end(); ++t) {
1402 if ((*t)->hidden()) {
1406 /* find the trackview at the top of the trackview group */
1407 res = (*t)->covers_y_position (vertical_pos);
1410 cerr << res.first->name() << " covers the top\n";
1417 if (prev != track_views.end()) {
1418 ensure_time_axis_view_is_visible (**prev);
1428 Editor::tav_zoom_step (bool coarser)
1430 DisplaySuspender ds;
1434 if (selection->tracks.empty()) {
1437 ts = &selection->tracks;
1440 for (TrackViewList::iterator i = ts->begin(); i != ts->end(); ++i) {
1441 TimeAxisView *tv = (static_cast<TimeAxisView*>(*i));
1442 tv->step_height (coarser);
1447 Editor::tav_zoom_smooth (bool coarser, bool force_all)
1449 DisplaySuspender ds;
1453 if (selection->tracks.empty() || force_all) {
1456 ts = &selection->tracks;
1459 for (TrackViewList::iterator i = ts->begin(); i != ts->end(); ++i) {
1460 TimeAxisView *tv = (static_cast<TimeAxisView*>(*i));
1461 uint32_t h = tv->current_height ();
1466 if (h >= TimeAxisView::preset_height (HeightSmall)) {
1471 tv->set_height (h + 5);
1478 Editor::temporal_zoom_step (bool coarser)
1480 ENSURE_GUI_THREAD (*this, &Editor::temporal_zoom_step, coarser)
1482 framecnt_t nspp = samples_per_pixel;
1490 temporal_zoom (nspp);
1494 Editor::temporal_zoom (framecnt_t fpp)
1500 framepos_t current_page = current_page_samples();
1501 framepos_t current_leftmost = leftmost_frame;
1502 framepos_t current_rightmost;
1503 framepos_t current_center;
1504 framepos_t new_page_size;
1505 framepos_t half_page_size;
1506 framepos_t leftmost_after_zoom = 0;
1508 bool in_track_canvas;
1512 if (fpp == samples_per_pixel) {
1516 // Imposing an arbitrary limit to zoom out as too much zoom out produces
1517 // segfaults for lack of memory. If somebody decides this is not high enough I
1518 // believe it can be raisen to higher values but some limit must be in place.
1520 // This constant represents 1 day @ 48kHz on a 1600 pixel wide display
1521 // all of which is used for the editor track displays. The whole day
1522 // would be 4147200000 samples, so 2592000 samples per pixel.
1524 nfpp = min (fpp, (framecnt_t) 2592000);
1525 nfpp = max ((framecnt_t) 1, fpp);
1527 new_page_size = (framepos_t) floor (_visible_canvas_width * nfpp);
1528 half_page_size = new_page_size / 2;
1530 switch (zoom_focus) {
1532 leftmost_after_zoom = current_leftmost;
1535 case ZoomFocusRight:
1536 current_rightmost = leftmost_frame + current_page;
1537 if (current_rightmost < new_page_size) {
1538 leftmost_after_zoom = 0;
1540 leftmost_after_zoom = current_rightmost - new_page_size;
1544 case ZoomFocusCenter:
1545 current_center = current_leftmost + (current_page/2);
1546 if (current_center < half_page_size) {
1547 leftmost_after_zoom = 0;
1549 leftmost_after_zoom = current_center - half_page_size;
1553 case ZoomFocusPlayhead:
1554 /* centre playhead */
1555 l = playhead_cursor->current_frame () - (new_page_size * 0.5);
1558 leftmost_after_zoom = 0;
1559 } else if (l > max_framepos) {
1560 leftmost_after_zoom = max_framepos - new_page_size;
1562 leftmost_after_zoom = (framepos_t) l;
1566 case ZoomFocusMouse:
1567 /* try to keep the mouse over the same point in the display */
1569 if (!mouse_frame (where, in_track_canvas)) {
1570 /* use playhead instead */
1571 where = playhead_cursor->current_frame ();
1573 if (where < half_page_size) {
1574 leftmost_after_zoom = 0;
1576 leftmost_after_zoom = where - half_page_size;
1581 l = - ((new_page_size * ((where - current_leftmost)/(double)current_page)) - where);
1584 leftmost_after_zoom = 0;
1585 } else if (l > max_framepos) {
1586 leftmost_after_zoom = max_framepos - new_page_size;
1588 leftmost_after_zoom = (framepos_t) l;
1595 /* try to keep the edit point in the same place */
1596 where = get_preferred_edit_position ();
1600 double l = - ((new_page_size * ((where - current_leftmost)/(double)current_page)) - where);
1603 leftmost_after_zoom = 0;
1604 } else if (l > max_framepos) {
1605 leftmost_after_zoom = max_framepos - new_page_size;
1607 leftmost_after_zoom = (framepos_t) l;
1611 /* edit point not defined */
1618 // leftmost_after_zoom = min (leftmost_after_zoom, _session->current_end_frame());
1620 reposition_and_zoom (leftmost_after_zoom, nfpp);
1624 Editor::temporal_zoom_region (bool both_axes)
1626 framepos_t start = max_framepos;
1628 set<TimeAxisView*> tracks;
1630 RegionSelection rs = get_regions_from_selection_and_entered ();
1636 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
1638 if ((*i)->region()->position() < start) {
1639 start = (*i)->region()->position();
1642 if ((*i)->region()->last_frame() + 1 > end) {
1643 end = (*i)->region()->last_frame() + 1;
1646 tracks.insert (&((*i)->get_time_axis_view()));
1649 /* now comes an "interesting" hack ... make sure we leave a little space
1650 at each end of the editor so that the zoom doesn't fit the region
1651 precisely to the screen.
1654 GdkScreen* screen = gdk_screen_get_default ();
1655 gint pixwidth = gdk_screen_get_width (screen);
1656 gint mmwidth = gdk_screen_get_width_mm (screen);
1657 double pix_per_mm = (double) pixwidth/ (double) mmwidth;
1658 double one_centimeter_in_pixels = pix_per_mm * 10.0;
1660 if ((start == 0 && end == 0) || end < start) {
1664 framepos_t range = end - start;
1665 double new_fpp = (double) range / (double) _visible_canvas_width;
1666 framepos_t extra_samples = (framepos_t) floor (one_centimeter_in_pixels * new_fpp);
1668 if (start > extra_samples) {
1669 start -= extra_samples;
1674 if (max_framepos - extra_samples > end) {
1675 end += extra_samples;
1680 /* if we're zooming on both axes we need to save track heights etc.
1683 undo_visual_stack.push_back (current_visual_state (both_axes));
1685 PBD::Unwinder<bool> nsv (no_save_visual, true);
1687 temporal_zoom_by_frame (start, end);
1690 uint32_t per_track_height = (uint32_t) floor ((_visible_canvas_height - 10.0) / tracks.size());
1692 /* set visible track heights appropriately */
1694 for (set<TimeAxisView*>::iterator t = tracks.begin(); t != tracks.end(); ++t) {
1695 (*t)->set_height (per_track_height);
1698 /* hide irrelevant tracks */
1700 DisplaySuspender ds;
1702 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1703 if (find (tracks.begin(), tracks.end(), (*i)) == tracks.end()) {
1704 hide_track_in_display (*i);
1708 vertical_adjustment.set_value (0.0);
1711 redo_visual_stack.push_back (current_visual_state (both_axes));
1715 Editor::zoom_to_region (bool both_axes)
1717 temporal_zoom_region (both_axes);
1721 Editor::temporal_zoom_selection ()
1723 if (!selection) return;
1725 if (selection->time.empty()) {
1729 framepos_t start = selection->time[clicked_selection].start;
1730 framepos_t end = selection->time[clicked_selection].end;
1732 temporal_zoom_by_frame (start, end);
1736 Editor::temporal_zoom_session ()
1738 ENSURE_GUI_THREAD (*this, &Editor::temporal_zoom_session)
1741 framecnt_t const l = _session->current_end_frame() - _session->current_start_frame();
1742 double s = _session->current_start_frame() - l * 0.01;
1746 framecnt_t const e = _session->current_end_frame() + l * 0.01;
1747 temporal_zoom_by_frame (framecnt_t (s), e);
1752 Editor::temporal_zoom_by_frame (framepos_t start, framepos_t end)
1754 if (!_session) return;
1756 if ((start == 0 && end == 0) || end < start) {
1760 framepos_t range = end - start;
1762 double const new_fpp = (double) range / (double) _visible_canvas_width;
1764 framepos_t new_page = (framepos_t) floor (_visible_canvas_width * new_fpp);
1765 framepos_t middle = (framepos_t) floor ((double) start + ((double) range / 2.0f));
1766 framepos_t new_leftmost = (framepos_t) floor ((double) middle - ((double) new_page / 2.0f));
1768 if (new_leftmost > middle) {
1772 if (new_leftmost < 0) {
1776 reposition_and_zoom (new_leftmost, new_fpp);
1780 Editor::temporal_zoom_to_frame (bool coarser, framepos_t frame)
1786 framecnt_t range_before = frame - leftmost_frame;
1790 if (samples_per_pixel <= 1) {
1793 new_spp = samples_per_pixel + (samples_per_pixel/2);
1795 range_before += range_before/2;
1797 if (samples_per_pixel >= 1) {
1798 new_spp = samples_per_pixel - (samples_per_pixel/2);
1800 /* could bail out here since we cannot zoom any finer,
1801 but leave that to the equality test below
1803 new_spp = samples_per_pixel;
1806 range_before -= range_before/2;
1809 if (new_spp == samples_per_pixel) {
1813 /* zoom focus is automatically taken as @param frame when this
1817 framepos_t new_leftmost = frame - (framepos_t)range_before;
1819 if (new_leftmost > frame) {
1823 if (new_leftmost < 0) {
1827 reposition_and_zoom (new_leftmost, new_spp);
1832 Editor::choose_new_marker_name(string &name) {
1834 if (!Config->get_name_new_markers()) {
1835 /* don't prompt user for a new name */
1839 ArdourPrompter dialog (true);
1841 dialog.set_prompt (_("New Name:"));
1843 dialog.set_title (_("New Location Marker"));
1845 dialog.set_name ("MarkNameWindow");
1846 dialog.set_size_request (250, -1);
1847 dialog.set_position (Gtk::WIN_POS_MOUSE);
1849 dialog.add_button (Stock::OK, RESPONSE_ACCEPT);
1850 dialog.set_initial_text (name);
1854 switch (dialog.run ()) {
1855 case RESPONSE_ACCEPT:
1861 dialog.get_result(name);
1868 Editor::add_location_from_selection ()
1872 if (selection->time.empty()) {
1876 if (_session == 0 || clicked_axisview == 0) {
1880 framepos_t start = selection->time[clicked_selection].start;
1881 framepos_t end = selection->time[clicked_selection].end;
1883 _session->locations()->next_available_name(rangename,"selection");
1884 Location *location = new Location (*_session, start, end, rangename, Location::IsRangeMarker);
1886 _session->begin_reversible_command (_("add marker"));
1887 XMLNode &before = _session->locations()->get_state();
1888 _session->locations()->add (location, true);
1889 XMLNode &after = _session->locations()->get_state();
1890 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
1891 _session->commit_reversible_command ();
1895 Editor::add_location_mark (framepos_t where)
1899 select_new_marker = true;
1901 _session->locations()->next_available_name(markername,"mark");
1902 if (!choose_new_marker_name(markername)) {
1905 Location *location = new Location (*_session, where, where, markername, Location::IsMark);
1906 _session->begin_reversible_command (_("add marker"));
1907 XMLNode &before = _session->locations()->get_state();
1908 _session->locations()->add (location, true);
1909 XMLNode &after = _session->locations()->get_state();
1910 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
1911 _session->commit_reversible_command ();
1915 Editor::add_location_from_playhead_cursor ()
1917 add_location_mark (_session->audible_frame());
1921 Editor::remove_location_at_playhead_cursor ()
1926 _session->begin_reversible_command (_("remove marker"));
1927 XMLNode &before = _session->locations()->get_state();
1928 bool removed = false;
1930 //find location(s) at this time
1931 Locations::LocationList locs;
1932 _session->locations()->find_all_between (_session->audible_frame(), _session->audible_frame()+1, locs, Location::Flags(0));
1933 for (Locations::LocationList::iterator i = locs.begin(); i != locs.end(); ++i) {
1934 if ((*i)->is_mark()) {
1935 _session->locations()->remove (*i);
1942 XMLNode &after = _session->locations()->get_state();
1943 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
1944 _session->commit_reversible_command ();
1949 /** Add a range marker around each selected region */
1951 Editor::add_locations_from_region ()
1953 RegionSelection rs = get_regions_from_selection_and_entered ();
1959 _session->begin_reversible_command (selection->regions.size () > 1 ? _("add markers") : _("add marker"));
1960 XMLNode &before = _session->locations()->get_state();
1962 for (RegionSelection::iterator i = rs.begin (); i != rs.end (); ++i) {
1964 boost::shared_ptr<Region> region = (*i)->region ();
1966 Location *location = new Location (*_session, region->position(), region->last_frame(), region->name(), Location::IsRangeMarker);
1968 _session->locations()->add (location, true);
1971 XMLNode &after = _session->locations()->get_state();
1972 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
1973 _session->commit_reversible_command ();
1976 /** Add a single range marker around all selected regions */
1978 Editor::add_location_from_region ()
1980 RegionSelection rs = get_regions_from_selection_and_entered ();
1986 _session->begin_reversible_command (_("add marker"));
1987 XMLNode &before = _session->locations()->get_state();
1991 if (rs.size() > 1) {
1992 _session->locations()->next_available_name(markername, "regions");
1994 RegionView* rv = *(rs.begin());
1995 boost::shared_ptr<Region> region = rv->region();
1996 markername = region->name();
1999 if (!choose_new_marker_name(markername)) {
2003 // single range spanning all selected
2004 Location *location = new Location (*_session, selection->regions.start(), selection->regions.end_frame(), markername, Location::IsRangeMarker);
2005 _session->locations()->add (location, true);
2007 XMLNode &after = _session->locations()->get_state();
2008 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2009 _session->commit_reversible_command ();
2015 Editor::jump_forward_to_mark ()
2021 framepos_t pos = _session->locations()->first_mark_after (playhead_cursor->current_frame());
2027 _session->request_locate (pos, _session->transport_rolling());
2031 Editor::jump_backward_to_mark ()
2037 framepos_t pos = _session->locations()->first_mark_before (playhead_cursor->current_frame());
2043 _session->request_locate (pos, _session->transport_rolling());
2049 framepos_t const pos = _session->audible_frame ();
2052 _session->locations()->next_available_name (markername, "mark");
2054 if (!choose_new_marker_name (markername)) {
2058 _session->locations()->add (new Location (*_session, pos, 0, markername, Location::IsMark), true);
2062 Editor::clear_markers ()
2065 _session->begin_reversible_command (_("clear markers"));
2066 XMLNode &before = _session->locations()->get_state();
2067 _session->locations()->clear_markers ();
2068 XMLNode &after = _session->locations()->get_state();
2069 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2070 _session->commit_reversible_command ();
2075 Editor::clear_ranges ()
2078 _session->begin_reversible_command (_("clear ranges"));
2079 XMLNode &before = _session->locations()->get_state();
2081 Location * looploc = _session->locations()->auto_loop_location();
2082 Location * punchloc = _session->locations()->auto_punch_location();
2083 Location * sessionloc = _session->locations()->session_range_location();
2085 _session->locations()->clear_ranges ();
2087 if (looploc) _session->locations()->add (looploc);
2088 if (punchloc) _session->locations()->add (punchloc);
2089 if (sessionloc) _session->locations()->add (sessionloc);
2091 XMLNode &after = _session->locations()->get_state();
2092 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2093 _session->commit_reversible_command ();
2098 Editor::clear_locations ()
2100 _session->begin_reversible_command (_("clear locations"));
2101 XMLNode &before = _session->locations()->get_state();
2102 _session->locations()->clear ();
2103 XMLNode &after = _session->locations()->get_state();
2104 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2105 _session->commit_reversible_command ();
2106 _session->locations()->clear ();
2110 Editor::unhide_markers ()
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_mark()) {
2115 l->set_hidden(false, this);
2121 Editor::unhide_ranges ()
2123 for (LocationMarkerMap::iterator i = location_markers.begin(); i != location_markers.end(); ++i) {
2124 Location *l = (*i).first;
2125 if (l->is_hidden() && l->is_range_marker()) {
2126 l->set_hidden(false, this);
2131 /* INSERT/REPLACE */
2134 Editor::insert_region_list_selection (float times)
2136 RouteTimeAxisView *tv = 0;
2137 boost::shared_ptr<Playlist> playlist;
2139 if (clicked_routeview != 0) {
2140 tv = clicked_routeview;
2141 } else if (!selection->tracks.empty()) {
2142 if ((tv = dynamic_cast<RouteTimeAxisView*>(selection->tracks.front())) == 0) {
2145 } else if (entered_track != 0) {
2146 if ((tv = dynamic_cast<RouteTimeAxisView*>(entered_track)) == 0) {
2153 if ((playlist = tv->playlist()) == 0) {
2157 boost::shared_ptr<Region> region = _regions->get_single_selection ();
2162 begin_reversible_command (_("insert region"));
2163 playlist->clear_changes ();
2164 playlist->add_region ((RegionFactory::create (region, true)), get_preferred_edit_position(), times);
2165 if (Config->get_edit_mode() == Ripple)
2166 playlist->ripple (get_preferred_edit_position(), region->length() * times, boost::shared_ptr<Region>());
2168 _session->add_command(new StatefulDiffCommand (playlist));
2169 commit_reversible_command ();
2172 /* BUILT-IN EFFECTS */
2175 Editor::reverse_selection ()
2180 /* GAIN ENVELOPE EDITING */
2183 Editor::edit_envelope ()
2190 Editor::transition_to_rolling (bool fwd)
2196 if (_session->config.get_external_sync()) {
2197 switch (Config->get_sync_source()) {
2201 /* transport controlled by the master */
2206 if (_session->is_auditioning()) {
2207 _session->cancel_audition ();
2211 _session->request_transport_speed (fwd ? 1.0f : -1.0f);
2215 Editor::play_from_start ()
2217 _session->request_locate (_session->current_start_frame(), true);
2221 Editor::play_from_edit_point ()
2223 _session->request_locate (get_preferred_edit_position(), true);
2227 Editor::play_from_edit_point_and_return ()
2229 framepos_t start_frame;
2230 framepos_t return_frame;
2232 start_frame = get_preferred_edit_position (true);
2234 if (_session->transport_rolling()) {
2235 _session->request_locate (start_frame, false);
2239 /* don't reset the return frame if its already set */
2241 if ((return_frame = _session->requested_return_frame()) < 0) {
2242 return_frame = _session->audible_frame();
2245 if (start_frame >= 0) {
2246 _session->request_roll_at_and_return (start_frame, return_frame);
2251 Editor::play_selection ()
2253 if (selection->time.empty()) {
2257 _session->request_play_range (&selection->time, true);
2261 Editor::get_preroll ()
2263 return 1.0 /*Config->get_edit_preroll_seconds()*/ * _session->frame_rate();
2268 Editor::maybe_locate_with_edit_preroll ( framepos_t location )
2270 if ( _session->transport_rolling() || !Config->get_follow_edits() )
2273 location -= get_preroll();
2275 //don't try to locate before the beginning of time
2279 //if follow_playhead is on, keep the playhead on the screen
2280 if ( _follow_playhead )
2281 if ( location < leftmost_frame )
2282 location = leftmost_frame;
2284 _session->request_locate( location );
2288 Editor::play_with_preroll ()
2290 if (selection->time.empty()) {
2293 framepos_t preroll = get_preroll();
2295 framepos_t start = 0;
2296 if (selection->time[clicked_selection].start > preroll)
2297 start = selection->time[clicked_selection].start - preroll;
2299 framepos_t end = selection->time[clicked_selection].end + preroll;
2301 AudioRange ar (start, end, 0);
2302 list<AudioRange> lar;
2305 _session->request_play_range (&lar, true);
2310 Editor::play_location (Location& location)
2312 if (location.start() <= location.end()) {
2316 _session->request_bounded_roll (location.start(), location.end());
2320 Editor::loop_location (Location& location)
2322 if (location.start() <= location.end()) {
2328 if ((tll = transport_loop_location()) != 0) {
2329 tll->set (location.start(), location.end());
2331 // enable looping, reposition and start rolling
2332 _session->request_play_loop (true);
2333 _session->request_locate (tll->start(), true);
2338 Editor::do_layer_operation (LayerOperation op)
2340 if (selection->regions.empty ()) {
2344 bool const multiple = selection->regions.size() > 1;
2348 begin_reversible_command (_("raise regions"));
2350 begin_reversible_command (_("raise region"));
2356 begin_reversible_command (_("raise regions to top"));
2358 begin_reversible_command (_("raise region to top"));
2364 begin_reversible_command (_("lower regions"));
2366 begin_reversible_command (_("lower region"));
2372 begin_reversible_command (_("lower regions to bottom"));
2374 begin_reversible_command (_("lower region"));
2379 set<boost::shared_ptr<Playlist> > playlists = selection->regions.playlists ();
2380 for (set<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
2381 (*i)->clear_owned_changes ();
2384 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
2385 boost::shared_ptr<Region> r = (*i)->region ();
2397 r->lower_to_bottom ();
2401 for (set<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
2402 vector<Command*> cmds;
2404 _session->add_commands (cmds);
2407 commit_reversible_command ();
2411 Editor::raise_region ()
2413 do_layer_operation (Raise);
2417 Editor::raise_region_to_top ()
2419 do_layer_operation (RaiseToTop);
2423 Editor::lower_region ()
2425 do_layer_operation (Lower);
2429 Editor::lower_region_to_bottom ()
2431 do_layer_operation (LowerToBottom);
2434 /** Show the region editor for the selected regions */
2436 Editor::show_region_properties ()
2438 selection->foreach_regionview (&RegionView::show_region_editor);
2441 /** Show the midi list editor for the selected MIDI regions */
2443 Editor::show_midi_list_editor ()
2445 selection->foreach_midi_regionview (&MidiRegionView::show_list_editor);
2449 Editor::rename_region ()
2451 RegionSelection rs = get_regions_from_selection_and_entered ();
2457 ArdourDialog d (*this, _("Rename Region"), true, false);
2459 Label label (_("New name:"));
2462 hbox.set_spacing (6);
2463 hbox.pack_start (label, false, false);
2464 hbox.pack_start (entry, true, true);
2466 d.get_vbox()->set_border_width (12);
2467 d.get_vbox()->pack_start (hbox, false, false);
2469 d.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
2470 d.add_button(Gtk::Stock::OK, Gtk::RESPONSE_OK);
2472 d.set_size_request (300, -1);
2474 entry.set_text (rs.front()->region()->name());
2475 entry.select_region (0, -1);
2477 entry.signal_activate().connect (sigc::bind (sigc::mem_fun (d, &Dialog::response), RESPONSE_OK));
2483 int const ret = d.run();
2487 if (ret != RESPONSE_OK) {
2491 std::string str = entry.get_text();
2492 strip_whitespace_edges (str);
2494 rs.front()->region()->set_name (str);
2495 _regions->redisplay ();
2500 Editor::audition_playlist_region_via_route (boost::shared_ptr<Region> region, Route& route)
2502 if (_session->is_auditioning()) {
2503 _session->cancel_audition ();
2506 // note: some potential for creativity here, because region doesn't
2507 // have to belong to the playlist that Route is handling
2509 // bool was_soloed = route.soloed();
2511 route.set_solo (true, this);
2513 _session->request_bounded_roll (region->position(), region->position() + region->length());
2515 /* XXX how to unset the solo state ? */
2518 /** Start an audition of the first selected region */
2520 Editor::play_edit_range ()
2522 framepos_t start, end;
2524 if (get_edit_op_range (start, end)) {
2525 _session->request_bounded_roll (start, end);
2530 Editor::play_selected_region ()
2532 framepos_t start = max_framepos;
2535 RegionSelection rs = get_regions_from_selection_and_entered ();
2541 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
2542 if ((*i)->region()->position() < start) {
2543 start = (*i)->region()->position();
2545 if ((*i)->region()->last_frame() + 1 > end) {
2546 end = (*i)->region()->last_frame() + 1;
2550 _session->request_bounded_roll (start, end);
2554 Editor::audition_playlist_region_standalone (boost::shared_ptr<Region> region)
2556 _session->audition_region (region);
2560 Editor::region_from_selection ()
2562 if (clicked_axisview == 0) {
2566 if (selection->time.empty()) {
2570 framepos_t start = selection->time[clicked_selection].start;
2571 framepos_t end = selection->time[clicked_selection].end;
2573 TrackViewList tracks = get_tracks_for_range_action ();
2575 framepos_t selection_cnt = end - start + 1;
2577 for (TrackSelection::iterator i = tracks.begin(); i != tracks.end(); ++i) {
2578 boost::shared_ptr<Region> current;
2579 boost::shared_ptr<Playlist> pl;
2580 framepos_t internal_start;
2583 if ((pl = (*i)->playlist()) == 0) {
2587 if ((current = pl->top_region_at (start)) == 0) {
2591 internal_start = start - current->position();
2592 RegionFactory::region_name (new_name, current->name(), true);
2596 plist.add (ARDOUR::Properties::start, current->start() + internal_start);
2597 plist.add (ARDOUR::Properties::length, selection_cnt);
2598 plist.add (ARDOUR::Properties::name, new_name);
2599 plist.add (ARDOUR::Properties::layer, 0);
2601 boost::shared_ptr<Region> region (RegionFactory::create (current, plist));
2606 Editor::create_region_from_selection (vector<boost::shared_ptr<Region> >& new_regions)
2608 if (selection->time.empty() || selection->tracks.empty()) {
2612 framepos_t start = selection->time[clicked_selection].start;
2613 framepos_t end = selection->time[clicked_selection].end;
2615 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
2616 sort_track_selection (ts);
2618 for (TrackSelection::iterator i = ts.begin(); i != ts.end(); ++i) {
2619 boost::shared_ptr<Region> current;
2620 boost::shared_ptr<Playlist> playlist;
2621 framepos_t internal_start;
2624 if ((playlist = (*i)->playlist()) == 0) {
2628 if ((current = playlist->top_region_at(start)) == 0) {
2632 internal_start = start - current->position();
2633 RegionFactory::region_name (new_name, current->name(), true);
2637 plist.add (ARDOUR::Properties::start, current->start() + internal_start);
2638 plist.add (ARDOUR::Properties::length, end - start + 1);
2639 plist.add (ARDOUR::Properties::name, new_name);
2641 new_regions.push_back (RegionFactory::create (current, plist));
2646 Editor::split_multichannel_region ()
2648 RegionSelection rs = get_regions_from_selection_and_entered ();
2654 vector< boost::shared_ptr<Region> > v;
2656 for (list<RegionView*>::iterator x = rs.begin(); x != rs.end(); ++x) {
2657 (*x)->region()->separate_by_channel (*_session, v);
2662 Editor::new_region_from_selection ()
2664 region_from_selection ();
2665 cancel_selection ();
2669 add_if_covered (RegionView* rv, const AudioRange* ar, RegionSelection* rs)
2671 switch (rv->region()->coverage (ar->start, ar->end - 1)) {
2672 case Evoral::OverlapNone:
2680 * - selected tracks, or if there are none...
2681 * - tracks containing selected regions, or if there are none...
2686 Editor::get_tracks_for_range_action () const
2690 if (selection->tracks.empty()) {
2692 /* use tracks with selected regions */
2694 RegionSelection rs = selection->regions;
2696 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
2697 TimeAxisView* tv = &(*i)->get_time_axis_view();
2699 if (!t.contains (tv)) {
2705 /* no regions and no tracks: use all tracks */
2711 t = selection->tracks;
2714 return t.filter_to_unique_playlists();
2718 Editor::separate_regions_between (const TimeSelection& ts)
2720 bool in_command = false;
2721 boost::shared_ptr<Playlist> playlist;
2722 RegionSelection new_selection;
2724 TrackViewList tmptracks = get_tracks_for_range_action ();
2725 sort_track_selection (tmptracks);
2727 for (TrackSelection::iterator i = tmptracks.begin(); i != tmptracks.end(); ++i) {
2729 RouteTimeAxisView* rtv;
2731 if ((rtv = dynamic_cast<RouteTimeAxisView*> ((*i))) != 0) {
2733 if (rtv->is_track()) {
2735 /* no edits to destructive tracks */
2737 if (rtv->track()->destructive()) {
2741 if ((playlist = rtv->playlist()) != 0) {
2743 playlist->clear_changes ();
2745 /* XXX need to consider musical time selections here at some point */
2747 double speed = rtv->track()->speed();
2750 for (list<AudioRange>::const_iterator t = ts.begin(); t != ts.end(); ++t) {
2752 sigc::connection c = rtv->view()->RegionViewAdded.connect (
2753 sigc::mem_fun(*this, &Editor::collect_new_region_view));
2755 latest_regionviews.clear ();
2757 playlist->partition ((framepos_t)((*t).start * speed),
2758 (framepos_t)((*t).end * speed), false);
2762 if (!latest_regionviews.empty()) {
2764 rtv->view()->foreach_regionview (sigc::bind (
2765 sigc::ptr_fun (add_if_covered),
2766 &(*t), &new_selection));
2769 begin_reversible_command (_("separate"));
2773 /* pick up changes to existing regions */
2775 vector<Command*> cmds;
2776 playlist->rdiff (cmds);
2777 _session->add_commands (cmds);
2779 /* pick up changes to the playlist itself (adds/removes)
2782 _session->add_command(new StatefulDiffCommand (playlist));
2791 selection->set (new_selection);
2793 commit_reversible_command ();
2797 struct PlaylistState {
2798 boost::shared_ptr<Playlist> playlist;
2802 /** Take tracks from get_tracks_for_range_action and cut any regions
2803 * on those tracks so that the tracks are empty over the time
2807 Editor::separate_region_from_selection ()
2809 /* preferentially use *all* ranges in the time selection if we're in range mode
2810 to allow discontiguous operation, since get_edit_op_range() currently
2811 returns a single range.
2814 if (!selection->time.empty()) {
2816 separate_regions_between (selection->time);
2823 if (get_edit_op_range (start, end)) {
2825 AudioRange ar (start, end, 1);
2829 separate_regions_between (ts);
2835 Editor::separate_region_from_punch ()
2837 Location* loc = _session->locations()->auto_punch_location();
2839 separate_regions_using_location (*loc);
2844 Editor::separate_region_from_loop ()
2846 Location* loc = _session->locations()->auto_loop_location();
2848 separate_regions_using_location (*loc);
2853 Editor::separate_regions_using_location (Location& loc)
2855 if (loc.is_mark()) {
2859 AudioRange ar (loc.start(), loc.end(), 1);
2864 separate_regions_between (ts);
2867 /** Separate regions under the selected region */
2869 Editor::separate_under_selected_regions ()
2871 vector<PlaylistState> playlists;
2875 rs = get_regions_from_selection_and_entered();
2877 if (!_session || rs.empty()) {
2881 begin_reversible_command (_("separate region under"));
2883 list<boost::shared_ptr<Region> > regions_to_remove;
2885 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
2886 // we can't just remove the region(s) in this loop because
2887 // this removes them from the RegionSelection, and they thus
2888 // disappear from underneath the iterator, and the ++i above
2889 // SEGVs in a puzzling fashion.
2891 // so, first iterate over the regions to be removed from rs and
2892 // add them to the regions_to_remove list, and then
2893 // iterate over the list to actually remove them.
2895 regions_to_remove.push_back ((*i)->region());
2898 for (list<boost::shared_ptr<Region> >::iterator rl = regions_to_remove.begin(); rl != regions_to_remove.end(); ++rl) {
2900 boost::shared_ptr<Playlist> playlist = (*rl)->playlist();
2903 // is this check necessary?
2907 vector<PlaylistState>::iterator i;
2909 //only take state if this is a new playlist.
2910 for (i = playlists.begin(); i != playlists.end(); ++i) {
2911 if ((*i).playlist == playlist) {
2916 if (i == playlists.end()) {
2918 PlaylistState before;
2919 before.playlist = playlist;
2920 before.before = &playlist->get_state();
2922 playlist->freeze ();
2923 playlists.push_back(before);
2926 //Partition on the region bounds
2927 playlist->partition ((*rl)->first_frame() - 1, (*rl)->last_frame() + 1, true);
2929 //Re-add region that was just removed due to the partition operation
2930 playlist->add_region( (*rl), (*rl)->first_frame() );
2933 vector<PlaylistState>::iterator pl;
2935 for (pl = playlists.begin(); pl != playlists.end(); ++pl) {
2936 (*pl).playlist->thaw ();
2937 _session->add_command(new MementoCommand<Playlist>(*(*pl).playlist, (*pl).before, &(*pl).playlist->get_state()));
2940 commit_reversible_command ();
2944 Editor::crop_region_to_selection ()
2946 if (!selection->time.empty()) {
2948 crop_region_to (selection->time.start(), selection->time.end_frame());
2955 if (get_edit_op_range (start, end)) {
2956 crop_region_to (start, end);
2963 Editor::crop_region_to (framepos_t start, framepos_t end)
2965 vector<boost::shared_ptr<Playlist> > playlists;
2966 boost::shared_ptr<Playlist> playlist;
2969 if (selection->tracks.empty()) {
2970 ts = track_views.filter_to_unique_playlists();
2972 ts = selection->tracks.filter_to_unique_playlists ();
2975 sort_track_selection (ts);
2977 for (TrackSelection::iterator i = ts.begin(); i != ts.end(); ++i) {
2979 RouteTimeAxisView* rtv;
2981 if ((rtv = dynamic_cast<RouteTimeAxisView*> ((*i))) != 0) {
2983 boost::shared_ptr<Track> t = rtv->track();
2985 if (t != 0 && ! t->destructive()) {
2987 if ((playlist = rtv->playlist()) != 0) {
2988 playlists.push_back (playlist);
2994 if (playlists.empty()) {
2998 framepos_t the_start;
3002 begin_reversible_command (_("trim to selection"));
3004 for (vector<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
3006 boost::shared_ptr<Region> region;
3010 if ((region = (*i)->top_region_at(the_start)) == 0) {
3014 /* now adjust lengths to that we do the right thing
3015 if the selection extends beyond the region
3018 the_start = max (the_start, (framepos_t) region->position());
3019 if (max_framepos - the_start < region->length()) {
3020 the_end = the_start + region->length() - 1;
3022 the_end = max_framepos;
3024 the_end = min (end, the_end);
3025 cnt = the_end - the_start + 1;
3027 region->clear_changes ();
3028 region->trim_to (the_start, cnt);
3029 _session->add_command (new StatefulDiffCommand (region));
3032 commit_reversible_command ();
3036 Editor::region_fill_track ()
3038 RegionSelection rs = get_regions_from_selection_and_entered ();
3040 if (!_session || rs.empty()) {
3044 framepos_t const end = _session->current_end_frame ();
3046 begin_reversible_command (Operations::region_fill);
3048 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3050 boost::shared_ptr<Region> region ((*i)->region());
3052 boost::shared_ptr<Playlist> pl = region->playlist();
3054 if (end <= region->last_frame()) {
3058 double times = (double) (end - region->last_frame()) / (double) region->length();
3064 pl->clear_changes ();
3065 pl->add_region (RegionFactory::create (region, true), region->last_frame(), times);
3066 _session->add_command (new StatefulDiffCommand (pl));
3069 commit_reversible_command ();
3073 Editor::region_fill_selection ()
3075 if (clicked_routeview == 0 || !clicked_routeview->is_audio_track()) {
3079 if (selection->time.empty()) {
3083 boost::shared_ptr<Region> region = _regions->get_single_selection ();
3088 framepos_t start = selection->time[clicked_selection].start;
3089 framepos_t end = selection->time[clicked_selection].end;
3091 boost::shared_ptr<Playlist> playlist;
3093 if (selection->tracks.empty()) {
3097 framepos_t selection_length = end - start;
3098 float times = (float)selection_length / region->length();
3100 begin_reversible_command (Operations::fill_selection);
3102 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
3104 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
3106 if ((playlist = (*i)->playlist()) == 0) {
3110 playlist->clear_changes ();
3111 playlist->add_region (RegionFactory::create (region, true), start, times);
3112 _session->add_command (new StatefulDiffCommand (playlist));
3115 commit_reversible_command ();
3119 Editor::set_region_sync_position ()
3121 set_sync_point (get_preferred_edit_position (), get_regions_from_selection_and_edit_point ());
3125 Editor::set_sync_point (framepos_t where, const RegionSelection& rs)
3127 bool in_command = false;
3129 for (RegionSelection::const_iterator r = rs.begin(); r != rs.end(); ++r) {
3131 if (!(*r)->region()->covers (where)) {
3135 boost::shared_ptr<Region> region ((*r)->region());
3138 begin_reversible_command (_("set sync point"));
3142 region->clear_changes ();
3143 region->set_sync_position (where);
3144 _session->add_command(new StatefulDiffCommand (region));
3148 commit_reversible_command ();
3152 /** Remove the sync positions of the selection */
3154 Editor::remove_region_sync ()
3156 RegionSelection rs = get_regions_from_selection_and_entered ();
3162 begin_reversible_command (_("remove region sync"));
3164 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3166 (*i)->region()->clear_changes ();
3167 (*i)->region()->clear_sync_position ();
3168 _session->add_command(new StatefulDiffCommand ((*i)->region()));
3171 commit_reversible_command ();
3175 Editor::naturalize_region ()
3177 RegionSelection rs = get_regions_from_selection_and_entered ();
3183 if (rs.size() > 1) {
3184 begin_reversible_command (_("move regions to original position"));
3186 begin_reversible_command (_("move region to original position"));
3189 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3190 (*i)->region()->clear_changes ();
3191 (*i)->region()->move_to_natural_position ();
3192 _session->add_command (new StatefulDiffCommand ((*i)->region()));
3195 commit_reversible_command ();
3199 Editor::align_regions (RegionPoint what)
3201 RegionSelection const rs = get_regions_from_selection_and_edit_point ();
3207 begin_reversible_command (_("align selection"));
3209 framepos_t const position = get_preferred_edit_position ();
3211 for (RegionSelection::const_iterator i = rs.begin(); i != rs.end(); ++i) {
3212 align_region_internal ((*i)->region(), what, position);
3215 commit_reversible_command ();
3218 struct RegionSortByTime {
3219 bool operator() (const RegionView* a, const RegionView* b) {
3220 return a->region()->position() < b->region()->position();
3225 Editor::align_regions_relative (RegionPoint point)
3227 RegionSelection const rs = get_regions_from_selection_and_edit_point ();
3233 framepos_t const position = get_preferred_edit_position ();
3235 framepos_t distance = 0;
3239 list<RegionView*> sorted;
3240 rs.by_position (sorted);
3242 boost::shared_ptr<Region> r ((*sorted.begin())->region());
3247 if (position > r->position()) {
3248 distance = position - r->position();
3250 distance = r->position() - position;
3256 if (position > r->last_frame()) {
3257 distance = position - r->last_frame();
3258 pos = r->position() + distance;
3260 distance = r->last_frame() - position;
3261 pos = r->position() - distance;
3267 pos = r->adjust_to_sync (position);
3268 if (pos > r->position()) {
3269 distance = pos - r->position();
3271 distance = r->position() - pos;
3277 if (pos == r->position()) {
3281 begin_reversible_command (_("align selection (relative)"));
3283 /* move first one specially */
3285 r->clear_changes ();
3286 r->set_position (pos);
3287 _session->add_command(new StatefulDiffCommand (r));
3289 /* move rest by the same amount */
3293 for (list<RegionView*>::iterator i = sorted.begin(); i != sorted.end(); ++i) {
3295 boost::shared_ptr<Region> region ((*i)->region());
3297 region->clear_changes ();
3300 region->set_position (region->position() + distance);
3302 region->set_position (region->position() - distance);
3305 _session->add_command(new StatefulDiffCommand (region));
3309 commit_reversible_command ();
3313 Editor::align_region (boost::shared_ptr<Region> region, RegionPoint point, framepos_t position)
3315 begin_reversible_command (_("align region"));
3316 align_region_internal (region, point, position);
3317 commit_reversible_command ();
3321 Editor::align_region_internal (boost::shared_ptr<Region> region, RegionPoint point, framepos_t position)
3323 region->clear_changes ();
3327 region->set_position (region->adjust_to_sync (position));
3331 if (position > region->length()) {
3332 region->set_position (position - region->length());
3337 region->set_position (position);
3341 _session->add_command(new StatefulDiffCommand (region));
3345 Editor::trim_region_front ()
3351 Editor::trim_region_back ()
3353 trim_region (false);
3357 Editor::trim_region (bool front)
3359 framepos_t where = get_preferred_edit_position();
3360 RegionSelection rs = get_regions_from_selection_and_edit_point ();
3366 begin_reversible_command (front ? _("trim front") : _("trim back"));
3368 for (list<RegionView*>::const_iterator i = rs.by_layer().begin(); i != rs.by_layer().end(); ++i) {
3369 if (!(*i)->region()->locked()) {
3371 (*i)->region()->clear_changes ();
3374 (*i)->region()->trim_front (where);
3375 maybe_locate_with_edit_preroll ( where );
3377 (*i)->region()->trim_end (where);
3378 maybe_locate_with_edit_preroll ( where );
3381 _session->add_command (new StatefulDiffCommand ((*i)->region()));
3385 commit_reversible_command ();
3388 /** Trim the end of the selected regions to the position of the edit cursor */
3390 Editor::trim_region_to_loop ()
3392 Location* loc = _session->locations()->auto_loop_location();
3396 trim_region_to_location (*loc, _("trim to loop"));
3400 Editor::trim_region_to_punch ()
3402 Location* loc = _session->locations()->auto_punch_location();
3406 trim_region_to_location (*loc, _("trim to punch"));
3410 Editor::trim_region_to_location (const Location& loc, const char* str)
3412 RegionSelection rs = get_regions_from_selection_and_entered ();
3414 begin_reversible_command (str);
3416 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
3417 RegionView* rv = (*x);
3419 /* require region to span proposed trim */
3420 switch (rv->region()->coverage (loc.start(), loc.end())) {
3421 case Evoral::OverlapInternal:
3427 RouteTimeAxisView* tav = dynamic_cast<RouteTimeAxisView*> (&rv->get_time_axis_view());
3436 if (tav->track() != 0) {
3437 speed = tav->track()->speed();
3440 start = session_frame_to_track_frame (loc.start(), speed);
3441 end = session_frame_to_track_frame (loc.end(), speed);
3443 rv->region()->clear_changes ();
3444 rv->region()->trim_to (start, (end - start));
3445 _session->add_command(new StatefulDiffCommand (rv->region()));
3448 commit_reversible_command ();
3452 Editor::trim_region_to_previous_region_end ()
3454 return trim_to_region(false);
3458 Editor::trim_region_to_next_region_start ()
3460 return trim_to_region(true);
3464 Editor::trim_to_region(bool forward)
3466 RegionSelection rs = get_regions_from_selection_and_entered ();
3468 begin_reversible_command (_("trim to region"));
3470 boost::shared_ptr<Region> next_region;
3472 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
3474 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*x);
3480 AudioTimeAxisView* atav = dynamic_cast<AudioTimeAxisView*> (&arv->get_time_axis_view());
3488 if (atav->track() != 0) {
3489 speed = atav->track()->speed();
3493 boost::shared_ptr<Region> region = arv->region();
3494 boost::shared_ptr<Playlist> playlist (region->playlist());
3496 region->clear_changes ();
3500 next_region = playlist->find_next_region (region->first_frame(), Start, 1);
3506 region->trim_end((framepos_t) ( (next_region->first_frame() - 1) * speed));
3507 arv->region_changed (PropertyChange (ARDOUR::Properties::length));
3511 next_region = playlist->find_next_region (region->first_frame(), Start, 0);
3517 region->trim_front((framepos_t) ((next_region->last_frame() + 1) * speed));
3519 arv->region_changed (ARDOUR::bounds_change);
3522 _session->add_command(new StatefulDiffCommand (region));
3525 commit_reversible_command ();
3529 Editor::unfreeze_route ()
3531 if (clicked_routeview == 0 || !clicked_routeview->is_track()) {
3535 clicked_routeview->track()->unfreeze ();
3539 Editor::_freeze_thread (void* arg)
3541 return static_cast<Editor*>(arg)->freeze_thread ();
3545 Editor::freeze_thread ()
3547 /* create event pool because we may need to talk to the session */
3548 SessionEvent::create_per_thread_pool ("freeze events", 64);
3549 /* create per-thread buffers for process() tree to use */
3550 clicked_routeview->audio_track()->freeze_me (*current_interthread_info);
3551 current_interthread_info->done = true;
3556 Editor::freeze_route ()
3562 /* stop transport before we start. this is important */
3564 _session->request_transport_speed (0.0);
3566 /* wait for just a little while, because the above call is asynchronous */
3568 Glib::usleep (250000);
3570 if (clicked_routeview == 0 || !clicked_routeview->is_audio_track()) {
3574 if (!clicked_routeview->track()->bounceable (clicked_routeview->track()->main_outs(), true)) {
3576 _("This track/bus cannot be frozen because the signal adds or loses channels before reaching the outputs.\n"
3577 "This is typically caused by plugins that generate stereo output from mono input or vice versa.")
3579 d.set_title (_("Cannot freeze"));
3584 if (clicked_routeview->track()->has_external_redirects()) {
3585 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"
3586 "Freezing will only process the signal as far as the first send/insert/return."),
3587 clicked_routeview->track()->name()), true, MESSAGE_INFO, BUTTONS_NONE, true);
3589 d.add_button (_("Freeze anyway"), Gtk::RESPONSE_OK);
3590 d.add_button (_("Don't freeze"), Gtk::RESPONSE_CANCEL);
3591 d.set_title (_("Freeze Limits"));
3593 int response = d.run ();
3596 case Gtk::RESPONSE_CANCEL:
3603 InterThreadInfo itt;
3604 current_interthread_info = &itt;
3606 InterthreadProgressWindow ipw (current_interthread_info, _("Freeze"), _("Cancel Freeze"));
3608 pthread_create_and_store (X_("freezer"), &itt.thread, _freeze_thread, this);
3610 set_canvas_cursor (_cursors->wait);
3612 while (!itt.done && !itt.cancel) {
3613 gtk_main_iteration ();
3616 current_interthread_info = 0;
3617 set_canvas_cursor (current_canvas_cursor);
3621 Editor::bounce_range_selection (bool replace, bool enable_processing)
3623 if (selection->time.empty()) {
3627 TrackSelection views = selection->tracks;
3629 for (TrackViewList::iterator i = views.begin(); i != views.end(); ++i) {
3631 if (enable_processing) {
3633 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*i);
3635 if (rtv && rtv->track() && replace && enable_processing && !rtv->track()->bounceable (rtv->track()->main_outs(), false)) {
3637 _("You can't perform this operation because the processing of the signal "
3638 "will cause one or more of the tracks to end up with a region with more channels than this track has inputs.\n\n"
3639 "You can do this without processing, which is a different operation.")
3641 d.set_title (_("Cannot bounce"));
3648 framepos_t start = selection->time[clicked_selection].start;
3649 framepos_t end = selection->time[clicked_selection].end;
3650 framepos_t cnt = end - start + 1;
3652 begin_reversible_command (_("bounce range"));
3654 for (TrackViewList::iterator i = views.begin(); i != views.end(); ++i) {
3656 RouteTimeAxisView* rtv;
3658 if ((rtv = dynamic_cast<RouteTimeAxisView*> (*i)) == 0) {
3662 boost::shared_ptr<Playlist> playlist;
3664 if ((playlist = rtv->playlist()) == 0) {
3668 InterThreadInfo itt;
3670 playlist->clear_changes ();
3671 playlist->clear_owned_changes ();
3673 boost::shared_ptr<Region> r;
3675 if (enable_processing) {
3676 r = rtv->track()->bounce_range (start, start+cnt, itt, rtv->track()->main_outs(), false);
3678 r = rtv->track()->bounce_range (start, start+cnt, itt, boost::shared_ptr<Processor>(), false);
3686 list<AudioRange> ranges;
3687 ranges.push_back (AudioRange (start, start+cnt, 0));
3688 playlist->cut (ranges); // discard result
3689 playlist->add_region (r, start);
3692 vector<Command*> cmds;
3693 playlist->rdiff (cmds);
3694 _session->add_commands (cmds);
3696 _session->add_command (new StatefulDiffCommand (playlist));
3699 commit_reversible_command ();
3702 /** Delete selected regions, automation points or a time range */
3709 /** Cut selected regions, automation points or a time range */
3716 /** Copy selected regions, automation points or a time range */
3724 /** @return true if a Cut, Copy or Clear is possible */
3726 Editor::can_cut_copy () const
3728 if (!selection->time.empty() || !selection->regions.empty() || !selection->points.empty())
3735 /** Cut, copy or clear selected regions, automation points or a time range.
3736 * @param op Operation (Delete, 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 != Delete ) //"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 if (!selection->points.empty()) {
3809 begin_reversible_command (opname + _(" points"));
3811 cut_copy_points (op);
3812 if (op == Cut || op == Delete) {
3813 selection->clear_points ();
3815 } else if (!selection->regions.empty() || !selection->points.empty()) {
3819 if (selection->regions.empty()) {
3820 thing_name = _("points");
3821 } else if (selection->points.empty()) {
3822 thing_name = _("regions");
3824 thing_name = _("objects");
3827 begin_reversible_command (opname + ' ' + thing_name);
3830 if (!selection->regions.empty()) {
3831 cut_copy_regions (op, selection->regions);
3833 if (op == Cut || op == Delete) {
3834 selection->clear_regions ();
3838 if (!selection->points.empty()) {
3839 cut_copy_points (op);
3841 if (op == Cut || op == Delete) {
3842 selection->clear_points ();
3845 } else if (selection->time.empty()) {
3846 framepos_t start, end;
3847 /* no time selection, see if we can get an edit range
3850 if (get_edit_op_range (start, end)) {
3851 selection->set (start, end);
3853 } else if (!selection->time.empty()) {
3854 begin_reversible_command (opname + _(" range"));
3857 cut_copy_ranges (op);
3859 if (op == Cut || op == Delete) {
3860 selection->clear_time ();
3865 commit_reversible_command ();
3868 if (op == Delete || op == Cut || op == Clear) {
3873 struct AutomationRecord {
3874 AutomationRecord () : state (0) {}
3875 AutomationRecord (XMLNode* s) : state (s) {}
3877 XMLNode* state; ///< state before any operation
3878 boost::shared_ptr<Evoral::ControlList> copy; ///< copied events for the cut buffer
3881 /** Cut, copy or clear selected automation points.
3882 * @param op Operation (Cut, Copy or Clear)
3885 Editor::cut_copy_points (CutCopyOp op)
3887 if (selection->points.empty ()) {
3891 /* XXX: not ideal, as there may be more than one track involved in the point selection */
3892 _last_cut_copy_source_track = &selection->points.front()->line().trackview;
3894 /* Keep a record of the AutomationLists that we end up using in this operation */
3895 typedef std::map<boost::shared_ptr<AutomationList>, AutomationRecord> Lists;
3898 /* Go through all selected points, making an AutomationRecord for each distinct AutomationList */
3899 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
3900 boost::shared_ptr<AutomationList> al = (*i)->line().the_list();
3901 if (lists.find (al) == lists.end ()) {
3902 /* We haven't seen this list yet, so make a record for it. This includes
3903 taking a copy of its current state, in case this is needed for undo later.
3905 lists[al] = AutomationRecord (&al->get_state ());
3909 if (op == Cut || op == Copy) {
3910 /* This operation will involve putting things in the cut buffer, so create an empty
3911 ControlList for each of our source lists to put the cut buffer data in.
3913 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
3914 i->second.copy = i->first->create (i->first->parameter ());
3917 /* Add all selected points to the relevant copy ControlLists */
3918 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
3919 boost::shared_ptr<AutomationList> al = (*i)->line().the_list();
3920 AutomationList::const_iterator j = (*i)->model ();
3921 lists[al].copy->add ((*j)->when, (*j)->value);
3924 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
3925 /* Correct this copy list so that it starts at time 0 */
3926 double const start = i->second.copy->front()->when;
3927 for (AutomationList::iterator j = i->second.copy->begin(); j != i->second.copy->end(); ++j) {
3928 (*j)->when -= start;
3931 /* And add it to the cut buffer */
3932 cut_buffer->add (i->second.copy);
3936 if (op == Delete || op == Cut) {
3937 /* This operation needs to remove things from the main AutomationList, so do that now */
3939 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
3940 i->first->freeze ();
3943 /* Remove each selected point from its AutomationList */
3944 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
3945 boost::shared_ptr<AutomationList> al = (*i)->line().the_list();
3946 al->erase ((*i)->model ());
3949 /* Thaw the lists and add undo records for them */
3950 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
3951 boost::shared_ptr<AutomationList> al = i->first;
3953 _session->add_command (new MementoCommand<AutomationList> (*al.get(), i->second.state, &(al->get_state ())));
3958 /** Cut, copy or clear selected automation points.
3959 * @param op Operation (Cut, Copy or Clear)
3962 Editor::cut_copy_midi (CutCopyOp op)
3964 for (MidiRegionSelection::iterator i = selection->midi_regions.begin(); i != selection->midi_regions.end(); ++i) {
3965 MidiRegionView* mrv = *i;
3966 mrv->cut_copy_clear (op);
3972 struct lt_playlist {
3973 bool operator () (const PlaylistState& a, const PlaylistState& b) {
3974 return a.playlist < b.playlist;
3978 struct PlaylistMapping {
3980 boost::shared_ptr<Playlist> pl;
3982 PlaylistMapping (TimeAxisView* tvp) : tv (tvp) {}
3985 /** Remove `clicked_regionview' */
3987 Editor::remove_clicked_region ()
3989 if (clicked_routeview == 0 || clicked_regionview == 0) {
3993 boost::shared_ptr<Playlist> playlist = clicked_routeview->playlist();
3995 playlist->clear_changes ();
3996 playlist->clear_owned_changes ();
3997 playlist->remove_region (clicked_regionview->region());
3998 if (Config->get_edit_mode() == Ripple)
3999 playlist->ripple (clicked_regionview->region()->position(), -clicked_regionview->region()->length(), boost::shared_ptr<Region>());
4001 /* We might have removed regions, which alters other regions' layering_index,
4002 so we need to do a recursive diff here.
4004 vector<Command*> cmds;
4005 playlist->rdiff (cmds);
4006 _session->add_commands (cmds);
4008 _session->add_command(new StatefulDiffCommand (playlist));
4009 commit_reversible_command ();
4013 /** Remove the selected regions */
4015 Editor::remove_selected_regions ()
4017 RegionSelection rs = get_regions_from_selection_and_entered ();
4019 if (!_session || rs.empty()) {
4023 begin_reversible_command (_("remove region"));
4025 list<boost::shared_ptr<Region> > regions_to_remove;
4027 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
4028 // we can't just remove the region(s) in this loop because
4029 // this removes them from the RegionSelection, and they thus
4030 // disappear from underneath the iterator, and the ++i above
4031 // SEGVs in a puzzling fashion.
4033 // so, first iterate over the regions to be removed from rs and
4034 // add them to the regions_to_remove list, and then
4035 // iterate over the list to actually remove them.
4037 regions_to_remove.push_back ((*i)->region());
4040 vector<boost::shared_ptr<Playlist> > playlists;
4042 for (list<boost::shared_ptr<Region> >::iterator rl = regions_to_remove.begin(); rl != regions_to_remove.end(); ++rl) {
4044 boost::shared_ptr<Playlist> playlist = (*rl)->playlist();
4047 // is this check necessary?
4051 /* get_regions_from_selection_and_entered() guarantees that
4052 the playlists involved are unique, so there is no need
4056 playlists.push_back (playlist);
4058 playlist->clear_changes ();
4059 playlist->clear_owned_changes ();
4060 playlist->freeze ();
4061 playlist->remove_region (*rl);
4062 if (Config->get_edit_mode() == Ripple)
4063 playlist->ripple ((*rl)->position(), -(*rl)->length(), boost::shared_ptr<Region>());
4067 vector<boost::shared_ptr<Playlist> >::iterator pl;
4069 for (pl = playlists.begin(); pl != playlists.end(); ++pl) {
4072 /* We might have removed regions, which alters other regions' layering_index,
4073 so we need to do a recursive diff here.
4075 vector<Command*> cmds;
4076 (*pl)->rdiff (cmds);
4077 _session->add_commands (cmds);
4079 _session->add_command(new StatefulDiffCommand (*pl));
4082 commit_reversible_command ();
4085 /** Cut, copy or clear selected regions.
4086 * @param op Operation (Cut, Copy or Clear)
4089 Editor::cut_copy_regions (CutCopyOp op, RegionSelection& rs)
4091 /* we can't use a std::map here because the ordering is important, and we can't trivially sort
4092 a map when we want ordered access to both elements. i think.
4095 vector<PlaylistMapping> pmap;
4097 framepos_t first_position = max_framepos;
4099 typedef set<boost::shared_ptr<Playlist> > FreezeList;
4100 FreezeList freezelist;
4102 /* get ordering correct before we cut/copy */
4104 rs.sort_by_position_and_track ();
4106 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
4108 first_position = min ((framepos_t) (*x)->region()->position(), first_position);
4110 if (op == Cut || op == Clear || op == Delete) {
4111 boost::shared_ptr<Playlist> pl = (*x)->region()->playlist();
4114 FreezeList::iterator fl;
4116 // only take state if this is a new playlist.
4117 for (fl = freezelist.begin(); fl != freezelist.end(); ++fl) {
4123 if (fl == freezelist.end()) {
4124 pl->clear_changes();
4125 pl->clear_owned_changes ();
4127 freezelist.insert (pl);
4132 TimeAxisView* tv = &(*x)->get_time_axis_view();
4133 vector<PlaylistMapping>::iterator z;
4135 for (z = pmap.begin(); z != pmap.end(); ++z) {
4136 if ((*z).tv == tv) {
4141 if (z == pmap.end()) {
4142 pmap.push_back (PlaylistMapping (tv));
4146 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ) {
4148 boost::shared_ptr<Playlist> pl = (*x)->region()->playlist();
4151 /* region not yet associated with a playlist (e.g. unfinished
4158 TimeAxisView& tv = (*x)->get_time_axis_view();
4159 boost::shared_ptr<Playlist> npl;
4160 RegionSelection::iterator tmp;
4167 vector<PlaylistMapping>::iterator z;
4169 for (z = pmap.begin(); z != pmap.end(); ++z) {
4170 if ((*z).tv == &tv) {
4175 assert (z != pmap.end());
4178 npl = PlaylistFactory::create (pl->data_type(), *_session, "cutlist", true);
4186 boost::shared_ptr<Region> r = (*x)->region();
4187 boost::shared_ptr<Region> _xx;
4193 pl->remove_region (r);
4194 if (Config->get_edit_mode() == Ripple)
4195 pl->ripple (r->position(), -r->length(), boost::shared_ptr<Region>());
4199 _xx = RegionFactory::create (r);
4200 npl->add_region (_xx, r->position() - first_position);
4201 pl->remove_region (r);
4202 if (Config->get_edit_mode() == Ripple)
4203 pl->ripple (r->position(), -r->length(), boost::shared_ptr<Region>());
4207 /* copy region before adding, so we're not putting same object into two different playlists */
4208 npl->add_region (RegionFactory::create (r), r->position() - first_position);
4212 pl->remove_region (r);
4213 if (Config->get_edit_mode() == Ripple)
4214 pl->ripple (r->position(), -r->length(), boost::shared_ptr<Region>());
4223 list<boost::shared_ptr<Playlist> > foo;
4225 /* the pmap is in the same order as the tracks in which selected regions occured */
4227 for (vector<PlaylistMapping>::iterator i = pmap.begin(); i != pmap.end(); ++i) {
4230 foo.push_back ((*i).pl);
4235 cut_buffer->set (foo);
4239 _last_cut_copy_source_track = 0;
4241 _last_cut_copy_source_track = pmap.front().tv;
4245 for (FreezeList::iterator pl = freezelist.begin(); pl != freezelist.end(); ++pl) {
4248 /* We might have removed regions, which alters other regions' layering_index,
4249 so we need to do a recursive diff here.
4251 vector<Command*> cmds;
4252 (*pl)->rdiff (cmds);
4253 _session->add_commands (cmds);
4255 _session->add_command (new StatefulDiffCommand (*pl));
4260 Editor::cut_copy_ranges (CutCopyOp op)
4262 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4264 /* Sort the track selection now, so that it if is used, the playlists
4265 selected by the calls below to cut_copy_clear are in the order that
4266 their tracks appear in the editor. This makes things like paste
4267 of ranges work properly.
4270 sort_track_selection (ts);
4273 if (!entered_track) {
4276 ts.push_back (entered_track);
4279 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4280 (*i)->cut_copy_clear (*selection, op);
4285 Editor::paste (float times, bool from_context)
4287 DEBUG_TRACE (DEBUG::CutNPaste, "paste to preferred edit pos\n");
4289 paste_internal (get_preferred_edit_position (false, from_context), times);
4293 Editor::mouse_paste ()
4298 if (!mouse_frame (where, ignored)) {
4303 paste_internal (where, 1);
4307 Editor::paste_internal (framepos_t position, float times)
4309 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("apparent paste position is %1\n", position));
4311 if (internal_editing()) {
4312 if (cut_buffer->midi_notes.empty()) {
4316 if (cut_buffer->empty()) {
4321 if (position == max_framepos) {
4322 position = get_preferred_edit_position();
4323 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("preferred edit position is %1\n", position));
4327 TrackViewList::iterator i;
4330 /* get everything in the correct order */
4332 if (_edit_point == Editing::EditAtMouse && entered_track) {
4333 /* With the mouse edit point, paste onto the track under the mouse */
4334 ts.push_back (entered_track);
4335 } else if (!selection->tracks.empty()) {
4336 /* Otherwise, if there are some selected tracks, paste to them */
4337 ts = selection->tracks.filter_to_unique_playlists ();
4338 sort_track_selection (ts);
4339 } else if (_last_cut_copy_source_track) {
4340 /* Otherwise paste to the track that the cut/copy came from;
4341 see discussion in mantis #3333.
4343 ts.push_back (_last_cut_copy_source_track);
4346 if (internal_editing ()) {
4348 /* undo/redo is handled by individual tracks/regions */
4350 for (nth = 0, i = ts.begin(); i != ts.end(); ++i, ++nth) {
4353 RegionSelection::iterator r;
4354 MidiNoteSelection::iterator cb;
4356 get_regions_at (rs, position, ts);
4358 for (cb = cut_buffer->midi_notes.begin(), r = rs.begin();
4359 cb != cut_buffer->midi_notes.end() && r != rs.end(); ++r) {
4360 MidiRegionView* mrv = dynamic_cast<MidiRegionView*> (*r);
4362 mrv->paste (position, times, **cb);
4370 /* we do redo (do you do voodoo?) */
4372 begin_reversible_command (Operations::paste);
4374 for (nth = 0, i = ts.begin(); i != ts.end(); ++i, ++nth) {
4375 (*i)->paste (position, times, *cut_buffer, nth);
4378 commit_reversible_command ();
4383 Editor::duplicate_some_regions (RegionSelection& regions, float times)
4385 boost::shared_ptr<Playlist> playlist;
4386 RegionSelection sel = regions; // clear (below) may clear the argument list if its the current region selection
4387 RegionSelection foo;
4389 framepos_t const start_frame = regions.start ();
4390 framepos_t const end_frame = regions.end_frame ();
4392 begin_reversible_command (Operations::duplicate_region);
4394 selection->clear_regions ();
4396 for (RegionSelection::iterator i = sel.begin(); i != sel.end(); ++i) {
4398 boost::shared_ptr<Region> r ((*i)->region());
4400 TimeAxisView& tv = (*i)->get_time_axis_view();
4401 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (&tv);
4402 latest_regionviews.clear ();
4403 sigc::connection c = rtv->view()->RegionViewAdded.connect (sigc::mem_fun(*this, &Editor::collect_new_region_view));
4405 playlist = (*i)->region()->playlist();
4406 playlist->clear_changes ();
4407 playlist->duplicate (r, end_frame + (r->first_frame() - start_frame), times);
4408 _session->add_command(new StatefulDiffCommand (playlist));
4412 foo.insert (foo.end(), latest_regionviews.begin(), latest_regionviews.end());
4415 commit_reversible_command ();
4418 selection->set (foo);
4423 Editor::duplicate_selection (float times)
4425 if (selection->time.empty() || selection->tracks.empty()) {
4429 boost::shared_ptr<Playlist> playlist;
4430 vector<boost::shared_ptr<Region> > new_regions;
4431 vector<boost::shared_ptr<Region> >::iterator ri;
4433 create_region_from_selection (new_regions);
4435 if (new_regions.empty()) {
4439 begin_reversible_command (_("duplicate selection"));
4441 ri = new_regions.begin();
4443 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4445 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4446 if ((playlist = (*i)->playlist()) == 0) {
4449 playlist->clear_changes ();
4450 playlist->duplicate (*ri, selection->time[clicked_selection].end, times);
4451 _session->add_command (new StatefulDiffCommand (playlist));
4454 if (ri == new_regions.end()) {
4459 commit_reversible_command ();
4462 /** Reset all selected points to the relevant default value */
4464 Editor::reset_point_selection ()
4466 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
4467 ARDOUR::AutomationList::iterator j = (*i)->model ();
4468 (*j)->value = (*i)->line().the_list()->default_value ();
4473 Editor::center_playhead ()
4475 float const page = _visible_canvas_width * samples_per_pixel;
4476 center_screen_internal (playhead_cursor->current_frame (), page);
4480 Editor::center_edit_point ()
4482 float const page = _visible_canvas_width * samples_per_pixel;
4483 center_screen_internal (get_preferred_edit_position(), page);
4486 /** Caller must begin and commit a reversible command */
4488 Editor::clear_playlist (boost::shared_ptr<Playlist> playlist)
4490 playlist->clear_changes ();
4492 _session->add_command (new StatefulDiffCommand (playlist));
4496 Editor::nudge_track (bool use_edit, bool forwards)
4498 boost::shared_ptr<Playlist> playlist;
4499 framepos_t distance;
4500 framepos_t next_distance;
4504 start = get_preferred_edit_position();
4509 if ((distance = get_nudge_distance (start, next_distance)) == 0) {
4513 if (selection->tracks.empty()) {
4517 begin_reversible_command (_("nudge track"));
4519 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4521 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4523 if ((playlist = (*i)->playlist()) == 0) {
4527 playlist->clear_changes ();
4528 playlist->clear_owned_changes ();
4530 playlist->nudge_after (start, distance, forwards);
4532 vector<Command*> cmds;
4534 playlist->rdiff (cmds);
4535 _session->add_commands (cmds);
4537 _session->add_command (new StatefulDiffCommand (playlist));
4540 commit_reversible_command ();
4544 Editor::remove_last_capture ()
4546 vector<string> choices;
4553 if (Config->get_verify_remove_last_capture()) {
4554 prompt = _("Do you really want to destroy the last capture?"
4555 "\n(This is destructive and cannot be undone)");
4557 choices.push_back (_("No, do nothing."));
4558 choices.push_back (_("Yes, destroy it."));
4560 Gtkmm2ext::Choice prompter (_("Destroy last capture"), prompt, choices);
4562 if (prompter.run () == 1) {
4563 _session->remove_last_capture ();
4564 _regions->redisplay ();
4568 _session->remove_last_capture();
4569 _regions->redisplay ();
4574 Editor::normalize_region ()
4580 RegionSelection rs = get_regions_from_selection_and_entered ();
4586 NormalizeDialog dialog (rs.size() > 1);
4588 if (dialog.run () == RESPONSE_CANCEL) {
4592 set_canvas_cursor (_cursors->wait);
4595 /* XXX: should really only count audio regions here */
4596 int const regions = rs.size ();
4598 /* Make a list of the selected audio regions' maximum amplitudes, and also
4599 obtain the maximum amplitude of them all.
4601 list<double> max_amps;
4603 for (RegionSelection::const_iterator i = rs.begin(); i != rs.end(); ++i) {
4604 AudioRegionView const * arv = dynamic_cast<AudioRegionView const *> (*i);
4606 dialog.descend (1.0 / regions);
4607 double const a = arv->audio_region()->maximum_amplitude (&dialog);
4610 /* the user cancelled the operation */
4611 set_canvas_cursor (current_canvas_cursor);
4615 max_amps.push_back (a);
4616 max_amp = max (max_amp, a);
4621 begin_reversible_command (_("normalize"));
4623 list<double>::const_iterator a = max_amps.begin ();
4625 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
4626 AudioRegionView* const arv = dynamic_cast<AudioRegionView*> (*r);
4631 arv->region()->clear_changes ();
4633 double const amp = dialog.normalize_individually() ? *a : max_amp;
4635 arv->audio_region()->normalize (amp, dialog.target ());
4636 _session->add_command (new StatefulDiffCommand (arv->region()));
4641 commit_reversible_command ();
4642 set_canvas_cursor (current_canvas_cursor);
4647 Editor::reset_region_scale_amplitude ()
4653 RegionSelection rs = get_regions_from_selection_and_entered ();
4659 begin_reversible_command ("reset gain");
4661 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
4662 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
4665 arv->region()->clear_changes ();
4666 arv->audio_region()->set_scale_amplitude (1.0f);
4667 _session->add_command (new StatefulDiffCommand (arv->region()));
4670 commit_reversible_command ();
4674 Editor::adjust_region_gain (bool up)
4676 RegionSelection rs = get_regions_from_selection_and_entered ();
4678 if (!_session || rs.empty()) {
4682 begin_reversible_command ("adjust region gain");
4684 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
4685 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
4690 arv->region()->clear_changes ();
4692 double dB = accurate_coefficient_to_dB (arv->audio_region()->scale_amplitude ());
4700 arv->audio_region()->set_scale_amplitude (dB_to_coefficient (dB));
4701 _session->add_command (new StatefulDiffCommand (arv->region()));
4704 commit_reversible_command ();
4709 Editor::reverse_region ()
4715 Reverse rev (*_session);
4716 apply_filter (rev, _("reverse regions"));
4720 Editor::strip_region_silence ()
4726 RegionSelection rs = get_regions_from_selection_and_entered ();
4732 std::list<RegionView*> audio_only;
4734 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
4735 AudioRegionView* const arv = dynamic_cast<AudioRegionView*> (*i);
4737 audio_only.push_back (arv);
4741 StripSilenceDialog d (_session, audio_only);
4742 int const r = d.run ();
4746 if (r == Gtk::RESPONSE_OK) {
4747 ARDOUR::AudioIntervalMap silences;
4748 d.silences (silences);
4749 StripSilence s (*_session, silences, d.fade_length());
4750 apply_filter (s, _("strip silence"), &d);
4755 Editor::apply_midi_note_edit_op_to_region (MidiOperator& op, MidiRegionView& mrv)
4757 Evoral::Sequence<Evoral::MusicalTime>::Notes selected;
4758 mrv.selection_as_notelist (selected, true);
4760 vector<Evoral::Sequence<Evoral::MusicalTime>::Notes> v;
4761 v.push_back (selected);
4763 framepos_t pos_frames = mrv.midi_region()->position() - mrv.midi_region()->start();
4764 double pos_beats = _session->tempo_map().framewalk_to_beats(0, pos_frames);
4766 return op (mrv.midi_region()->model(), pos_beats, v);
4770 Editor::apply_midi_note_edit_op (MidiOperator& op)
4774 RegionSelection rs = get_regions_from_selection_and_entered ();
4780 begin_reversible_command (op.name ());
4782 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
4783 RegionSelection::iterator tmp = r;
4786 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*r);
4789 cmd = apply_midi_note_edit_op_to_region (op, *mrv);
4792 _session->add_command (cmd);
4799 commit_reversible_command ();
4803 Editor::fork_region ()
4805 RegionSelection rs = get_regions_from_selection_and_entered ();
4811 begin_reversible_command (_("Fork Region(s)"));
4813 set_canvas_cursor (_cursors->wait);
4816 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
4817 RegionSelection::iterator tmp = r;
4820 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*>(*r);
4824 boost::shared_ptr<Playlist> playlist = mrv->region()->playlist();
4825 boost::shared_ptr<MidiSource> new_source = _session->create_midi_source_by_stealing_name (mrv->midi_view()->track());
4826 boost::shared_ptr<MidiRegion> newregion = mrv->midi_region()->clone (new_source);
4828 playlist->clear_changes ();
4829 playlist->replace_region (mrv->region(), newregion, mrv->region()->position());
4830 _session->add_command(new StatefulDiffCommand (playlist));
4832 error << string_compose (_("Could not unlink %1"), mrv->region()->name()) << endmsg;
4839 commit_reversible_command ();
4841 set_canvas_cursor (current_canvas_cursor);
4845 Editor::quantize_region ()
4847 int selected_midi_region_cnt = 0;
4853 RegionSelection rs = get_regions_from_selection_and_entered ();
4859 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
4860 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*r);
4862 selected_midi_region_cnt++;
4866 if (selected_midi_region_cnt == 0) {
4870 QuantizeDialog* qd = new QuantizeDialog (*this);
4873 const int r = qd->run ();
4876 if (r == Gtk::RESPONSE_OK) {
4877 Quantize quant (*_session, qd->snap_start(), qd->snap_end(),
4878 qd->start_grid_size(), qd->end_grid_size(),
4879 qd->strength(), qd->swing(), qd->threshold());
4881 apply_midi_note_edit_op (quant);
4886 Editor::insert_patch_change (bool from_context)
4888 RegionSelection rs = get_regions_from_selection_and_entered ();
4894 const framepos_t p = get_preferred_edit_position (false, from_context);
4896 /* XXX: bit of a hack; use the MIDNAM from the first selected region;
4897 there may be more than one, but the PatchChangeDialog can only offer
4898 one set of patch menus.
4900 MidiRegionView* first = dynamic_cast<MidiRegionView*> (rs.front ());
4902 Evoral::PatchChange<Evoral::MusicalTime> empty (0, 0, 0, 0);
4903 PatchChangeDialog d (0, _session, empty, first->instrument_info(), Gtk::Stock::ADD);
4905 if (d.run() == RESPONSE_CANCEL) {
4909 for (RegionSelection::iterator i = rs.begin (); i != rs.end(); ++i) {
4910 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*i);
4912 if (p >= mrv->region()->first_frame() && p <= mrv->region()->last_frame()) {
4913 mrv->add_patch_change (p - mrv->region()->position(), d.patch ());
4920 Editor::apply_filter (Filter& filter, string command, ProgressReporter* progress)
4922 RegionSelection rs = get_regions_from_selection_and_entered ();
4928 begin_reversible_command (command);
4930 set_canvas_cursor (_cursors->wait);
4934 int const N = rs.size ();
4936 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
4937 RegionSelection::iterator tmp = r;
4940 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
4942 boost::shared_ptr<Playlist> playlist = arv->region()->playlist();
4945 progress->descend (1.0 / N);
4948 if (arv->audio_region()->apply (filter, progress) == 0) {
4950 playlist->clear_changes ();
4951 playlist->clear_owned_changes ();
4953 if (filter.results.empty ()) {
4955 /* no regions returned; remove the old one */
4956 playlist->remove_region (arv->region ());
4960 std::vector<boost::shared_ptr<Region> >::iterator res = filter.results.begin ();
4962 /* first region replaces the old one */
4963 playlist->replace_region (arv->region(), *res, (*res)->position());
4967 while (res != filter.results.end()) {
4968 playlist->add_region (*res, (*res)->position());
4974 /* We might have removed regions, which alters other regions' layering_index,
4975 so we need to do a recursive diff here.
4977 vector<Command*> cmds;
4978 playlist->rdiff (cmds);
4979 _session->add_commands (cmds);
4981 _session->add_command(new StatefulDiffCommand (playlist));
4987 progress->ascend ();
4995 commit_reversible_command ();
4998 set_canvas_cursor (current_canvas_cursor);
5002 Editor::external_edit_region ()
5008 Editor::reset_region_gain_envelopes ()
5010 RegionSelection rs = get_regions_from_selection_and_entered ();
5012 if (!_session || rs.empty()) {
5016 _session->begin_reversible_command (_("reset region gain"));
5018 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5019 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
5021 boost::shared_ptr<AutomationList> alist (arv->audio_region()->envelope());
5022 XMLNode& before (alist->get_state());
5024 arv->audio_region()->set_default_envelope ();
5025 _session->add_command (new MementoCommand<AutomationList>(*arv->audio_region()->envelope().get(), &before, &alist->get_state()));
5029 _session->commit_reversible_command ();
5033 Editor::set_region_gain_visibility (RegionView* rv)
5035 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (rv);
5037 arv->update_envelope_visibility();
5042 Editor::set_gain_envelope_visibility ()
5048 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5049 AudioTimeAxisView* v = dynamic_cast<AudioTimeAxisView*>(*i);
5051 v->audio_view()->foreach_regionview (sigc::mem_fun (this, &Editor::set_region_gain_visibility));
5057 Editor::toggle_gain_envelope_active ()
5059 if (_ignore_region_action) {
5063 RegionSelection rs = get_regions_from_selection_and_entered ();
5065 if (!_session || rs.empty()) {
5069 _session->begin_reversible_command (_("region gain envelope active"));
5071 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5072 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
5074 arv->region()->clear_changes ();
5075 arv->audio_region()->set_envelope_active (!arv->audio_region()->envelope_active());
5076 _session->add_command (new StatefulDiffCommand (arv->region()));
5080 _session->commit_reversible_command ();
5084 Editor::toggle_region_lock ()
5086 if (_ignore_region_action) {
5090 RegionSelection rs = get_regions_from_selection_and_entered ();
5092 if (!_session || rs.empty()) {
5096 _session->begin_reversible_command (_("toggle region lock"));
5098 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5099 (*i)->region()->clear_changes ();
5100 (*i)->region()->set_locked (!(*i)->region()->locked());
5101 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5104 _session->commit_reversible_command ();
5108 Editor::toggle_region_video_lock ()
5110 if (_ignore_region_action) {
5114 RegionSelection rs = get_regions_from_selection_and_entered ();
5116 if (!_session || rs.empty()) {
5120 _session->begin_reversible_command (_("Toggle Video Lock"));
5122 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5123 (*i)->region()->clear_changes ();
5124 (*i)->region()->set_video_locked (!(*i)->region()->video_locked());
5125 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5128 _session->commit_reversible_command ();
5132 Editor::toggle_region_lock_style ()
5134 if (_ignore_region_action) {
5138 RegionSelection rs = get_regions_from_selection_and_entered ();
5140 if (!_session || rs.empty()) {
5144 _session->begin_reversible_command (_("region lock style"));
5146 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5147 (*i)->region()->clear_changes ();
5148 PositionLockStyle const ns = (*i)->region()->position_lock_style() == AudioTime ? MusicTime : AudioTime;
5149 (*i)->region()->set_position_lock_style (ns);
5150 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5153 _session->commit_reversible_command ();
5157 Editor::toggle_opaque_region ()
5159 if (_ignore_region_action) {
5163 RegionSelection rs = get_regions_from_selection_and_entered ();
5165 if (!_session || rs.empty()) {
5169 _session->begin_reversible_command (_("change region opacity"));
5171 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5172 (*i)->region()->clear_changes ();
5173 (*i)->region()->set_opaque (!(*i)->region()->opaque());
5174 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5177 _session->commit_reversible_command ();
5181 Editor::toggle_record_enable ()
5183 bool new_state = false;
5185 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5186 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5189 if (!rtav->is_track())
5193 new_state = !rtav->track()->record_enabled();
5197 rtav->track()->set_record_enabled (new_state, this);
5202 Editor::toggle_solo ()
5204 bool new_state = false;
5206 boost::shared_ptr<RouteList> rl (new RouteList);
5208 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5209 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5216 new_state = !rtav->route()->soloed ();
5220 rl->push_back (rtav->route());
5223 _session->set_solo (rl, new_state, Session::rt_cleanup, true);
5227 Editor::toggle_mute ()
5229 bool new_state = false;
5231 boost::shared_ptr<RouteList> rl (new RouteList);
5233 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5234 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5241 new_state = !rtav->route()->muted();
5245 rl->push_back (rtav->route());
5248 _session->set_mute (rl, new_state, Session::rt_cleanup, true);
5252 Editor::toggle_solo_isolate ()
5257 Editor::set_fade_length (bool in)
5259 RegionSelection rs = get_regions_from_selection_and_entered ();
5265 /* we need a region to measure the offset from the start */
5267 RegionView* rv = rs.front ();
5269 framepos_t pos = get_preferred_edit_position();
5273 if (pos > rv->region()->last_frame() || pos < rv->region()->first_frame()) {
5274 /* edit point is outside the relevant region */
5279 if (pos <= rv->region()->position()) {
5283 len = pos - rv->region()->position();
5284 cmd = _("set fade in length");
5286 if (pos >= rv->region()->last_frame()) {
5290 len = rv->region()->last_frame() - pos;
5291 cmd = _("set fade out length");
5294 begin_reversible_command (cmd);
5296 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5297 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5303 boost::shared_ptr<AutomationList> alist;
5305 alist = tmp->audio_region()->fade_in();
5307 alist = tmp->audio_region()->fade_out();
5310 XMLNode &before = alist->get_state();
5313 tmp->audio_region()->set_fade_in_length (len);
5314 tmp->audio_region()->set_fade_in_active (true);
5316 tmp->audio_region()->set_fade_out_length (len);
5317 tmp->audio_region()->set_fade_out_active (true);
5320 XMLNode &after = alist->get_state();
5321 _session->add_command(new MementoCommand<AutomationList>(*alist, &before, &after));
5324 commit_reversible_command ();
5328 Editor::set_fade_in_shape (FadeShape shape)
5330 RegionSelection rs = get_regions_from_selection_and_entered ();
5336 begin_reversible_command (_("set fade in shape"));
5338 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5339 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5345 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_in();
5346 XMLNode &before = alist->get_state();
5348 tmp->audio_region()->set_fade_in_shape (shape);
5350 XMLNode &after = alist->get_state();
5351 _session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
5354 commit_reversible_command ();
5359 Editor::set_fade_out_shape (FadeShape shape)
5361 RegionSelection rs = get_regions_from_selection_and_entered ();
5367 begin_reversible_command (_("set fade out shape"));
5369 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5370 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5376 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_out();
5377 XMLNode &before = alist->get_state();
5379 tmp->audio_region()->set_fade_out_shape (shape);
5381 XMLNode &after = alist->get_state();
5382 _session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
5385 commit_reversible_command ();
5389 Editor::set_fade_in_active (bool yn)
5391 RegionSelection rs = get_regions_from_selection_and_entered ();
5397 begin_reversible_command (_("set fade in active"));
5399 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5400 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5407 boost::shared_ptr<AudioRegion> ar (tmp->audio_region());
5409 ar->clear_changes ();
5410 ar->set_fade_in_active (yn);
5411 _session->add_command (new StatefulDiffCommand (ar));
5414 commit_reversible_command ();
5418 Editor::set_fade_out_active (bool yn)
5420 RegionSelection rs = get_regions_from_selection_and_entered ();
5426 begin_reversible_command (_("set fade out active"));
5428 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5429 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5435 boost::shared_ptr<AudioRegion> ar (tmp->audio_region());
5437 ar->clear_changes ();
5438 ar->set_fade_out_active (yn);
5439 _session->add_command(new StatefulDiffCommand (ar));
5442 commit_reversible_command ();
5446 Editor::toggle_region_fades (int dir)
5448 if (_ignore_region_action) {
5452 boost::shared_ptr<AudioRegion> ar;
5455 RegionSelection rs = get_regions_from_selection_and_entered ();
5461 RegionSelection::iterator i;
5462 for (i = rs.begin(); i != rs.end(); ++i) {
5463 if ((ar = boost::dynamic_pointer_cast<AudioRegion>((*i)->region())) != 0) {
5465 yn = ar->fade_out_active ();
5467 yn = ar->fade_in_active ();
5473 if (i == rs.end()) {
5477 /* XXX should this undo-able? */
5479 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5480 if ((ar = boost::dynamic_pointer_cast<AudioRegion>((*i)->region())) == 0) {
5483 if (dir == 1 || dir == 0) {
5484 ar->set_fade_in_active (!yn);
5487 if (dir == -1 || dir == 0) {
5488 ar->set_fade_out_active (!yn);
5494 /** Update region fade visibility after its configuration has been changed */
5496 Editor::update_region_fade_visibility ()
5498 bool _fade_visibility = _session->config.get_show_region_fades ();
5500 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5501 AudioTimeAxisView* v = dynamic_cast<AudioTimeAxisView*>(*i);
5503 if (_fade_visibility) {
5504 v->audio_view()->show_all_fades ();
5506 v->audio_view()->hide_all_fades ();
5513 Editor::set_edit_point ()
5518 if (!mouse_frame (where, ignored)) {
5524 if (selection->markers.empty()) {
5526 mouse_add_new_marker (where);
5531 Location* loc = find_location_from_marker (selection->markers.front(), ignored);
5534 loc->move_to (where);
5540 Editor::set_playhead_cursor ()
5542 if (entered_marker) {
5543 _session->request_locate (entered_marker->position(), _session->transport_rolling());
5548 if (!mouse_frame (where, ignored)) {
5555 _session->request_locate (where, _session->transport_rolling());
5559 if ( Config->get_follow_edits() )
5560 cancel_time_selection();
5564 Editor::split_region ()
5566 if ( !selection->time.empty()) {
5567 separate_regions_between (selection->time);
5571 RegionSelection rs = get_regions_from_selection_and_edit_point ();
5573 framepos_t where = get_preferred_edit_position ();
5579 split_regions_at (where, rs);
5582 struct EditorOrderRouteSorter {
5583 bool operator() (boost::shared_ptr<Route> a, boost::shared_ptr<Route> b) {
5584 return a->order_key () < b->order_key ();
5589 Editor::select_next_route()
5591 if (selection->tracks.empty()) {
5592 selection->set (track_views.front());
5596 TimeAxisView* current = selection->tracks.front();
5600 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5601 if (*i == current) {
5603 if (i != track_views.end()) {
5606 current = (*(track_views.begin()));
5607 //selection->set (*(track_views.begin()));
5612 rui = dynamic_cast<RouteUI *>(current);
5613 } while ( current->hidden() || (rui != NULL && !rui->route()->active()));
5615 selection->set(current);
5617 ensure_time_axis_view_is_visible (*current);
5621 Editor::select_prev_route()
5623 if (selection->tracks.empty()) {
5624 selection->set (track_views.front());
5628 TimeAxisView* current = selection->tracks.front();
5632 for (TrackViewList::reverse_iterator i = track_views.rbegin(); i != track_views.rend(); ++i) {
5633 if (*i == current) {
5635 if (i != track_views.rend()) {
5638 current = *(track_views.rbegin());
5643 rui = dynamic_cast<RouteUI *>(current);
5644 } while ( current->hidden() || (rui != NULL && !rui->route()->active()));
5646 selection->set (current);
5648 ensure_time_axis_view_is_visible (*current);
5652 Editor::set_loop_from_selection (bool play)
5654 if (_session == 0 || selection->time.empty()) {
5658 framepos_t start = selection->time[clicked_selection].start;
5659 framepos_t end = selection->time[clicked_selection].end;
5661 set_loop_range (start, end, _("set loop range from selection"));
5664 _session->request_play_loop (true);
5665 _session->request_locate (start, true);
5670 Editor::set_loop_from_edit_range (bool play)
5672 if (_session == 0) {
5679 if (!get_edit_op_range (start, end)) {
5683 set_loop_range (start, end, _("set loop range from edit range"));
5686 _session->request_play_loop (true);
5687 _session->request_locate (start, true);
5692 Editor::set_loop_from_region (bool play)
5694 framepos_t start = max_framepos;
5697 RegionSelection rs = get_regions_from_selection_and_entered ();
5703 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5704 if ((*i)->region()->position() < start) {
5705 start = (*i)->region()->position();
5707 if ((*i)->region()->last_frame() + 1 > end) {
5708 end = (*i)->region()->last_frame() + 1;
5712 set_loop_range (start, end, _("set loop range from region"));
5715 _session->request_play_loop (true);
5716 _session->request_locate (start, true);
5721 Editor::set_punch_from_selection ()
5723 if (_session == 0 || selection->time.empty()) {
5727 framepos_t start = selection->time[clicked_selection].start;
5728 framepos_t end = selection->time[clicked_selection].end;
5730 set_punch_range (start, end, _("set punch range from selection"));
5734 Editor::set_punch_from_edit_range ()
5736 if (_session == 0) {
5743 if (!get_edit_op_range (start, end)) {
5747 set_punch_range (start, end, _("set punch range from edit range"));
5751 Editor::set_punch_from_region ()
5753 framepos_t start = max_framepos;
5756 RegionSelection rs = get_regions_from_selection_and_entered ();
5762 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5763 if ((*i)->region()->position() < start) {
5764 start = (*i)->region()->position();
5766 if ((*i)->region()->last_frame() + 1 > end) {
5767 end = (*i)->region()->last_frame() + 1;
5771 set_punch_range (start, end, _("set punch range from region"));
5775 Editor::pitch_shift_region ()
5777 RegionSelection rs = get_regions_from_selection_and_entered ();
5779 RegionSelection audio_rs;
5780 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5781 if (dynamic_cast<AudioRegionView*> (*i)) {
5782 audio_rs.push_back (*i);
5786 if (audio_rs.empty()) {
5790 pitch_shift (audio_rs, 1.2);
5794 Editor::transpose_region ()
5796 RegionSelection rs = get_regions_from_selection_and_entered ();
5798 list<MidiRegionView*> midi_region_views;
5799 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5800 MidiRegionView* mrv = dynamic_cast<MidiRegionView*> (*i);
5802 midi_region_views.push_back (mrv);
5807 int const r = d.run ();
5808 if (r != RESPONSE_ACCEPT) {
5812 for (list<MidiRegionView*>::iterator i = midi_region_views.begin(); i != midi_region_views.end(); ++i) {
5813 (*i)->midi_region()->transpose (d.semitones ());
5818 Editor::set_tempo_from_region ()
5820 RegionSelection rs = get_regions_from_selection_and_entered ();
5822 if (!_session || rs.empty()) {
5826 RegionView* rv = rs.front();
5828 define_one_bar (rv->region()->position(), rv->region()->last_frame() + 1);
5832 Editor::use_range_as_bar ()
5834 framepos_t start, end;
5835 if (get_edit_op_range (start, end)) {
5836 define_one_bar (start, end);
5841 Editor::define_one_bar (framepos_t start, framepos_t end)
5843 framepos_t length = end - start;
5845 const Meter& m (_session->tempo_map().meter_at (start));
5847 /* length = 1 bar */
5849 /* now we want frames per beat.
5850 we have frames per bar, and beats per bar, so ...
5853 /* XXXX METER MATH */
5855 double frames_per_beat = length / m.divisions_per_bar();
5857 /* beats per minute = */
5859 double beats_per_minute = (_session->frame_rate() * 60.0) / frames_per_beat;
5861 /* now decide whether to:
5863 (a) set global tempo
5864 (b) add a new tempo marker
5868 const TempoSection& t (_session->tempo_map().tempo_section_at (start));
5870 bool do_global = false;
5872 if ((_session->tempo_map().n_tempos() == 1) && (_session->tempo_map().n_meters() == 1)) {
5874 /* only 1 tempo & 1 meter: ask if the user wants to set the tempo
5875 at the start, or create a new marker
5878 vector<string> options;
5879 options.push_back (_("Cancel"));
5880 options.push_back (_("Add new marker"));
5881 options.push_back (_("Set global tempo"));
5884 _("Define one bar"),
5885 _("Do you want to set the global tempo or add a new tempo marker?"),
5889 c.set_default_response (2);
5905 /* more than 1 tempo and/or meter section already, go ahead do the "usual":
5906 if the marker is at the region starter, change it, otherwise add
5911 begin_reversible_command (_("set tempo from region"));
5912 XMLNode& before (_session->tempo_map().get_state());
5915 _session->tempo_map().change_initial_tempo (beats_per_minute, t.note_type());
5916 } else if (t.frame() == start) {
5917 _session->tempo_map().change_existing_tempo_at (start, beats_per_minute, t.note_type());
5919 Timecode::BBT_Time bbt;
5920 _session->tempo_map().bbt_time (start, bbt);
5921 _session->tempo_map().add_tempo (Tempo (beats_per_minute, t.note_type()), bbt);
5924 XMLNode& after (_session->tempo_map().get_state());
5926 _session->add_command (new MementoCommand<TempoMap>(_session->tempo_map(), &before, &after));
5927 commit_reversible_command ();
5931 Editor::split_region_at_transients ()
5933 AnalysisFeatureList positions;
5935 RegionSelection rs = get_regions_from_selection_and_entered ();
5937 if (!_session || rs.empty()) {
5941 _session->begin_reversible_command (_("split regions"));
5943 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ) {
5945 RegionSelection::iterator tmp;
5950 boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion> ((*i)->region());
5952 if (ar && (ar->get_transients (positions) == 0)) {
5953 split_region_at_points ((*i)->region(), positions, true);
5960 _session->commit_reversible_command ();
5965 Editor::split_region_at_points (boost::shared_ptr<Region> r, AnalysisFeatureList& positions, bool can_ferret, bool select_new)
5967 bool use_rhythmic_rodent = false;
5969 boost::shared_ptr<Playlist> pl = r->playlist();
5971 list<boost::shared_ptr<Region> > new_regions;
5977 if (positions.empty()) {
5982 if (positions.size() > 20 && can_ferret) {
5983 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);
5984 MessageDialog msg (msgstr,
5987 Gtk::BUTTONS_OK_CANCEL);
5990 msg.add_button (_("Call for the Ferret!"), RESPONSE_APPLY);
5991 msg.set_secondary_text (_("Press OK to continue with this split operation\nor ask the Ferret dialog to tune the analysis"));
5993 msg.set_secondary_text (_("Press OK to continue with this split operation"));
5996 msg.set_title (_("Excessive split?"));
5999 int response = msg.run();
6005 case RESPONSE_APPLY:
6006 use_rhythmic_rodent = true;
6013 if (use_rhythmic_rodent) {
6014 show_rhythm_ferret ();
6018 AnalysisFeatureList::const_iterator x;
6020 pl->clear_changes ();
6021 pl->clear_owned_changes ();
6023 x = positions.begin();
6025 if (x == positions.end()) {
6030 pl->remove_region (r);
6034 while (x != positions.end()) {
6036 /* deal with positons that are out of scope of present region bounds */
6037 if (*x <= 0 || *x > r->length()) {
6042 /* file start = original start + how far we from the initial position ?
6045 framepos_t file_start = r->start() + pos;
6047 /* length = next position - current position
6050 framepos_t len = (*x) - pos;
6052 /* XXX we do we really want to allow even single-sample regions?
6053 shouldn't we have some kind of lower limit on region size?
6062 if (RegionFactory::region_name (new_name, r->name())) {
6066 /* do NOT announce new regions 1 by one, just wait till they are all done */
6070 plist.add (ARDOUR::Properties::start, file_start);
6071 plist.add (ARDOUR::Properties::length, len);
6072 plist.add (ARDOUR::Properties::name, new_name);
6073 plist.add (ARDOUR::Properties::layer, 0);
6075 boost::shared_ptr<Region> nr = RegionFactory::create (r->sources(), plist, false);
6076 /* because we set annouce to false, manually add the new region to the
6079 RegionFactory::map_add (nr);
6081 pl->add_region (nr, r->position() + pos);
6084 new_regions.push_front(nr);
6093 RegionFactory::region_name (new_name, r->name());
6095 /* Add the final region */
6098 plist.add (ARDOUR::Properties::start, r->start() + pos);
6099 plist.add (ARDOUR::Properties::length, r->last_frame() - (r->position() + pos) + 1);
6100 plist.add (ARDOUR::Properties::name, new_name);
6101 plist.add (ARDOUR::Properties::layer, 0);
6103 boost::shared_ptr<Region> nr = RegionFactory::create (r->sources(), plist, false);
6104 /* because we set annouce to false, manually add the new region to the
6107 RegionFactory::map_add (nr);
6108 pl->add_region (nr, r->position() + pos);
6111 new_regions.push_front(nr);
6116 /* We might have removed regions, which alters other regions' layering_index,
6117 so we need to do a recursive diff here.
6119 vector<Command*> cmds;
6121 _session->add_commands (cmds);
6123 _session->add_command (new StatefulDiffCommand (pl));
6127 for (list<boost::shared_ptr<Region> >::iterator i = new_regions.begin(); i != new_regions.end(); ++i){
6128 set_selected_regionview_from_region_list ((*i), Selection::Add);
6134 Editor::place_transient()
6140 RegionSelection rs = get_regions_from_selection_and_edit_point ();
6146 framepos_t where = get_preferred_edit_position();
6148 _session->begin_reversible_command (_("place transient"));
6150 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6151 framepos_t position = (*r)->region()->position();
6152 (*r)->region()->add_transient(where - position);
6155 _session->commit_reversible_command ();
6159 Editor::remove_transient(ArdourCanvas::Item* item)
6165 ArdourCanvas::Line* _line = reinterpret_cast<ArdourCanvas::Line*> (item);
6168 AudioRegionView* _arv = reinterpret_cast<AudioRegionView*> (item->get_data ("regionview"));
6169 _arv->remove_transient (*(float*) _line->get_data ("position"));
6173 Editor::snap_regions_to_grid ()
6175 list <boost::shared_ptr<Playlist > > used_playlists;
6177 RegionSelection rs = get_regions_from_selection_and_entered ();
6179 if (!_session || rs.empty()) {
6183 _session->begin_reversible_command (_("snap regions to grid"));
6185 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6187 boost::shared_ptr<Playlist> pl = (*r)->region()->playlist();
6189 if (!pl->frozen()) {
6190 /* we haven't seen this playlist before */
6192 /* remember used playlists so we can thaw them later */
6193 used_playlists.push_back(pl);
6197 framepos_t start_frame = (*r)->region()->first_frame ();
6198 snap_to (start_frame);
6199 (*r)->region()->set_position (start_frame);
6202 while (used_playlists.size() > 0) {
6203 list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
6205 used_playlists.pop_front();
6208 _session->commit_reversible_command ();
6212 Editor::close_region_gaps ()
6214 list <boost::shared_ptr<Playlist > > used_playlists;
6216 RegionSelection rs = get_regions_from_selection_and_entered ();
6218 if (!_session || rs.empty()) {
6222 Dialog dialog (_("Close Region Gaps"));
6225 table.set_spacings (12);
6226 table.set_border_width (12);
6227 Label* l = manage (left_aligned_label (_("Crossfade length")));
6228 table.attach (*l, 0, 1, 0, 1);
6230 SpinButton spin_crossfade (1, 0);
6231 spin_crossfade.set_range (0, 15);
6232 spin_crossfade.set_increments (1, 1);
6233 spin_crossfade.set_value (5);
6234 table.attach (spin_crossfade, 1, 2, 0, 1);
6236 table.attach (*manage (new Label (_("ms"))), 2, 3, 0, 1);
6238 l = manage (left_aligned_label (_("Pull-back length")));
6239 table.attach (*l, 0, 1, 1, 2);
6241 SpinButton spin_pullback (1, 0);
6242 spin_pullback.set_range (0, 100);
6243 spin_pullback.set_increments (1, 1);
6244 spin_pullback.set_value(30);
6245 table.attach (spin_pullback, 1, 2, 1, 2);
6247 table.attach (*manage (new Label (_("ms"))), 2, 3, 1, 2);
6249 dialog.get_vbox()->pack_start (table);
6250 dialog.add_button (Stock::CANCEL, RESPONSE_CANCEL);
6251 dialog.add_button (_("Ok"), RESPONSE_ACCEPT);
6254 if (dialog.run () == RESPONSE_CANCEL) {
6258 framepos_t crossfade_len = spin_crossfade.get_value();
6259 framepos_t pull_back_frames = spin_pullback.get_value();
6261 crossfade_len = lrintf (crossfade_len * _session->frame_rate()/1000);
6262 pull_back_frames = lrintf (pull_back_frames * _session->frame_rate()/1000);
6264 /* Iterate over the region list and make adjacent regions overlap by crossfade_len_ms */
6266 _session->begin_reversible_command (_("close region gaps"));
6269 boost::shared_ptr<Region> last_region;
6271 rs.sort_by_position_and_track();
6273 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6275 boost::shared_ptr<Playlist> pl = (*r)->region()->playlist();
6277 if (!pl->frozen()) {
6278 /* we haven't seen this playlist before */
6280 /* remember used playlists so we can thaw them later */
6281 used_playlists.push_back(pl);
6285 framepos_t position = (*r)->region()->position();
6287 if (idx == 0 || position < last_region->position()){
6288 last_region = (*r)->region();
6293 (*r)->region()->trim_front( (position - pull_back_frames));
6294 last_region->trim_end( (position - pull_back_frames + crossfade_len));
6296 last_region = (*r)->region();
6301 while (used_playlists.size() > 0) {
6302 list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
6304 used_playlists.pop_front();
6307 _session->commit_reversible_command ();
6311 Editor::tab_to_transient (bool forward)
6313 AnalysisFeatureList positions;
6315 RegionSelection rs = get_regions_from_selection_and_entered ();
6321 framepos_t pos = _session->audible_frame ();
6323 if (!selection->tracks.empty()) {
6325 /* don't waste time searching for transients in duplicate playlists.
6328 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
6330 for (TrackViewList::iterator t = ts.begin(); t != ts.end(); ++t) {
6332 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*t);
6335 boost::shared_ptr<Track> tr = rtv->track();
6337 boost::shared_ptr<Playlist> pl = tr->playlist ();
6339 framepos_t result = pl->find_next_transient (pos, forward ? 1 : -1);
6342 positions.push_back (result);
6355 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6356 (*r)->region()->get_transients (positions);
6360 TransientDetector::cleanup_transients (positions, _session->frame_rate(), 3.0);
6363 AnalysisFeatureList::iterator x;
6365 for (x = positions.begin(); x != positions.end(); ++x) {
6371 if (x != positions.end ()) {
6372 _session->request_locate (*x);
6376 AnalysisFeatureList::reverse_iterator x;
6378 for (x = positions.rbegin(); x != positions.rend(); ++x) {
6384 if (x != positions.rend ()) {
6385 _session->request_locate (*x);
6391 Editor::playhead_forward_to_grid ()
6397 framepos_t pos = playhead_cursor->current_frame ();
6398 if (pos < max_framepos - 1) {
6400 snap_to_internal (pos, 1, false);
6401 _session->request_locate (pos);
6407 Editor::playhead_backward_to_grid ()
6413 framepos_t pos = playhead_cursor->current_frame ();
6416 snap_to_internal (pos, -1, false);
6417 _session->request_locate (pos);
6422 Editor::set_track_height (Height h)
6424 TrackSelection& ts (selection->tracks);
6426 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
6427 (*x)->set_height_enum (h);
6432 Editor::toggle_tracks_active ()
6434 TrackSelection& ts (selection->tracks);
6436 bool target = false;
6442 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
6443 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*x);
6447 target = !rtv->_route->active();
6450 rtv->_route->set_active (target, this);
6456 Editor::remove_tracks ()
6458 TrackSelection& ts (selection->tracks);
6464 vector<string> choices;
6468 const char* trackstr;
6470 vector<boost::shared_ptr<Route> > routes;
6471 bool special_bus = false;
6473 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
6474 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*x);
6478 if (rtv->is_track()) {
6483 routes.push_back (rtv->_route);
6485 if (rtv->route()->is_master() || rtv->route()->is_monitor()) {
6490 if (special_bus && !Config->get_allow_special_bus_removal()) {
6491 MessageDialog msg (_("That would be bad news ...."),
6495 msg.set_secondary_text (string_compose (_(
6496 "Removing the master or monitor bus is such a bad idea\n\
6497 that %1 is not going to allow it.\n\
6499 If you really want to do this sort of thing\n\
6500 edit your ardour.rc file to set the\n\
6501 \"allow-special-bus-removal\" option to be \"yes\""), PROGRAM_NAME));
6508 if (ntracks + nbusses == 0) {
6513 trackstr = _("tracks");
6515 trackstr = _("track");
6519 busstr = _("busses");
6526 prompt = string_compose (_("Do you really want to remove %1 %2 and %3 %4?\n"
6527 "(You may also lose the playlists associated with the %2)\n\n"
6528 "This action cannot be undone, and the session file will be overwritten!"),
6529 ntracks, trackstr, nbusses, busstr);
6531 prompt = string_compose (_("Do you really want to remove %1 %2?\n"
6532 "(You may also lose the playlists associated with the %2)\n\n"
6533 "This action cannot be undone, and the session file will be overwritten!"),
6536 } else if (nbusses) {
6537 prompt = string_compose (_("Do you really want to remove %1 %2?\n\n"
6538 "This action cannot be undon, and the session file will be overwritten"),
6542 choices.push_back (_("No, do nothing."));
6543 if (ntracks + nbusses > 1) {
6544 choices.push_back (_("Yes, remove them."));
6546 choices.push_back (_("Yes, remove it."));
6551 title = string_compose (_("Remove %1"), trackstr);
6553 title = string_compose (_("Remove %1"), busstr);
6556 Choice prompter (title, prompt, choices);
6558 if (prompter.run () != 1) {
6563 Session::StateProtector sp (_session);
6564 for (vector<boost::shared_ptr<Route> >::iterator x = routes.begin(); x != routes.end(); ++x) {
6565 _session->remove_route (*x);
6571 Editor::do_insert_time ()
6573 if (selection->tracks.empty()) {
6577 InsertTimeDialog d (*this);
6578 int response = d.run ();
6580 if (response != RESPONSE_OK) {
6584 if (d.distance() == 0) {
6588 InsertTimeOption opt = d.intersected_region_action ();
6591 get_preferred_edit_position(),
6597 d.move_glued_markers(),
6598 d.move_locked_markers(),
6604 Editor::insert_time (
6605 framepos_t pos, framecnt_t frames, InsertTimeOption opt,
6606 bool all_playlists, bool ignore_music_glue, bool markers_too, bool glued_markers_too, bool locked_markers_too, bool tempo_too
6609 bool commit = false;
6611 if (Config->get_edit_mode() == Lock) {
6615 begin_reversible_command (_("insert time"));
6617 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
6619 for (TrackViewList::iterator x = ts.begin(); x != ts.end(); ++x) {
6623 /* don't operate on any playlist more than once, which could
6624 * happen if "all playlists" is enabled, but there is more
6625 * than 1 track using playlists "from" a given track.
6628 set<boost::shared_ptr<Playlist> > pl;
6630 if (all_playlists) {
6631 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*x);
6633 vector<boost::shared_ptr<Playlist> > all = _session->playlists->playlists_for_track (rtav->track ());
6634 for (vector<boost::shared_ptr<Playlist> >::iterator p = all.begin(); p != all.end(); ++p) {
6639 if ((*x)->playlist ()) {
6640 pl.insert ((*x)->playlist ());
6644 for (set<boost::shared_ptr<Playlist> >::iterator i = pl.begin(); i != pl.end(); ++i) {
6646 (*i)->clear_changes ();
6647 (*i)->clear_owned_changes ();
6649 if (opt == SplitIntersected) {
6653 (*i)->shift (pos, frames, (opt == MoveIntersected), ignore_music_glue);
6655 vector<Command*> cmds;
6657 _session->add_commands (cmds);
6659 _session->add_command (new StatefulDiffCommand (*i));
6664 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*x);
6666 rtav->route ()->shift (pos, frames);
6674 XMLNode& before (_session->locations()->get_state());
6675 Locations::LocationList copy (_session->locations()->list());
6677 for (Locations::LocationList::iterator i = copy.begin(); i != copy.end(); ++i) {
6679 Locations::LocationList::const_iterator tmp;
6681 bool const was_locked = (*i)->locked ();
6682 if (locked_markers_too) {
6686 if ((*i)->position_lock_style() == AudioTime || glued_markers_too) {
6688 if ((*i)->start() >= pos) {
6689 (*i)->set_start ((*i)->start() + frames);
6690 if (!(*i)->is_mark()) {
6691 (*i)->set_end ((*i)->end() + frames);
6704 XMLNode& after (_session->locations()->get_state());
6705 _session->add_command (new MementoCommand<Locations>(*_session->locations(), &before, &after));
6710 _session->tempo_map().insert_time (pos, frames);
6714 commit_reversible_command ();
6719 Editor::fit_selected_tracks ()
6721 if (!selection->tracks.empty()) {
6722 fit_tracks (selection->tracks);
6726 /* no selected tracks - use tracks with selected regions */
6728 if (!selection->regions.empty()) {
6729 for (RegionSelection::iterator r = selection->regions.begin(); r != selection->regions.end(); ++r) {
6730 tvl.push_back (&(*r)->get_time_axis_view ());
6736 } else if (internal_editing()) {
6737 /* no selected tracks, or regions, but in internal edit mode, so follow the mouse and use
6740 if (entered_track) {
6741 tvl.push_back (entered_track);
6749 Editor::fit_tracks (TrackViewList & tracks)
6751 if (tracks.empty()) {
6755 uint32_t child_heights = 0;
6756 int visible_tracks = 0;
6758 for (TrackSelection::iterator t = tracks.begin(); t != tracks.end(); ++t) {
6760 if (!(*t)->marked_for_display()) {
6764 child_heights += (*t)->effective_height() - (*t)->current_height();
6768 /* compute the per-track height from:
6770 total canvas visible height -
6771 height that will be taken by visible children of selected
6772 tracks - height of the ruler/hscroll area
6774 uint32_t h = (uint32_t) floor ((_visible_canvas_height - (child_heights + _trackview_group->canvas_origin().y)) / visible_tracks);
6775 double first_y_pos = DBL_MAX;
6777 if (h < TimeAxisView::preset_height (HeightSmall)) {
6778 MessageDialog msg (*this, _("There are too many tracks to fit in the current window"));
6779 /* too small to be displayed */
6783 undo_visual_stack.push_back (current_visual_state (true));
6784 no_save_visual = true;
6786 /* build a list of all tracks, including children */
6789 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
6791 TimeAxisView::Children c = (*i)->get_child_list ();
6792 for (TimeAxisView::Children::iterator j = c.begin(); j != c.end(); ++j) {
6793 all.push_back (j->get());
6797 /* operate on all tracks, hide unselected ones that are in the middle of selected ones */
6799 bool within_selected = false;
6801 for (TrackViewList::iterator t = all.begin(); t != all.end(); ++t) {
6803 TrackViewList::iterator next;
6808 if ((*t)->marked_for_display ()) {
6809 if (tracks.contains (*t)) {
6810 (*t)->set_height (h);
6811 first_y_pos = std::min ((*t)->y_position (), first_y_pos);
6812 within_selected = true;
6813 } else if (within_selected) {
6814 hide_track_in_display (*t);
6820 set the controls_layout height now, because waiting for its size
6821 request signal handler will cause the vertical adjustment setting to fail
6824 controls_layout.property_height () = _full_canvas_height;
6825 vertical_adjustment.set_value (first_y_pos);
6827 redo_visual_stack.push_back (current_visual_state (true));
6831 Editor::save_visual_state (uint32_t n)
6833 while (visual_states.size() <= n) {
6834 visual_states.push_back (0);
6837 if (visual_states[n] != 0) {
6838 delete visual_states[n];
6841 visual_states[n] = current_visual_state (true);
6846 Editor::goto_visual_state (uint32_t n)
6848 if (visual_states.size() <= n) {
6852 if (visual_states[n] == 0) {
6856 use_visual_state (*visual_states[n]);
6860 Editor::start_visual_state_op (uint32_t n)
6862 save_visual_state (n);
6864 PopUp* pup = new PopUp (WIN_POS_MOUSE, 1000, true);
6866 snprintf (buf, sizeof (buf), _("Saved view %u"), n+1);
6867 pup->set_text (buf);
6872 Editor::cancel_visual_state_op (uint32_t n)
6874 goto_visual_state (n);
6878 Editor::toggle_region_mute ()
6880 if (_ignore_region_action) {
6884 RegionSelection rs = get_regions_from_selection_and_entered ();
6890 if (rs.size() > 1) {
6891 begin_reversible_command (_("mute regions"));
6893 begin_reversible_command (_("mute region"));
6896 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
6898 (*i)->region()->playlist()->clear_changes ();
6899 (*i)->region()->set_muted (!(*i)->region()->muted ());
6900 _session->add_command (new StatefulDiffCommand ((*i)->region()->playlist()));
6904 commit_reversible_command ();
6908 Editor::combine_regions ()
6910 /* foreach track with selected regions, take all selected regions
6911 and join them into a new region containing the subregions (as a
6915 typedef set<RouteTimeAxisView*> RTVS;
6918 if (selection->regions.empty()) {
6922 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
6923 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(&(*i)->get_time_axis_view());
6926 tracks.insert (rtv);
6930 begin_reversible_command (_("combine regions"));
6932 vector<RegionView*> new_selection;
6934 for (RTVS::iterator i = tracks.begin(); i != tracks.end(); ++i) {
6937 if ((rv = (*i)->combine_regions ()) != 0) {
6938 new_selection.push_back (rv);
6942 selection->clear_regions ();
6943 for (vector<RegionView*>::iterator i = new_selection.begin(); i != new_selection.end(); ++i) {
6944 selection->add (*i);
6947 commit_reversible_command ();
6951 Editor::uncombine_regions ()
6953 typedef set<RouteTimeAxisView*> RTVS;
6956 if (selection->regions.empty()) {
6960 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
6961 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(&(*i)->get_time_axis_view());
6964 tracks.insert (rtv);
6968 begin_reversible_command (_("uncombine regions"));
6970 for (RTVS::iterator i = tracks.begin(); i != tracks.end(); ++i) {
6971 (*i)->uncombine_regions ();
6974 commit_reversible_command ();
6978 Editor::toggle_midi_input_active (bool flip_others)
6981 boost::shared_ptr<RouteList> rl (new RouteList);
6983 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
6984 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
6990 boost::shared_ptr<MidiTrack> mt = rtav->midi_track();
6993 rl->push_back (rtav->route());
6994 onoff = !mt->input_active();
6998 _session->set_exclusive_input_active (rl, onoff, flip_others);
7005 lock_dialog = new Gtk::Dialog (string_compose (_("%1: Locked"), PROGRAM_NAME), true);
7007 Gtk::Image* padlock = manage (new Gtk::Image (ARDOUR_UI_UTILS::get_icon ("padlock_closed")));
7008 lock_dialog->get_vbox()->pack_start (*padlock);
7010 ArdourButton* b = manage (new ArdourButton);
7011 b->set_name ("lock button");
7012 b->set_markup (string_compose ("<span size=\"large\" weight=\"bold\">%1</span>", _("Click to unlock")));
7013 b->signal_clicked.connect (sigc::mem_fun (*this, &Editor::unlock));
7014 lock_dialog->get_vbox()->pack_start (*b);
7016 lock_dialog->get_vbox()->show_all ();
7017 lock_dialog->set_size_request (200, 200);
7021 /* The global menu bar continues to be accessible to applications
7022 with modal dialogs, which means that we need to desensitize
7023 all items in the menu bar. Since those items are really just
7024 proxies for actions, that means disabling all actions.
7026 ActionManager::disable_all_actions ();
7028 lock_dialog->present ();
7034 lock_dialog->hide ();
7037 ActionManager::pop_action_state ();
7040 if (ARDOUR_UI::config()->get_lock_gui_after_seconds()) {
7041 start_lock_event_timing ();