2 Copyright (C) 2000-2004 Paul Davis
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 /* Note: public Editor methods are documented in public_editor.h */
30 #include "pbd/error.h"
31 #include "pbd/basename.h"
32 #include "pbd/pthread_utils.h"
33 #include "pbd/memento_command.h"
34 #include "pbd/unwind.h"
35 #include "pbd/whitespace.h"
36 #include "pbd/stateful_diff_command.h"
38 #include <gtkmm2ext/utils.h>
39 #include <gtkmm2ext/choice.h>
40 #include <gtkmm2ext/popup.h>
42 #include "ardour/audio_track.h"
43 #include "ardour/audioregion.h"
44 #include "ardour/dB.h"
45 #include "ardour/location.h"
46 #include "ardour/midi_region.h"
47 #include "ardour/midi_track.h"
48 #include "ardour/operations.h"
49 #include "ardour/playlist_factory.h"
50 #include "ardour/quantize.h"
51 #include "ardour/region_factory.h"
52 #include "ardour/reverse.h"
53 #include "ardour/session.h"
54 #include "ardour/session_playlists.h"
55 #include "ardour/strip_silence.h"
56 #include "ardour/transient_detector.h"
58 #include "canvas/canvas.h"
60 #include "ardour_ui.h"
61 #include "audio_region_view.h"
62 #include "audio_streamview.h"
63 #include "audio_time_axis.h"
64 #include "automation_time_axis.h"
65 #include "control_point.h"
69 #include "editor_cursors.h"
70 #include "editor_drag.h"
71 #include "editor_regions.h"
72 #include "editor_routes.h"
73 #include "gui_thread.h"
74 #include "insert_time_dialog.h"
75 #include "interthread_progress_window.h"
77 #include "midi_region_view.h"
78 #include "mouse_cursors.h"
79 #include "normalize_dialog.h"
80 #include "patch_change_dialog.h"
81 #include "quantize_dialog.h"
82 #include "region_gain_line.h"
83 #include "rgb_macros.h"
84 #include "route_time_axis.h"
85 #include "selection.h"
86 #include "selection_templates.h"
87 #include "streamview.h"
88 #include "strip_silence_dialog.h"
89 #include "time_axis_view.h"
90 #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;
138 if (regions.empty()) {
142 begin_reversible_command (_("split"));
144 // if splitting a single region, and snap-to is using
145 // region boundaries, don't pay attention to them
147 if (regions.size() == 1) {
148 switch (_snap_type) {
149 case SnapToRegionStart:
150 case SnapToRegionSync:
151 case SnapToRegionEnd:
160 EditorFreeze(); /* Emit Signal */
163 for (RegionSelection::iterator a = regions.begin(); a != regions.end(); ) {
165 RegionSelection::iterator tmp;
167 /* XXX this test needs to be more complicated, to make sure we really
168 have something to split.
171 if (!(*a)->region()->covers (where)) {
179 boost::shared_ptr<Playlist> pl = (*a)->region()->playlist();
187 /* we haven't seen this playlist before */
189 /* remember used playlists so we can thaw them later */
190 used_playlists.push_back(pl);
195 pl->clear_changes ();
196 pl->split_region ((*a)->region(), where);
197 _session->add_command (new StatefulDiffCommand (pl));
203 while (used_playlists.size() > 0) {
204 list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
206 used_playlists.pop_front();
209 commit_reversible_command ();
212 EditorThaw(); /* Emit Signal */
216 /** Move one extreme of the current range selection. If more than one range is selected,
217 * the start of the earliest range or the end of the latest range is moved.
219 * @param move_end true to move the end of the current range selection, false to move
221 * @param next true to move the extreme to the next region boundary, false to move to
225 Editor::move_range_selection_start_or_end_to_region_boundary (bool move_end, bool next)
227 if (selection->time.start() == selection->time.end_frame()) {
231 framepos_t start = selection->time.start ();
232 framepos_t end = selection->time.end_frame ();
234 /* the position of the thing we may move */
235 framepos_t pos = move_end ? end : start;
236 int dir = next ? 1 : -1;
238 /* so we don't find the current region again */
239 if (dir > 0 || pos > 0) {
243 framepos_t const target = get_region_boundary (pos, dir, true, false);
258 begin_reversible_command (_("alter selection"));
259 selection->set_preserving_all_ranges (start, end);
260 commit_reversible_command ();
264 Editor::nudge_forward_release (GdkEventButton* ev)
266 if (ev->state & Keyboard::PrimaryModifier) {
267 nudge_forward (false, true);
269 nudge_forward (false, false);
275 Editor::nudge_backward_release (GdkEventButton* ev)
277 if (ev->state & Keyboard::PrimaryModifier) {
278 nudge_backward (false, true);
280 nudge_backward (false, false);
287 Editor::nudge_forward (bool next, bool force_playhead)
290 framepos_t next_distance;
296 RegionSelection rs = get_regions_from_selection_and_entered ();
298 if (!force_playhead && !rs.empty()) {
300 begin_reversible_command (_("nudge regions forward"));
302 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
303 boost::shared_ptr<Region> r ((*i)->region());
305 distance = get_nudge_distance (r->position(), next_distance);
308 distance = next_distance;
312 r->set_position (r->position() + distance);
313 _session->add_command (new StatefulDiffCommand (r));
316 commit_reversible_command ();
319 } else if (!force_playhead && !selection->markers.empty()) {
323 begin_reversible_command (_("nudge location forward"));
325 for (MarkerSelection::iterator i = selection->markers.begin(); i != selection->markers.end(); ++i) {
327 Location* loc = find_location_from_marker ((*i), is_start);
331 XMLNode& before (loc->get_state());
334 distance = get_nudge_distance (loc->start(), next_distance);
336 distance = next_distance;
338 if (max_framepos - distance > loc->start() + loc->length()) {
339 loc->set_start (loc->start() + distance);
341 loc->set_start (max_framepos - loc->length());
344 distance = get_nudge_distance (loc->end(), next_distance);
346 distance = next_distance;
348 if (max_framepos - distance > loc->end()) {
349 loc->set_end (loc->end() + distance);
351 loc->set_end (max_framepos);
354 XMLNode& after (loc->get_state());
355 _session->add_command (new MementoCommand<Location>(*loc, &before, &after));
359 commit_reversible_command ();
362 distance = get_nudge_distance (playhead_cursor->current_frame (), next_distance);
363 _session->request_locate (playhead_cursor->current_frame () + distance);
368 Editor::nudge_backward (bool next, bool force_playhead)
371 framepos_t next_distance;
377 RegionSelection rs = get_regions_from_selection_and_entered ();
379 if (!force_playhead && !rs.empty()) {
381 begin_reversible_command (_("nudge regions backward"));
383 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
384 boost::shared_ptr<Region> r ((*i)->region());
386 distance = get_nudge_distance (r->position(), next_distance);
389 distance = next_distance;
394 if (r->position() > distance) {
395 r->set_position (r->position() - distance);
399 _session->add_command (new StatefulDiffCommand (r));
402 commit_reversible_command ();
404 } else if (!force_playhead && !selection->markers.empty()) {
408 begin_reversible_command (_("nudge location forward"));
410 for (MarkerSelection::iterator i = selection->markers.begin(); i != selection->markers.end(); ++i) {
412 Location* loc = find_location_from_marker ((*i), is_start);
416 XMLNode& before (loc->get_state());
419 distance = get_nudge_distance (loc->start(), next_distance);
421 distance = next_distance;
423 if (distance < loc->start()) {
424 loc->set_start (loc->start() - distance);
429 distance = get_nudge_distance (loc->end(), next_distance);
432 distance = next_distance;
435 if (distance < loc->end() - loc->length()) {
436 loc->set_end (loc->end() - distance);
438 loc->set_end (loc->length());
442 XMLNode& after (loc->get_state());
443 _session->add_command (new MementoCommand<Location>(*loc, &before, &after));
447 commit_reversible_command ();
451 distance = get_nudge_distance (playhead_cursor->current_frame (), next_distance);
453 if (playhead_cursor->current_frame () > distance) {
454 _session->request_locate (playhead_cursor->current_frame () - distance);
456 _session->goto_start();
462 Editor::nudge_forward_capture_offset ()
464 RegionSelection rs = get_regions_from_selection_and_entered ();
466 if (!_session || rs.empty()) {
470 begin_reversible_command (_("nudge forward"));
472 framepos_t const distance = _session->worst_output_latency();
474 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
475 boost::shared_ptr<Region> r ((*i)->region());
478 r->set_position (r->position() + distance);
479 _session->add_command(new StatefulDiffCommand (r));
482 commit_reversible_command ();
486 Editor::nudge_backward_capture_offset ()
488 RegionSelection rs = get_regions_from_selection_and_entered ();
490 if (!_session || rs.empty()) {
494 begin_reversible_command (_("nudge backward"));
496 framepos_t const distance = _session->worst_output_latency();
498 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
499 boost::shared_ptr<Region> r ((*i)->region());
503 if (r->position() > distance) {
504 r->set_position (r->position() - distance);
508 _session->add_command(new StatefulDiffCommand (r));
511 commit_reversible_command ();
514 struct RegionSelectionPositionSorter {
515 bool operator() (RegionView* a, RegionView* b) {
516 return a->region()->position() < b->region()->position();
521 Editor::sequence_regions ()
524 framepos_t r_end_prev;
532 RegionSelection rs = get_regions_from_selection_and_entered ();
533 rs.sort(RegionSelectionPositionSorter());
537 begin_reversible_command (_("sequence regions"));
538 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
539 boost::shared_ptr<Region> r ((*i)->region());
547 if(r->position_locked())
554 r->set_position(r_end_prev);
557 _session->add_command (new StatefulDiffCommand (r));
559 r_end=r->position() + r->length();
563 commit_reversible_command ();
571 Editor::move_to_start ()
573 _session->goto_start ();
577 Editor::move_to_end ()
580 _session->request_locate (_session->current_end_frame());
584 Editor::build_region_boundary_cache ()
587 vector<RegionPoint> interesting_points;
588 boost::shared_ptr<Region> r;
589 TrackViewList tracks;
592 region_boundary_cache.clear ();
598 switch (_snap_type) {
599 case SnapToRegionStart:
600 interesting_points.push_back (Start);
602 case SnapToRegionEnd:
603 interesting_points.push_back (End);
605 case SnapToRegionSync:
606 interesting_points.push_back (SyncPoint);
608 case SnapToRegionBoundary:
609 interesting_points.push_back (Start);
610 interesting_points.push_back (End);
613 fatal << string_compose (_("build_region_boundary_cache called with snap_type = %1"), _snap_type) << endmsg;
618 TimeAxisView *ontrack = 0;
621 if (!selection->tracks.empty()) {
622 tlist = selection->tracks.filter_to_unique_playlists ();
624 tlist = track_views.filter_to_unique_playlists ();
627 while (pos < _session->current_end_frame() && !at_end) {
630 framepos_t lpos = max_framepos;
632 for (vector<RegionPoint>::iterator p = interesting_points.begin(); p != interesting_points.end(); ++p) {
634 if ((r = find_next_region (pos, *p, 1, tlist, &ontrack)) == 0) {
635 if (*p == interesting_points.back()) {
638 /* move to next point type */
644 rpos = r->first_frame();
648 rpos = r->last_frame();
652 rpos = r->sync_position ();
660 RouteTimeAxisView *rtav;
662 if (ontrack != 0 && (rtav = dynamic_cast<RouteTimeAxisView*>(ontrack)) != 0 ) {
663 if (rtav->track() != 0) {
664 speed = rtav->track()->speed();
668 rpos = track_frame_to_session_frame (rpos, speed);
674 /* prevent duplicates, but we don't use set<> because we want to be able
678 vector<framepos_t>::iterator ri;
680 for (ri = region_boundary_cache.begin(); ri != region_boundary_cache.end(); ++ri) {
686 if (ri == region_boundary_cache.end()) {
687 region_boundary_cache.push_back (rpos);
694 /* finally sort to be sure that the order is correct */
696 sort (region_boundary_cache.begin(), region_boundary_cache.end());
699 boost::shared_ptr<Region>
700 Editor::find_next_region (framepos_t frame, RegionPoint point, int32_t dir, TrackViewList& tracks, TimeAxisView **ontrack)
702 TrackViewList::iterator i;
703 framepos_t closest = max_framepos;
704 boost::shared_ptr<Region> ret;
708 framepos_t track_frame;
709 RouteTimeAxisView *rtav;
711 for (i = tracks.begin(); i != tracks.end(); ++i) {
714 boost::shared_ptr<Region> r;
717 if ( (rtav = dynamic_cast<RouteTimeAxisView*>(*i)) != 0 ) {
718 if (rtav->track()!=0)
719 track_speed = rtav->track()->speed();
722 track_frame = session_frame_to_track_frame(frame, track_speed);
724 if ((r = (*i)->find_next_region (track_frame, point, dir)) == 0) {
730 rpos = r->first_frame ();
734 rpos = r->last_frame ();
738 rpos = r->sync_position ();
742 // rpos is a "track frame", converting it to "_session frame"
743 rpos = track_frame_to_session_frame(rpos, track_speed);
746 distance = rpos - frame;
748 distance = frame - rpos;
751 if (distance < closest) {
763 Editor::find_next_region_boundary (framepos_t pos, int32_t dir, const TrackViewList& tracks)
765 framecnt_t distance = max_framepos;
766 framepos_t current_nearest = -1;
768 for (TrackViewList::const_iterator i = tracks.begin(); i != tracks.end(); ++i) {
769 framepos_t contender;
772 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*i);
778 if ((contender = rtv->find_next_region_boundary (pos, dir)) < 0) {
782 d = ::llabs (pos - contender);
785 current_nearest = contender;
790 return current_nearest;
794 Editor::get_region_boundary (framepos_t pos, int32_t dir, bool with_selection, bool only_onscreen)
799 if (with_selection && Config->get_region_boundaries_from_selected_tracks()) {
801 if (!selection->tracks.empty()) {
803 target = find_next_region_boundary (pos, dir, selection->tracks);
807 if (only_onscreen || Config->get_region_boundaries_from_onscreen_tracks()) {
808 get_onscreen_tracks (tvl);
809 target = find_next_region_boundary (pos, dir, tvl);
811 target = find_next_region_boundary (pos, dir, track_views);
817 if (only_onscreen || Config->get_region_boundaries_from_onscreen_tracks()) {
818 get_onscreen_tracks (tvl);
819 target = find_next_region_boundary (pos, dir, tvl);
821 target = find_next_region_boundary (pos, dir, track_views);
829 Editor::cursor_to_region_boundary (bool with_selection, int32_t dir)
831 framepos_t pos = playhead_cursor->current_frame ();
838 // so we don't find the current region again..
839 if (dir > 0 || pos > 0) {
843 if ((target = get_region_boundary (pos, dir, with_selection, false)) < 0) {
847 _session->request_locate (target);
851 Editor::cursor_to_next_region_boundary (bool with_selection)
853 cursor_to_region_boundary (with_selection, 1);
857 Editor::cursor_to_previous_region_boundary (bool with_selection)
859 cursor_to_region_boundary (with_selection, -1);
863 Editor::cursor_to_region_point (EditorCursor* cursor, RegionPoint point, int32_t dir)
865 boost::shared_ptr<Region> r;
866 framepos_t pos = cursor->current_frame ();
872 TimeAxisView *ontrack = 0;
874 // so we don't find the current region again..
878 if (!selection->tracks.empty()) {
880 r = find_next_region (pos, point, dir, selection->tracks, &ontrack);
882 } else if (clicked_axisview) {
885 t.push_back (clicked_axisview);
887 r = find_next_region (pos, point, dir, t, &ontrack);
891 r = find_next_region (pos, point, dir, track_views, &ontrack);
900 pos = r->first_frame ();
904 pos = r->last_frame ();
908 pos = r->sync_position ();
913 RouteTimeAxisView *rtav;
915 if ( ontrack != 0 && (rtav = dynamic_cast<RouteTimeAxisView*>(ontrack)) != 0 ) {
916 if (rtav->track() != 0) {
917 speed = rtav->track()->speed();
921 pos = track_frame_to_session_frame(pos, speed);
923 if (cursor == playhead_cursor) {
924 _session->request_locate (pos);
926 cursor->set_position (pos);
931 Editor::cursor_to_next_region_point (EditorCursor* cursor, RegionPoint point)
933 cursor_to_region_point (cursor, point, 1);
937 Editor::cursor_to_previous_region_point (EditorCursor* cursor, RegionPoint point)
939 cursor_to_region_point (cursor, point, -1);
943 Editor::cursor_to_selection_start (EditorCursor *cursor)
947 switch (mouse_mode) {
949 if (!selection->regions.empty()) {
950 pos = selection->regions.start();
955 if (!selection->time.empty()) {
956 pos = selection->time.start ();
964 if (cursor == playhead_cursor) {
965 _session->request_locate (pos);
967 cursor->set_position (pos);
972 Editor::cursor_to_selection_end (EditorCursor *cursor)
976 switch (mouse_mode) {
978 if (!selection->regions.empty()) {
979 pos = selection->regions.end_frame();
984 if (!selection->time.empty()) {
985 pos = selection->time.end_frame ();
993 if (cursor == playhead_cursor) {
994 _session->request_locate (pos);
996 cursor->set_position (pos);
1001 Editor::selected_marker_to_region_boundary (bool with_selection, int32_t dir)
1011 if (selection->markers.empty()) {
1015 if (!mouse_frame (mouse, ignored)) {
1019 add_location_mark (mouse);
1022 if ((loc = find_location_from_marker (selection->markers.front(), ignored)) == 0) {
1026 framepos_t pos = loc->start();
1028 // so we don't find the current region again..
1029 if (dir > 0 || pos > 0) {
1033 if ((target = get_region_boundary (pos, dir, with_selection, false)) < 0) {
1037 loc->move_to (target);
1041 Editor::selected_marker_to_next_region_boundary (bool with_selection)
1043 selected_marker_to_region_boundary (with_selection, 1);
1047 Editor::selected_marker_to_previous_region_boundary (bool with_selection)
1049 selected_marker_to_region_boundary (with_selection, -1);
1053 Editor::selected_marker_to_region_point (RegionPoint point, int32_t dir)
1055 boost::shared_ptr<Region> r;
1060 if (!_session || selection->markers.empty()) {
1064 if ((loc = find_location_from_marker (selection->markers.front(), ignored)) == 0) {
1068 TimeAxisView *ontrack = 0;
1072 // so we don't find the current region again..
1076 if (!selection->tracks.empty()) {
1078 r = find_next_region (pos, point, dir, selection->tracks, &ontrack);
1082 r = find_next_region (pos, point, dir, track_views, &ontrack);
1091 pos = r->first_frame ();
1095 pos = r->last_frame ();
1099 pos = r->adjust_to_sync (r->first_frame());
1104 RouteTimeAxisView *rtav;
1106 if (ontrack != 0 && (rtav = dynamic_cast<RouteTimeAxisView*>(ontrack)) != 0) {
1107 if (rtav->track() != 0) {
1108 speed = rtav->track()->speed();
1112 pos = track_frame_to_session_frame(pos, speed);
1118 Editor::selected_marker_to_next_region_point (RegionPoint point)
1120 selected_marker_to_region_point (point, 1);
1124 Editor::selected_marker_to_previous_region_point (RegionPoint point)
1126 selected_marker_to_region_point (point, -1);
1130 Editor::selected_marker_to_selection_start ()
1136 if (!_session || selection->markers.empty()) {
1140 if ((loc = find_location_from_marker (selection->markers.front(), ignored)) == 0) {
1144 switch (mouse_mode) {
1146 if (!selection->regions.empty()) {
1147 pos = selection->regions.start();
1152 if (!selection->time.empty()) {
1153 pos = selection->time.start ();
1165 Editor::selected_marker_to_selection_end ()
1171 if (!_session || selection->markers.empty()) {
1175 if ((loc = find_location_from_marker (selection->markers.front(), ignored)) == 0) {
1179 switch (mouse_mode) {
1181 if (!selection->regions.empty()) {
1182 pos = selection->regions.end_frame();
1187 if (!selection->time.empty()) {
1188 pos = selection->time.end_frame ();
1200 Editor::scroll_playhead (bool forward)
1202 framepos_t pos = playhead_cursor->current_frame ();
1203 framecnt_t delta = (framecnt_t) floor (current_page_samples() / 0.8);
1206 if (pos == max_framepos) {
1210 if (pos < max_framepos - delta) {
1229 _session->request_locate (pos);
1233 Editor::cursor_align (bool playhead_to_edit)
1239 if (playhead_to_edit) {
1241 if (selection->markers.empty()) {
1245 _session->request_locate (selection->markers.front()->position(), _session->transport_rolling());
1248 /* move selected markers to playhead */
1250 for (MarkerSelection::iterator i = selection->markers.begin(); i != selection->markers.end(); ++i) {
1253 Location* loc = find_location_from_marker (*i, ignored);
1255 if (loc->is_mark()) {
1256 loc->set_start (playhead_cursor->current_frame ());
1258 loc->set (playhead_cursor->current_frame (),
1259 playhead_cursor->current_frame () + loc->length());
1266 Editor::scroll_backward (float pages)
1268 framepos_t const one_page = (framepos_t) rint (_visible_canvas_width * samples_per_pixel);
1269 framepos_t const cnt = (framepos_t) floor (pages * one_page);
1272 if (leftmost_frame < cnt) {
1275 frame = leftmost_frame - cnt;
1278 reset_x_origin (frame);
1282 Editor::scroll_forward (float pages)
1284 framepos_t const one_page = (framepos_t) rint (_visible_canvas_width * samples_per_pixel);
1285 framepos_t const cnt = (framepos_t) floor (pages * one_page);
1288 if (max_framepos - cnt < leftmost_frame) {
1289 frame = max_framepos - cnt;
1291 frame = leftmost_frame + cnt;
1294 reset_x_origin (frame);
1298 Editor::scroll_tracks_down ()
1300 double vert_value = vertical_adjustment.get_value() + vertical_adjustment.get_page_size();
1301 if (vert_value > vertical_adjustment.get_upper() - _visible_canvas_height) {
1302 vert_value = vertical_adjustment.get_upper() - _visible_canvas_height;
1305 vertical_adjustment.set_value (vert_value);
1309 Editor::scroll_tracks_up ()
1311 vertical_adjustment.set_value (vertical_adjustment.get_value() - vertical_adjustment.get_page_size());
1315 Editor::scroll_tracks_down_line ()
1317 double vert_value = vertical_adjustment.get_value() + 60;
1319 if (vert_value > vertical_adjustment.get_upper() - _visible_canvas_height) {
1320 vert_value = vertical_adjustment.get_upper() - _visible_canvas_height;
1323 vertical_adjustment.set_value (vert_value);
1327 Editor::scroll_tracks_up_line ()
1329 reset_y_origin (vertical_adjustment.get_value() - 60);
1333 Editor::scroll_down_one_track ()
1335 TrackViewList::reverse_iterator next = track_views.rend();
1336 std::pair<TimeAxisView*,double> res;
1337 const double bottom_of_trackviews = vertical_adjustment.get_value() + vertical_adjustment.get_page_size() - 1;
1339 for (TrackViewList::reverse_iterator t = track_views.rbegin(); t != track_views.rend(); ++t) {
1340 if ((*t)->hidden()) {
1344 /* If this is the bottom visible trackview, we want to display
1348 res = (*t)->covers_y_position (bottom_of_trackviews);
1354 ++next; // moves "next" towards the "front" since it is a reverse iterator
1357 /* move to the track below the first one that covers the */
1359 if (next != track_views.rend()) {
1360 ensure_track_visible (*next);
1368 Editor::scroll_up_one_track ()
1370 double vertical_pos = vertical_adjustment.get_value ();
1372 TrackViewList::iterator prev = track_views.end();
1373 std::pair<TimeAxisView*,double> res;
1375 for (TrackViewList::iterator t = track_views.begin(); t != track_views.end(); ++t) {
1377 if ((*t)->hidden()) {
1381 /* find the trackview at the top of the trackview group */
1382 res = (*t)->covers_y_position (vertical_pos);
1385 cerr << res.first->name() << " covers the top\n";
1392 if (prev != track_views.end()) {
1393 ensure_track_visible (*prev);
1403 Editor::tav_zoom_step (bool coarser)
1405 _routes->suspend_redisplay ();
1409 if (selection->tracks.empty()) {
1412 ts = &selection->tracks;
1415 for (TrackViewList::iterator i = ts->begin(); i != ts->end(); ++i) {
1416 TimeAxisView *tv = (static_cast<TimeAxisView*>(*i));
1417 tv->step_height (coarser);
1420 _routes->resume_redisplay ();
1424 Editor::tav_zoom_smooth (bool coarser, bool force_all)
1426 _routes->suspend_redisplay ();
1430 if (selection->tracks.empty() || force_all) {
1433 ts = &selection->tracks;
1436 for (TrackViewList::iterator i = ts->begin(); i != ts->end(); ++i) {
1437 TimeAxisView *tv = (static_cast<TimeAxisView*>(*i));
1438 uint32_t h = tv->current_height ();
1443 if (h >= TimeAxisView::preset_height (HeightSmall)) {
1448 tv->set_height (h + 5);
1452 _routes->resume_redisplay ();
1456 Editor::clamp_samples_per_pixel (framecnt_t& fpp) const
1458 bool clamped = false;
1468 sr = _session->frame_rate ();
1473 const framecnt_t three_days = 3 * 24 * 60 * 60 * sr;
1474 const framecnt_t lots_of_pixels = 4000;
1476 /* if the zoom level is greater than what you'd get trying to display 3
1477 * days of audio on a really big screen, scale it down.
1480 if (fpp * lots_of_pixels > three_days) {
1481 fpp = three_days / _track_canvas->width();
1489 Editor::temporal_zoom_step (bool coarser)
1491 ENSURE_GUI_THREAD (*this, &Editor::temporal_zoom_step, coarser)
1493 framecnt_t nspp = samples_per_pixel;
1501 temporal_zoom (nspp);
1505 Editor::temporal_zoom (framecnt_t fpp)
1511 framepos_t current_page = current_page_samples();
1512 framepos_t current_leftmost = leftmost_frame;
1513 framepos_t current_rightmost;
1514 framepos_t current_center;
1515 framepos_t new_page_size;
1516 framepos_t half_page_size;
1517 framepos_t leftmost_after_zoom = 0;
1519 bool in_track_canvas;
1523 clamp_samples_per_pixel (fpp);
1524 if (fpp == samples_per_pixel) {
1528 // Imposing an arbitrary limit to zoom out as too much zoom out produces
1529 // segfaults for lack of memory. If somebody decides this is not high enough I
1530 // believe it can be raisen to higher values but some limit must be in place.
1532 // This constant represents 1 day @ 48kHz on a 1600 pixel wide display
1533 // all of which is used for the editor track displays. The whole day
1534 // would be 4147200000 samples, so 2592000 samples per pixel.
1536 nfpp = min (fpp, (framecnt_t) 2592000);
1537 nfpp = max ((framecnt_t) 1, fpp);
1539 new_page_size = (framepos_t) floor (_visible_canvas_width * nfpp);
1540 half_page_size = new_page_size / 2;
1542 switch (zoom_focus) {
1544 leftmost_after_zoom = current_leftmost;
1547 case ZoomFocusRight:
1548 current_rightmost = leftmost_frame + current_page;
1549 if (current_rightmost < new_page_size) {
1550 leftmost_after_zoom = 0;
1552 leftmost_after_zoom = current_rightmost - new_page_size;
1556 case ZoomFocusCenter:
1557 current_center = current_leftmost + (current_page/2);
1558 if (current_center < half_page_size) {
1559 leftmost_after_zoom = 0;
1561 leftmost_after_zoom = current_center - half_page_size;
1565 case ZoomFocusPlayhead:
1566 /* centre playhead */
1567 l = playhead_cursor->current_frame () - (new_page_size * 0.5);
1570 leftmost_after_zoom = 0;
1571 } else if (l > max_framepos) {
1572 leftmost_after_zoom = max_framepos - new_page_size;
1574 leftmost_after_zoom = (framepos_t) l;
1578 case ZoomFocusMouse:
1579 /* try to keep the mouse over the same point in the display */
1581 if (!mouse_frame (where, in_track_canvas)) {
1582 /* use playhead instead */
1583 where = playhead_cursor->current_frame ();
1585 if (where < half_page_size) {
1586 leftmost_after_zoom = 0;
1588 leftmost_after_zoom = where - half_page_size;
1593 l = - ((new_page_size * ((where - current_leftmost)/(double)current_page)) - where);
1596 leftmost_after_zoom = 0;
1597 } else if (l > max_framepos) {
1598 leftmost_after_zoom = max_framepos - new_page_size;
1600 leftmost_after_zoom = (framepos_t) l;
1607 /* try to keep the edit point in the same place */
1608 where = get_preferred_edit_position ();
1612 double l = - ((new_page_size * ((where - current_leftmost)/(double)current_page)) - where);
1615 leftmost_after_zoom = 0;
1616 } else if (l > max_framepos) {
1617 leftmost_after_zoom = max_framepos - new_page_size;
1619 leftmost_after_zoom = (framepos_t) l;
1623 /* edit point not defined */
1630 // leftmost_after_zoom = min (leftmost_after_zoom, _session->current_end_frame());
1632 reposition_and_zoom (leftmost_after_zoom, nfpp);
1636 Editor::temporal_zoom_region (bool both_axes)
1638 framepos_t start = max_framepos;
1640 set<TimeAxisView*> tracks;
1642 RegionSelection rs = get_regions_from_selection_and_entered ();
1648 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
1650 if ((*i)->region()->position() < start) {
1651 start = (*i)->region()->position();
1654 if ((*i)->region()->last_frame() + 1 > end) {
1655 end = (*i)->region()->last_frame() + 1;
1658 tracks.insert (&((*i)->get_time_axis_view()));
1661 /* now comes an "interesting" hack ... make sure we leave a little space
1662 at each end of the editor so that the zoom doesn't fit the region
1663 precisely to the screen.
1666 GdkScreen* screen = gdk_screen_get_default ();
1667 gint pixwidth = gdk_screen_get_width (screen);
1668 gint mmwidth = gdk_screen_get_width_mm (screen);
1669 double pix_per_mm = (double) pixwidth/ (double) mmwidth;
1670 double one_centimeter_in_pixels = pix_per_mm * 10.0;
1672 if ((start == 0 && end == 0) || end < start) {
1676 framepos_t range = end - start;
1677 double new_fpp = (double) range / (double) _visible_canvas_width;
1678 framepos_t extra_samples = (framepos_t) floor (one_centimeter_in_pixels * new_fpp);
1680 if (start > extra_samples) {
1681 start -= extra_samples;
1686 if (max_framepos - extra_samples > end) {
1687 end += extra_samples;
1692 /* if we're zooming on both axes we need to save track heights etc.
1695 undo_visual_stack.push_back (current_visual_state (both_axes));
1697 PBD::Unwinder<bool> nsv (no_save_visual, true);
1699 temporal_zoom_by_frame (start, end);
1702 uint32_t per_track_height = (uint32_t) floor ((_visible_canvas_height - 10.0) / tracks.size());
1704 /* set visible track heights appropriately */
1706 for (set<TimeAxisView*>::iterator t = tracks.begin(); t != tracks.end(); ++t) {
1707 (*t)->set_height (per_track_height);
1710 /* hide irrelevant tracks */
1712 _routes->suspend_redisplay ();
1714 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1715 if (find (tracks.begin(), tracks.end(), (*i)) == tracks.end()) {
1716 hide_track_in_display (*i);
1720 _routes->resume_redisplay ();
1722 vertical_adjustment.set_value (0.0);
1725 redo_visual_stack.push_back (current_visual_state (both_axes));
1729 Editor::zoom_to_region (bool both_axes)
1731 temporal_zoom_region (both_axes);
1735 Editor::temporal_zoom_selection ()
1737 if (!selection) return;
1739 if (selection->time.empty()) {
1743 framepos_t start = selection->time[clicked_selection].start;
1744 framepos_t end = selection->time[clicked_selection].end;
1746 temporal_zoom_by_frame (start, end);
1750 Editor::temporal_zoom_session ()
1752 ENSURE_GUI_THREAD (*this, &Editor::temporal_zoom_session)
1755 framecnt_t const l = _session->current_end_frame() - _session->current_start_frame();
1756 double s = _session->current_start_frame() - l * 0.01;
1760 framecnt_t const e = _session->current_end_frame() + l * 0.01;
1761 temporal_zoom_by_frame (framecnt_t (s), e);
1766 Editor::temporal_zoom_by_frame (framepos_t start, framepos_t end)
1768 if (!_session) return;
1770 if ((start == 0 && end == 0) || end < start) {
1774 framepos_t range = end - start;
1776 double const new_fpp = (double) range / (double) _visible_canvas_width;
1778 framepos_t new_page = (framepos_t) floor (_visible_canvas_width * new_fpp);
1779 framepos_t middle = (framepos_t) floor ((double) start + ((double) range / 2.0f));
1780 framepos_t new_leftmost = (framepos_t) floor ((double) middle - ((double) new_page / 2.0f));
1782 if (new_leftmost > middle) {
1786 if (new_leftmost < 0) {
1790 reposition_and_zoom (new_leftmost, new_fpp);
1794 Editor::temporal_zoom_to_frame (bool coarser, framepos_t frame)
1800 framecnt_t range_before = frame - leftmost_frame;
1804 if (samples_per_pixel <= 1) {
1807 new_spp = samples_per_pixel + (samples_per_pixel/2);
1809 range_before += range_before/2;
1811 if (samples_per_pixel >= 1) {
1812 new_spp = samples_per_pixel - (samples_per_pixel/2);
1814 /* could bail out here since we cannot zoom any finer,
1815 but leave that to the clamp_samples_per_pixel() and
1818 new_spp = samples_per_pixel;
1821 range_before -= range_before/2;
1824 clamp_samples_per_pixel (new_spp);
1826 if (new_spp == samples_per_pixel) {
1830 /* zoom focus is automatically taken as @param frame when this
1834 framepos_t new_leftmost = frame - (framepos_t)range_before;
1836 if (new_leftmost > frame) {
1840 if (new_leftmost < 0) {
1844 reposition_and_zoom (new_leftmost, new_spp);
1849 Editor::choose_new_marker_name(string &name) {
1851 if (!Config->get_name_new_markers()) {
1852 /* don't prompt user for a new name */
1856 ArdourPrompter dialog (true);
1858 dialog.set_prompt (_("New Name:"));
1860 dialog.set_title (_("New Location Marker"));
1862 dialog.set_name ("MarkNameWindow");
1863 dialog.set_size_request (250, -1);
1864 dialog.set_position (Gtk::WIN_POS_MOUSE);
1866 dialog.add_button (Stock::OK, RESPONSE_ACCEPT);
1867 dialog.set_initial_text (name);
1871 switch (dialog.run ()) {
1872 case RESPONSE_ACCEPT:
1878 dialog.get_result(name);
1885 Editor::add_location_from_selection ()
1889 if (selection->time.empty()) {
1893 if (_session == 0 || clicked_axisview == 0) {
1897 framepos_t start = selection->time[clicked_selection].start;
1898 framepos_t end = selection->time[clicked_selection].end;
1900 _session->locations()->next_available_name(rangename,"selection");
1901 Location *location = new Location (*_session, start, end, rangename, Location::IsRangeMarker);
1903 _session->begin_reversible_command (_("add marker"));
1904 XMLNode &before = _session->locations()->get_state();
1905 _session->locations()->add (location, true);
1906 XMLNode &after = _session->locations()->get_state();
1907 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
1908 _session->commit_reversible_command ();
1912 Editor::add_location_mark (framepos_t where)
1916 select_new_marker = true;
1918 _session->locations()->next_available_name(markername,"mark");
1919 if (!choose_new_marker_name(markername)) {
1922 Location *location = new Location (*_session, where, where, markername, Location::IsMark);
1923 _session->begin_reversible_command (_("add marker"));
1924 XMLNode &before = _session->locations()->get_state();
1925 _session->locations()->add (location, true);
1926 XMLNode &after = _session->locations()->get_state();
1927 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
1928 _session->commit_reversible_command ();
1932 Editor::add_location_from_playhead_cursor ()
1934 add_location_mark (_session->audible_frame());
1937 /** Add a range marker around each selected region */
1939 Editor::add_locations_from_region ()
1941 RegionSelection rs = get_regions_from_selection_and_entered ();
1947 _session->begin_reversible_command (selection->regions.size () > 1 ? _("add markers") : _("add marker"));
1948 XMLNode &before = _session->locations()->get_state();
1950 for (RegionSelection::iterator i = rs.begin (); i != rs.end (); ++i) {
1952 boost::shared_ptr<Region> region = (*i)->region ();
1954 Location *location = new Location (*_session, region->position(), region->last_frame(), region->name(), Location::IsRangeMarker);
1956 _session->locations()->add (location, true);
1959 XMLNode &after = _session->locations()->get_state();
1960 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
1961 _session->commit_reversible_command ();
1964 /** Add a single range marker around all selected regions */
1966 Editor::add_location_from_region ()
1968 RegionSelection rs = get_regions_from_selection_and_entered ();
1974 _session->begin_reversible_command (_("add marker"));
1975 XMLNode &before = _session->locations()->get_state();
1979 if (rs.size() > 1) {
1980 _session->locations()->next_available_name(markername, "regions");
1982 RegionView* rv = *(rs.begin());
1983 boost::shared_ptr<Region> region = rv->region();
1984 markername = region->name();
1987 if (!choose_new_marker_name(markername)) {
1991 // single range spanning all selected
1992 Location *location = new Location (*_session, selection->regions.start(), selection->regions.end_frame(), markername, Location::IsRangeMarker);
1993 _session->locations()->add (location, true);
1995 XMLNode &after = _session->locations()->get_state();
1996 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
1997 _session->commit_reversible_command ();
2003 Editor::jump_forward_to_mark ()
2009 framepos_t pos = _session->locations()->first_mark_after (playhead_cursor->current_frame());
2015 _session->request_locate (pos, _session->transport_rolling());
2019 Editor::jump_backward_to_mark ()
2025 framepos_t pos = _session->locations()->first_mark_before (playhead_cursor->current_frame());
2031 _session->request_locate (pos, _session->transport_rolling());
2037 framepos_t const pos = _session->audible_frame ();
2040 _session->locations()->next_available_name (markername, "mark");
2042 if (!choose_new_marker_name (markername)) {
2046 _session->locations()->add (new Location (*_session, pos, 0, markername, Location::IsMark), true);
2050 Editor::clear_markers ()
2053 _session->begin_reversible_command (_("clear markers"));
2054 XMLNode &before = _session->locations()->get_state();
2055 _session->locations()->clear_markers ();
2056 XMLNode &after = _session->locations()->get_state();
2057 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2058 _session->commit_reversible_command ();
2063 Editor::clear_ranges ()
2066 _session->begin_reversible_command (_("clear ranges"));
2067 XMLNode &before = _session->locations()->get_state();
2069 Location * looploc = _session->locations()->auto_loop_location();
2070 Location * punchloc = _session->locations()->auto_punch_location();
2071 Location * sessionloc = _session->locations()->session_range_location();
2073 _session->locations()->clear_ranges ();
2075 if (looploc) _session->locations()->add (looploc);
2076 if (punchloc) _session->locations()->add (punchloc);
2077 if (sessionloc) _session->locations()->add (sessionloc);
2079 XMLNode &after = _session->locations()->get_state();
2080 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2081 _session->commit_reversible_command ();
2086 Editor::clear_locations ()
2088 _session->begin_reversible_command (_("clear locations"));
2089 XMLNode &before = _session->locations()->get_state();
2090 _session->locations()->clear ();
2091 XMLNode &after = _session->locations()->get_state();
2092 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2093 _session->commit_reversible_command ();
2094 _session->locations()->clear ();
2098 Editor::unhide_markers ()
2100 for (LocationMarkerMap::iterator i = location_markers.begin(); i != location_markers.end(); ++i) {
2101 Location *l = (*i).first;
2102 if (l->is_hidden() && l->is_mark()) {
2103 l->set_hidden(false, this);
2109 Editor::unhide_ranges ()
2111 for (LocationMarkerMap::iterator i = location_markers.begin(); i != location_markers.end(); ++i) {
2112 Location *l = (*i).first;
2113 if (l->is_hidden() && l->is_range_marker()) {
2114 l->set_hidden(false, this);
2119 /* INSERT/REPLACE */
2122 Editor::insert_region_list_drag (boost::shared_ptr<Region> region, int x, int y)
2126 RouteTimeAxisView *rtv = 0;
2127 boost::shared_ptr<Playlist> playlist;
2130 event.type = GDK_BUTTON_RELEASE;
2134 where = window_event_sample (&event, &cx, &cy);
2136 if (where < leftmost_frame || where > leftmost_frame + current_page_samples()) {
2137 /* clearly outside canvas area */
2141 std::pair<TimeAxisView*, int> tv = trackview_by_y_position (cy);
2142 if (tv.first == 0) {
2146 if ((rtv = dynamic_cast<RouteTimeAxisView*> (tv.first)) == 0) {
2150 if ((playlist = rtv->playlist()) == 0) {
2156 begin_reversible_command (_("insert dragged region"));
2157 playlist->clear_changes ();
2158 playlist->add_region (RegionFactory::create (region, true), where, 1.0);
2159 _session->add_command(new StatefulDiffCommand (playlist));
2160 commit_reversible_command ();
2164 Editor::insert_route_list_drag (boost::shared_ptr<Route> route, int x, int y)
2167 RouteTimeAxisView *dest_rtv = 0;
2168 RouteTimeAxisView *source_rtv = 0;
2171 event.type = GDK_BUTTON_RELEASE;
2175 window_event_sample (&event, &cx, &cy);
2177 std::pair<TimeAxisView*, int> const tv = trackview_by_y_position (cy);
2178 if (tv.first == 0) {
2182 if ((dest_rtv = dynamic_cast<RouteTimeAxisView*> (tv.first)) == 0) {
2186 /* use this drag source to add underlay to a track. But we really don't care
2187 about the Route, only the view of the route, so find it first */
2188 for(TrackViewList::iterator it = track_views.begin(); it != track_views.end(); ++it) {
2189 if((source_rtv = dynamic_cast<RouteTimeAxisView*>(*it)) == 0) {
2193 if(source_rtv->route() == route && source_rtv != dest_rtv) {
2194 dest_rtv->add_underlay(source_rtv->view());
2201 Editor::insert_region_list_selection (float times)
2203 RouteTimeAxisView *tv = 0;
2204 boost::shared_ptr<Playlist> playlist;
2206 if (clicked_routeview != 0) {
2207 tv = clicked_routeview;
2208 } else if (!selection->tracks.empty()) {
2209 if ((tv = dynamic_cast<RouteTimeAxisView*>(selection->tracks.front())) == 0) {
2212 } else if (entered_track != 0) {
2213 if ((tv = dynamic_cast<RouteTimeAxisView*>(entered_track)) == 0) {
2220 if ((playlist = tv->playlist()) == 0) {
2224 boost::shared_ptr<Region> region = _regions->get_single_selection ();
2229 begin_reversible_command (_("insert region"));
2230 playlist->clear_changes ();
2231 playlist->add_region ((RegionFactory::create (region, true)), get_preferred_edit_position(), times);
2232 _session->add_command(new StatefulDiffCommand (playlist));
2233 commit_reversible_command ();
2236 /* BUILT-IN EFFECTS */
2239 Editor::reverse_selection ()
2244 /* GAIN ENVELOPE EDITING */
2247 Editor::edit_envelope ()
2254 Editor::transition_to_rolling (bool fwd)
2260 if (_session->config.get_external_sync()) {
2261 switch (Config->get_sync_source()) {
2265 /* transport controlled by the master */
2270 if (_session->is_auditioning()) {
2271 _session->cancel_audition ();
2275 _session->request_transport_speed (fwd ? 1.0f : -1.0f);
2279 Editor::play_from_start ()
2281 _session->request_locate (_session->current_start_frame(), true);
2285 Editor::play_from_edit_point ()
2287 _session->request_locate (get_preferred_edit_position(), true);
2291 Editor::play_from_edit_point_and_return ()
2293 framepos_t start_frame;
2294 framepos_t return_frame;
2296 start_frame = get_preferred_edit_position (true);
2298 if (_session->transport_rolling()) {
2299 _session->request_locate (start_frame, false);
2303 /* don't reset the return frame if its already set */
2305 if ((return_frame = _session->requested_return_frame()) < 0) {
2306 return_frame = _session->audible_frame();
2309 if (start_frame >= 0) {
2310 _session->request_roll_at_and_return (start_frame, return_frame);
2315 Editor::play_selection ()
2317 if (selection->time.empty()) {
2321 _session->request_play_range (&selection->time, true);
2325 Editor::get_preroll ()
2327 return 1.0 /*Config->get_edit_preroll_seconds()*/ * _session->frame_rate();
2332 Editor::maybe_locate_with_edit_preroll ( framepos_t location )
2334 if ( _session->transport_rolling() || !Config->get_always_play_range() )
2337 location -= get_preroll();
2339 //don't try to locate before the beginning of time
2343 //if follow_playhead is on, keep the playhead on the screen
2344 if ( _follow_playhead )
2345 if ( location < leftmost_frame )
2346 location = leftmost_frame;
2348 _session->request_locate( location );
2352 Editor::play_with_preroll ()
2354 if (selection->time.empty()) {
2357 framepos_t preroll = get_preroll();
2359 framepos_t start = 0;
2360 if (selection->time[clicked_selection].start > preroll)
2361 start = selection->time[clicked_selection].start - preroll;
2363 framepos_t end = selection->time[clicked_selection].end + preroll;
2365 AudioRange ar (start, end, 0);
2366 list<AudioRange> lar;
2369 _session->request_play_range (&lar, true);
2374 Editor::play_location (Location& location)
2376 if (location.start() <= location.end()) {
2380 _session->request_bounded_roll (location.start(), location.end());
2384 Editor::loop_location (Location& location)
2386 if (location.start() <= location.end()) {
2392 if ((tll = transport_loop_location()) != 0) {
2393 tll->set (location.start(), location.end());
2395 // enable looping, reposition and start rolling
2396 _session->request_play_loop (true);
2397 _session->request_locate (tll->start(), true);
2402 Editor::do_layer_operation (LayerOperation op)
2404 if (selection->regions.empty ()) {
2408 bool const multiple = selection->regions.size() > 1;
2412 begin_reversible_command (_("raise regions"));
2414 begin_reversible_command (_("raise region"));
2420 begin_reversible_command (_("raise regions to top"));
2422 begin_reversible_command (_("raise region to top"));
2428 begin_reversible_command (_("lower regions"));
2430 begin_reversible_command (_("lower region"));
2436 begin_reversible_command (_("lower regions to bottom"));
2438 begin_reversible_command (_("lower region"));
2443 set<boost::shared_ptr<Playlist> > playlists = selection->regions.playlists ();
2444 for (set<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
2445 (*i)->clear_owned_changes ();
2448 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
2449 boost::shared_ptr<Region> r = (*i)->region ();
2461 r->lower_to_bottom ();
2465 for (set<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
2466 vector<Command*> cmds;
2468 _session->add_commands (cmds);
2471 commit_reversible_command ();
2475 Editor::raise_region ()
2477 do_layer_operation (Raise);
2481 Editor::raise_region_to_top ()
2483 do_layer_operation (RaiseToTop);
2487 Editor::lower_region ()
2489 do_layer_operation (Lower);
2493 Editor::lower_region_to_bottom ()
2495 do_layer_operation (LowerToBottom);
2498 /** Show the region editor for the selected regions */
2500 Editor::show_region_properties ()
2502 selection->foreach_regionview (&RegionView::show_region_editor);
2505 /** Show the midi list editor for the selected MIDI regions */
2507 Editor::show_midi_list_editor ()
2509 selection->foreach_midi_regionview (&MidiRegionView::show_list_editor);
2513 Editor::rename_region ()
2515 RegionSelection rs = get_regions_from_selection_and_entered ();
2521 ArdourDialog d (*this, _("Rename Region"), true, false);
2523 Label label (_("New name:"));
2526 hbox.set_spacing (6);
2527 hbox.pack_start (label, false, false);
2528 hbox.pack_start (entry, true, true);
2530 d.get_vbox()->set_border_width (12);
2531 d.get_vbox()->pack_start (hbox, false, false);
2533 d.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
2534 d.add_button(Gtk::Stock::OK, Gtk::RESPONSE_OK);
2536 d.set_size_request (300, -1);
2538 entry.set_text (rs.front()->region()->name());
2539 entry.select_region (0, -1);
2541 entry.signal_activate().connect (sigc::bind (sigc::mem_fun (d, &Dialog::response), RESPONSE_OK));
2547 int const ret = d.run();
2551 if (ret != RESPONSE_OK) {
2555 std::string str = entry.get_text();
2556 strip_whitespace_edges (str);
2558 rs.front()->region()->set_name (str);
2559 _regions->redisplay ();
2564 Editor::audition_playlist_region_via_route (boost::shared_ptr<Region> region, Route& route)
2566 if (_session->is_auditioning()) {
2567 _session->cancel_audition ();
2570 // note: some potential for creativity here, because region doesn't
2571 // have to belong to the playlist that Route is handling
2573 // bool was_soloed = route.soloed();
2575 route.set_solo (true, this);
2577 _session->request_bounded_roll (region->position(), region->position() + region->length());
2579 /* XXX how to unset the solo state ? */
2582 /** Start an audition of the first selected region */
2584 Editor::play_edit_range ()
2586 framepos_t start, end;
2588 if (get_edit_op_range (start, end)) {
2589 _session->request_bounded_roll (start, end);
2594 Editor::play_selected_region ()
2596 framepos_t start = max_framepos;
2599 RegionSelection rs = get_regions_from_selection_and_entered ();
2605 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
2606 if ((*i)->region()->position() < start) {
2607 start = (*i)->region()->position();
2609 if ((*i)->region()->last_frame() + 1 > end) {
2610 end = (*i)->region()->last_frame() + 1;
2614 _session->request_bounded_roll (start, end);
2618 Editor::audition_playlist_region_standalone (boost::shared_ptr<Region> region)
2620 _session->audition_region (region);
2624 Editor::region_from_selection ()
2626 if (clicked_axisview == 0) {
2630 if (selection->time.empty()) {
2634 framepos_t start = selection->time[clicked_selection].start;
2635 framepos_t end = selection->time[clicked_selection].end;
2637 TrackViewList tracks = get_tracks_for_range_action ();
2639 framepos_t selection_cnt = end - start + 1;
2641 for (TrackSelection::iterator i = tracks.begin(); i != tracks.end(); ++i) {
2642 boost::shared_ptr<Region> current;
2643 boost::shared_ptr<Playlist> pl;
2644 framepos_t internal_start;
2647 if ((pl = (*i)->playlist()) == 0) {
2651 if ((current = pl->top_region_at (start)) == 0) {
2655 internal_start = start - current->position();
2656 RegionFactory::region_name (new_name, current->name(), true);
2660 plist.add (ARDOUR::Properties::start, current->start() + internal_start);
2661 plist.add (ARDOUR::Properties::length, selection_cnt);
2662 plist.add (ARDOUR::Properties::name, new_name);
2663 plist.add (ARDOUR::Properties::layer, 0);
2665 boost::shared_ptr<Region> region (RegionFactory::create (current, plist));
2670 Editor::create_region_from_selection (vector<boost::shared_ptr<Region> >& new_regions)
2672 if (selection->time.empty() || selection->tracks.empty()) {
2676 framepos_t start = selection->time[clicked_selection].start;
2677 framepos_t end = selection->time[clicked_selection].end;
2679 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
2680 sort_track_selection (ts);
2682 for (TrackSelection::iterator i = ts.begin(); i != ts.end(); ++i) {
2683 boost::shared_ptr<Region> current;
2684 boost::shared_ptr<Playlist> playlist;
2685 framepos_t internal_start;
2688 if ((playlist = (*i)->playlist()) == 0) {
2692 if ((current = playlist->top_region_at(start)) == 0) {
2696 internal_start = start - current->position();
2697 RegionFactory::region_name (new_name, current->name(), true);
2701 plist.add (ARDOUR::Properties::start, current->start() + internal_start);
2702 plist.add (ARDOUR::Properties::length, end - start + 1);
2703 plist.add (ARDOUR::Properties::name, new_name);
2705 new_regions.push_back (RegionFactory::create (current, plist));
2710 Editor::split_multichannel_region ()
2712 RegionSelection rs = get_regions_from_selection_and_entered ();
2718 vector< boost::shared_ptr<Region> > v;
2720 for (list<RegionView*>::iterator x = rs.begin(); x != rs.end(); ++x) {
2721 (*x)->region()->separate_by_channel (*_session, v);
2726 Editor::new_region_from_selection ()
2728 region_from_selection ();
2729 cancel_selection ();
2733 add_if_covered (RegionView* rv, const AudioRange* ar, RegionSelection* rs)
2735 switch (rv->region()->coverage (ar->start, ar->end - 1)) {
2736 case Evoral::OverlapNone:
2744 * - selected tracks, or if there are none...
2745 * - tracks containing selected regions, or if there are none...
2750 Editor::get_tracks_for_range_action () const
2754 if (selection->tracks.empty()) {
2756 /* use tracks with selected regions */
2758 RegionSelection rs = selection->regions;
2760 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
2761 TimeAxisView* tv = &(*i)->get_time_axis_view();
2763 if (!t.contains (tv)) {
2769 /* no regions and no tracks: use all tracks */
2775 t = selection->tracks;
2778 return t.filter_to_unique_playlists();
2782 Editor::separate_regions_between (const TimeSelection& ts)
2784 bool in_command = false;
2785 boost::shared_ptr<Playlist> playlist;
2786 RegionSelection new_selection;
2788 TrackViewList tmptracks = get_tracks_for_range_action ();
2789 sort_track_selection (tmptracks);
2791 for (TrackSelection::iterator i = tmptracks.begin(); i != tmptracks.end(); ++i) {
2793 RouteTimeAxisView* rtv;
2795 if ((rtv = dynamic_cast<RouteTimeAxisView*> ((*i))) != 0) {
2797 if (rtv->is_track()) {
2799 /* no edits to destructive tracks */
2801 if (rtv->track()->destructive()) {
2805 if ((playlist = rtv->playlist()) != 0) {
2807 playlist->clear_changes ();
2809 /* XXX need to consider musical time selections here at some point */
2811 double speed = rtv->track()->speed();
2814 for (list<AudioRange>::const_iterator t = ts.begin(); t != ts.end(); ++t) {
2816 sigc::connection c = rtv->view()->RegionViewAdded.connect (
2817 sigc::mem_fun(*this, &Editor::collect_new_region_view));
2819 latest_regionviews.clear ();
2821 playlist->partition ((framepos_t)((*t).start * speed),
2822 (framepos_t)((*t).end * speed), false);
2826 if (!latest_regionviews.empty()) {
2828 rtv->view()->foreach_regionview (sigc::bind (
2829 sigc::ptr_fun (add_if_covered),
2830 &(*t), &new_selection));
2833 begin_reversible_command (_("separate"));
2837 /* pick up changes to existing regions */
2839 vector<Command*> cmds;
2840 playlist->rdiff (cmds);
2841 _session->add_commands (cmds);
2843 /* pick up changes to the playlist itself (adds/removes)
2846 _session->add_command(new StatefulDiffCommand (playlist));
2855 selection->set (new_selection);
2856 set_mouse_mode (MouseObject);
2858 commit_reversible_command ();
2862 struct PlaylistState {
2863 boost::shared_ptr<Playlist> playlist;
2867 /** Take tracks from get_tracks_for_range_action and cut any regions
2868 * on those tracks so that the tracks are empty over the time
2872 Editor::separate_region_from_selection ()
2874 /* preferentially use *all* ranges in the time selection if we're in range mode
2875 to allow discontiguous operation, since get_edit_op_range() currently
2876 returns a single range.
2879 if (!selection->time.empty()) {
2881 separate_regions_between (selection->time);
2888 if (get_edit_op_range (start, end)) {
2890 AudioRange ar (start, end, 1);
2894 separate_regions_between (ts);
2900 Editor::separate_region_from_punch ()
2902 Location* loc = _session->locations()->auto_punch_location();
2904 separate_regions_using_location (*loc);
2909 Editor::separate_region_from_loop ()
2911 Location* loc = _session->locations()->auto_loop_location();
2913 separate_regions_using_location (*loc);
2918 Editor::separate_regions_using_location (Location& loc)
2920 if (loc.is_mark()) {
2924 AudioRange ar (loc.start(), loc.end(), 1);
2929 separate_regions_between (ts);
2932 /** Separate regions under the selected region */
2934 Editor::separate_under_selected_regions ()
2936 vector<PlaylistState> playlists;
2940 rs = get_regions_from_selection_and_entered();
2942 if (!_session || rs.empty()) {
2946 begin_reversible_command (_("separate region under"));
2948 list<boost::shared_ptr<Region> > regions_to_remove;
2950 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
2951 // we can't just remove the region(s) in this loop because
2952 // this removes them from the RegionSelection, and they thus
2953 // disappear from underneath the iterator, and the ++i above
2954 // SEGVs in a puzzling fashion.
2956 // so, first iterate over the regions to be removed from rs and
2957 // add them to the regions_to_remove list, and then
2958 // iterate over the list to actually remove them.
2960 regions_to_remove.push_back ((*i)->region());
2963 for (list<boost::shared_ptr<Region> >::iterator rl = regions_to_remove.begin(); rl != regions_to_remove.end(); ++rl) {
2965 boost::shared_ptr<Playlist> playlist = (*rl)->playlist();
2968 // is this check necessary?
2972 vector<PlaylistState>::iterator i;
2974 //only take state if this is a new playlist.
2975 for (i = playlists.begin(); i != playlists.end(); ++i) {
2976 if ((*i).playlist == playlist) {
2981 if (i == playlists.end()) {
2983 PlaylistState before;
2984 before.playlist = playlist;
2985 before.before = &playlist->get_state();
2987 playlist->freeze ();
2988 playlists.push_back(before);
2991 //Partition on the region bounds
2992 playlist->partition ((*rl)->first_frame() - 1, (*rl)->last_frame() + 1, true);
2994 //Re-add region that was just removed due to the partition operation
2995 playlist->add_region( (*rl), (*rl)->first_frame() );
2998 vector<PlaylistState>::iterator pl;
3000 for (pl = playlists.begin(); pl != playlists.end(); ++pl) {
3001 (*pl).playlist->thaw ();
3002 _session->add_command(new MementoCommand<Playlist>(*(*pl).playlist, (*pl).before, &(*pl).playlist->get_state()));
3005 commit_reversible_command ();
3009 Editor::crop_region_to_selection ()
3011 if (!selection->time.empty()) {
3013 crop_region_to (selection->time.start(), selection->time.end_frame());
3020 if (get_edit_op_range (start, end)) {
3021 crop_region_to (start, end);
3028 Editor::crop_region_to (framepos_t start, framepos_t end)
3030 vector<boost::shared_ptr<Playlist> > playlists;
3031 boost::shared_ptr<Playlist> playlist;
3034 if (selection->tracks.empty()) {
3035 ts = track_views.filter_to_unique_playlists();
3037 ts = selection->tracks.filter_to_unique_playlists ();
3040 sort_track_selection (ts);
3042 for (TrackSelection::iterator i = ts.begin(); i != ts.end(); ++i) {
3044 RouteTimeAxisView* rtv;
3046 if ((rtv = dynamic_cast<RouteTimeAxisView*> ((*i))) != 0) {
3048 boost::shared_ptr<Track> t = rtv->track();
3050 if (t != 0 && ! t->destructive()) {
3052 if ((playlist = rtv->playlist()) != 0) {
3053 playlists.push_back (playlist);
3059 if (playlists.empty()) {
3063 framepos_t the_start;
3067 begin_reversible_command (_("trim to selection"));
3069 for (vector<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
3071 boost::shared_ptr<Region> region;
3075 if ((region = (*i)->top_region_at(the_start)) == 0) {
3079 /* now adjust lengths to that we do the right thing
3080 if the selection extends beyond the region
3083 the_start = max (the_start, (framepos_t) region->position());
3084 if (max_framepos - the_start < region->length()) {
3085 the_end = the_start + region->length() - 1;
3087 the_end = max_framepos;
3089 the_end = min (end, the_end);
3090 cnt = the_end - the_start + 1;
3092 region->clear_changes ();
3093 region->trim_to (the_start, cnt);
3094 _session->add_command (new StatefulDiffCommand (region));
3097 commit_reversible_command ();
3101 Editor::region_fill_track ()
3103 RegionSelection rs = get_regions_from_selection_and_entered ();
3105 if (!_session || rs.empty()) {
3109 framepos_t const end = _session->current_end_frame ();
3111 begin_reversible_command (Operations::region_fill);
3113 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3115 boost::shared_ptr<Region> region ((*i)->region());
3117 boost::shared_ptr<Playlist> pl = region->playlist();
3119 if (end <= region->last_frame()) {
3123 double times = (double) (end - region->last_frame()) / (double) region->length();
3129 pl->clear_changes ();
3130 pl->add_region (RegionFactory::create (region, true), region->last_frame(), times);
3131 _session->add_command (new StatefulDiffCommand (pl));
3134 commit_reversible_command ();
3138 Editor::region_fill_selection ()
3140 if (clicked_routeview == 0 || !clicked_routeview->is_audio_track()) {
3144 if (selection->time.empty()) {
3148 boost::shared_ptr<Region> region = _regions->get_single_selection ();
3153 framepos_t start = selection->time[clicked_selection].start;
3154 framepos_t end = selection->time[clicked_selection].end;
3156 boost::shared_ptr<Playlist> playlist;
3158 if (selection->tracks.empty()) {
3162 framepos_t selection_length = end - start;
3163 float times = (float)selection_length / region->length();
3165 begin_reversible_command (Operations::fill_selection);
3167 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
3169 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
3171 if ((playlist = (*i)->playlist()) == 0) {
3175 playlist->clear_changes ();
3176 playlist->add_region (RegionFactory::create (region, true), start, times);
3177 _session->add_command (new StatefulDiffCommand (playlist));
3180 commit_reversible_command ();
3184 Editor::set_region_sync_position ()
3186 set_sync_point (get_preferred_edit_position (), get_regions_from_selection_and_edit_point ());
3190 Editor::set_sync_point (framepos_t where, const RegionSelection& rs)
3192 bool in_command = false;
3194 for (RegionSelection::const_iterator r = rs.begin(); r != rs.end(); ++r) {
3196 if (!(*r)->region()->covers (where)) {
3200 boost::shared_ptr<Region> region ((*r)->region());
3203 begin_reversible_command (_("set sync point"));
3207 region->clear_changes ();
3208 region->set_sync_position (where);
3209 _session->add_command(new StatefulDiffCommand (region));
3213 commit_reversible_command ();
3217 /** Remove the sync positions of the selection */
3219 Editor::remove_region_sync ()
3221 RegionSelection rs = get_regions_from_selection_and_entered ();
3227 begin_reversible_command (_("remove region sync"));
3229 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3231 (*i)->region()->clear_changes ();
3232 (*i)->region()->clear_sync_position ();
3233 _session->add_command(new StatefulDiffCommand ((*i)->region()));
3236 commit_reversible_command ();
3240 Editor::naturalize_region ()
3242 RegionSelection rs = get_regions_from_selection_and_entered ();
3248 if (rs.size() > 1) {
3249 begin_reversible_command (_("move regions to original position"));
3251 begin_reversible_command (_("move region to original position"));
3254 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3255 (*i)->region()->clear_changes ();
3256 (*i)->region()->move_to_natural_position ();
3257 _session->add_command (new StatefulDiffCommand ((*i)->region()));
3260 commit_reversible_command ();
3264 Editor::align_regions (RegionPoint what)
3266 RegionSelection const rs = get_regions_from_selection_and_edit_point ();
3272 begin_reversible_command (_("align selection"));
3274 framepos_t const position = get_preferred_edit_position ();
3276 for (RegionSelection::const_iterator i = rs.begin(); i != rs.end(); ++i) {
3277 align_region_internal ((*i)->region(), what, position);
3280 commit_reversible_command ();
3283 struct RegionSortByTime {
3284 bool operator() (const RegionView* a, const RegionView* b) {
3285 return a->region()->position() < b->region()->position();
3290 Editor::align_regions_relative (RegionPoint point)
3292 RegionSelection const rs = get_regions_from_selection_and_edit_point ();
3298 framepos_t const position = get_preferred_edit_position ();
3300 framepos_t distance = 0;
3304 list<RegionView*> sorted;
3305 rs.by_position (sorted);
3307 boost::shared_ptr<Region> r ((*sorted.begin())->region());
3312 if (position > r->position()) {
3313 distance = position - r->position();
3315 distance = r->position() - position;
3321 if (position > r->last_frame()) {
3322 distance = position - r->last_frame();
3323 pos = r->position() + distance;
3325 distance = r->last_frame() - position;
3326 pos = r->position() - distance;
3332 pos = r->adjust_to_sync (position);
3333 if (pos > r->position()) {
3334 distance = pos - r->position();
3336 distance = r->position() - pos;
3342 if (pos == r->position()) {
3346 begin_reversible_command (_("align selection (relative)"));
3348 /* move first one specially */
3350 r->clear_changes ();
3351 r->set_position (pos);
3352 _session->add_command(new StatefulDiffCommand (r));
3354 /* move rest by the same amount */
3358 for (list<RegionView*>::iterator i = sorted.begin(); i != sorted.end(); ++i) {
3360 boost::shared_ptr<Region> region ((*i)->region());
3362 region->clear_changes ();
3365 region->set_position (region->position() + distance);
3367 region->set_position (region->position() - distance);
3370 _session->add_command(new StatefulDiffCommand (region));
3374 commit_reversible_command ();
3378 Editor::align_region (boost::shared_ptr<Region> region, RegionPoint point, framepos_t position)
3380 begin_reversible_command (_("align region"));
3381 align_region_internal (region, point, position);
3382 commit_reversible_command ();
3386 Editor::align_region_internal (boost::shared_ptr<Region> region, RegionPoint point, framepos_t position)
3388 region->clear_changes ();
3392 region->set_position (region->adjust_to_sync (position));
3396 if (position > region->length()) {
3397 region->set_position (position - region->length());
3402 region->set_position (position);
3406 _session->add_command(new StatefulDiffCommand (region));
3410 Editor::trim_region_front ()
3416 Editor::trim_region_back ()
3418 trim_region (false);
3422 Editor::trim_region (bool front)
3424 framepos_t where = get_preferred_edit_position();
3425 RegionSelection rs = get_regions_from_selection_and_edit_point ();
3431 begin_reversible_command (front ? _("trim front") : _("trim back"));
3433 for (list<RegionView*>::const_iterator i = rs.by_layer().begin(); i != rs.by_layer().end(); ++i) {
3434 if (!(*i)->region()->locked()) {
3436 (*i)->region()->clear_changes ();
3439 (*i)->region()->trim_front (where);
3440 maybe_locate_with_edit_preroll ( where );
3442 (*i)->region()->trim_end (where);
3443 maybe_locate_with_edit_preroll ( where );
3446 _session->add_command (new StatefulDiffCommand ((*i)->region()));
3450 commit_reversible_command ();
3453 /** Trim the end of the selected regions to the position of the edit cursor */
3455 Editor::trim_region_to_loop ()
3457 Location* loc = _session->locations()->auto_loop_location();
3461 trim_region_to_location (*loc, _("trim to loop"));
3465 Editor::trim_region_to_punch ()
3467 Location* loc = _session->locations()->auto_punch_location();
3471 trim_region_to_location (*loc, _("trim to punch"));
3475 Editor::trim_region_to_location (const Location& loc, const char* str)
3477 RegionSelection rs = get_regions_from_selection_and_entered ();
3479 begin_reversible_command (str);
3481 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
3482 RegionView* rv = (*x);
3484 /* require region to span proposed trim */
3485 switch (rv->region()->coverage (loc.start(), loc.end())) {
3486 case Evoral::OverlapInternal:
3492 RouteTimeAxisView* tav = dynamic_cast<RouteTimeAxisView*> (&rv->get_time_axis_view());
3501 if (tav->track() != 0) {
3502 speed = tav->track()->speed();
3505 start = session_frame_to_track_frame (loc.start(), speed);
3506 end = session_frame_to_track_frame (loc.end(), speed);
3508 rv->region()->clear_changes ();
3509 rv->region()->trim_to (start, (end - start));
3510 _session->add_command(new StatefulDiffCommand (rv->region()));
3513 commit_reversible_command ();
3517 Editor::trim_region_to_previous_region_end ()
3519 return trim_to_region(false);
3523 Editor::trim_region_to_next_region_start ()
3525 return trim_to_region(true);
3529 Editor::trim_to_region(bool forward)
3531 RegionSelection rs = get_regions_from_selection_and_entered ();
3533 begin_reversible_command (_("trim to region"));
3535 boost::shared_ptr<Region> next_region;
3537 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
3539 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*x);
3545 AudioTimeAxisView* atav = dynamic_cast<AudioTimeAxisView*> (&arv->get_time_axis_view());
3553 if (atav->track() != 0) {
3554 speed = atav->track()->speed();
3558 boost::shared_ptr<Region> region = arv->region();
3559 boost::shared_ptr<Playlist> playlist (region->playlist());
3561 region->clear_changes ();
3565 next_region = playlist->find_next_region (region->first_frame(), Start, 1);
3571 region->trim_end((framepos_t) ( (next_region->first_frame() - 1) * speed));
3572 arv->region_changed (PropertyChange (ARDOUR::Properties::length));
3576 next_region = playlist->find_next_region (region->first_frame(), Start, 0);
3582 region->trim_front((framepos_t) ((next_region->last_frame() + 1) * speed));
3584 arv->region_changed (ARDOUR::bounds_change);
3587 _session->add_command(new StatefulDiffCommand (region));
3590 commit_reversible_command ();
3594 Editor::unfreeze_route ()
3596 if (clicked_routeview == 0 || !clicked_routeview->is_track()) {
3600 clicked_routeview->track()->unfreeze ();
3604 Editor::_freeze_thread (void* arg)
3606 return static_cast<Editor*>(arg)->freeze_thread ();
3610 Editor::freeze_thread ()
3612 /* create event pool because we may need to talk to the session */
3613 SessionEvent::create_per_thread_pool ("freeze events", 64);
3614 /* create per-thread buffers for process() tree to use */
3615 clicked_routeview->audio_track()->freeze_me (*current_interthread_info);
3616 current_interthread_info->done = true;
3621 Editor::freeze_route ()
3627 /* stop transport before we start. this is important */
3629 _session->request_transport_speed (0.0);
3631 /* wait for just a little while, because the above call is asynchronous */
3633 Glib::usleep (250000);
3635 if (clicked_routeview == 0 || !clicked_routeview->is_audio_track()) {
3639 if (!clicked_routeview->track()->bounceable (clicked_routeview->track()->main_outs(), true)) {
3641 _("This track/bus cannot be frozen because the signal adds or loses channels before reaching the outputs.\n"
3642 "This is typically caused by plugins that generate stereo output from mono input or vice versa.")
3644 d.set_title (_("Cannot freeze"));
3649 if (clicked_routeview->track()->has_external_redirects()) {
3650 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"
3651 "Freezing will only process the signal as far as the first send/insert/return."),
3652 clicked_routeview->track()->name()), true, MESSAGE_INFO, BUTTONS_NONE, true);
3654 d.add_button (_("Freeze anyway"), Gtk::RESPONSE_OK);
3655 d.add_button (_("Don't freeze"), Gtk::RESPONSE_CANCEL);
3656 d.set_title (_("Freeze Limits"));
3658 int response = d.run ();
3661 case Gtk::RESPONSE_CANCEL:
3668 InterThreadInfo itt;
3669 current_interthread_info = &itt;
3671 InterthreadProgressWindow ipw (current_interthread_info, _("Freeze"), _("Cancel Freeze"));
3673 pthread_create_and_store (X_("freezer"), &itt.thread, _freeze_thread, this);
3675 set_canvas_cursor (_cursors->wait);
3677 while (!itt.done && !itt.cancel) {
3678 gtk_main_iteration ();
3681 current_interthread_info = 0;
3682 set_canvas_cursor (current_canvas_cursor);
3686 Editor::bounce_range_selection (bool replace, bool enable_processing)
3688 if (selection->time.empty()) {
3692 TrackSelection views = selection->tracks;
3694 for (TrackViewList::iterator i = views.begin(); i != views.end(); ++i) {
3696 if (enable_processing) {
3698 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*i);
3700 if (rtv && rtv->track() && replace && enable_processing && !rtv->track()->bounceable (rtv->track()->main_outs(), false)) {
3702 _("You can't perform this operation because the processing of the signal "
3703 "will cause one or more of the tracks to end up with a region with more channels than this track has inputs.\n\n"
3704 "You can do this without processing, which is a different operation.")
3706 d.set_title (_("Cannot bounce"));
3713 framepos_t start = selection->time[clicked_selection].start;
3714 framepos_t end = selection->time[clicked_selection].end;
3715 framepos_t cnt = end - start + 1;
3717 begin_reversible_command (_("bounce range"));
3719 for (TrackViewList::iterator i = views.begin(); i != views.end(); ++i) {
3721 RouteTimeAxisView* rtv;
3723 if ((rtv = dynamic_cast<RouteTimeAxisView*> (*i)) == 0) {
3727 boost::shared_ptr<Playlist> playlist;
3729 if ((playlist = rtv->playlist()) == 0) {
3733 InterThreadInfo itt;
3735 playlist->clear_changes ();
3736 playlist->clear_owned_changes ();
3738 boost::shared_ptr<Region> r;
3740 if (enable_processing) {
3741 r = rtv->track()->bounce_range (start, start+cnt, itt, rtv->track()->main_outs(), false);
3743 r = rtv->track()->bounce_range (start, start+cnt, itt, boost::shared_ptr<Processor>(), false);
3751 list<AudioRange> ranges;
3752 ranges.push_back (AudioRange (start, start+cnt, 0));
3753 playlist->cut (ranges); // discard result
3754 playlist->add_region (r, start);
3757 vector<Command*> cmds;
3758 playlist->rdiff (cmds);
3759 _session->add_commands (cmds);
3761 _session->add_command (new StatefulDiffCommand (playlist));
3764 commit_reversible_command ();
3767 /** Delete selected regions, automation points or a time range */
3774 /** Cut selected regions, automation points or a time range */
3781 /** Copy selected regions, automation points or a time range */
3789 /** @return true if a Cut, Copy or Clear is possible */
3791 Editor::can_cut_copy () const
3793 switch (effective_mouse_mode()) {
3796 if (!selection->regions.empty() || !selection->points.empty()) {
3802 if (!selection->time.empty()) {
3815 /** Cut, copy or clear selected regions, automation points or a time range.
3816 * @param op Operation (Cut, Copy or Clear)
3819 Editor::cut_copy (CutCopyOp op)
3821 /* only cancel selection if cut/copy is successful.*/
3827 opname = _("delete");
3836 opname = _("clear");
3840 /* if we're deleting something, and the mouse is still pressed,
3841 the thing we started a drag for will be gone when we release
3842 the mouse button(s). avoid this. see part 2 at the end of
3846 if (op == Delete || op == Cut || op == Clear) {
3847 if (_drags->active ()) {
3852 if ( op != Clear ) //"Delete" doesn't change copy/paste buf
3853 cut_buffer->clear ();
3855 if (entered_marker) {
3857 /* cut/delete op while pointing at a marker */
3860 Location* loc = find_location_from_marker (entered_marker, ignored);
3862 if (_session && loc) {
3863 Glib::signal_idle().connect (sigc::bind (sigc::mem_fun(*this, &Editor::really_remove_marker), loc));
3870 if (internal_editing()) {
3872 switch (effective_mouse_mode()) {
3875 begin_reversible_command (opname + ' ' + X_("MIDI"));
3877 commit_reversible_command ();
3886 bool did_edit = false;
3888 switch (effective_mouse_mode()) {
3890 if (!selection->points.empty()) {
3891 begin_reversible_command (opname + _(" points"));
3893 cut_copy_points (op);
3894 if (op == Cut || op == Delete) {
3895 selection->clear_points ();
3902 if (!selection->regions.empty() || !selection->points.empty()) {
3906 if (selection->regions.empty()) {
3907 thing_name = _("points");
3908 } else if (selection->points.empty()) {
3909 thing_name = _("regions");
3911 thing_name = _("objects");
3914 begin_reversible_command (opname + ' ' + thing_name);
3917 if (!selection->regions.empty()) {
3918 cut_copy_regions (op, selection->regions);
3920 if (op == Cut || op == Delete) {
3921 selection->clear_regions ();
3925 if (!selection->points.empty()) {
3926 cut_copy_points (op);
3928 if (op == Cut || op == Delete) {
3929 selection->clear_points ();
3936 if (selection->time.empty()) {
3937 framepos_t start, end;
3938 /* no time selection, see if we can get an edit range
3941 if (get_edit_op_range (start, end)) {
3942 selection->set (start, end);
3945 if (!selection->time.empty()) {
3946 begin_reversible_command (opname + _(" range"));
3949 cut_copy_ranges (op);
3951 if (op == Cut || op == Delete) {
3952 selection->clear_time ();
3962 commit_reversible_command ();
3965 if (op == Delete || op == Cut || op == Clear) {
3970 struct AutomationRecord {
3971 AutomationRecord () : state (0) {}
3972 AutomationRecord (XMLNode* s) : state (s) {}
3974 XMLNode* state; ///< state before any operation
3975 boost::shared_ptr<Evoral::ControlList> copy; ///< copied events for the cut buffer
3978 /** Cut, copy or clear selected automation points.
3979 * @param op Operation (Cut, Copy or Clear)
3982 Editor::cut_copy_points (CutCopyOp op)
3984 if (selection->points.empty ()) {
3988 /* XXX: not ideal, as there may be more than one track involved in the point selection */
3989 _last_cut_copy_source_track = &selection->points.front()->line().trackview;
3991 /* Keep a record of the AutomationLists that we end up using in this operation */
3992 typedef std::map<boost::shared_ptr<AutomationList>, AutomationRecord> Lists;
3995 /* Go through all selected points, making an AutomationRecord for each distinct AutomationList */
3996 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
3997 boost::shared_ptr<AutomationList> al = (*i)->line().the_list();
3998 if (lists.find (al) == lists.end ()) {
3999 /* We haven't seen this list yet, so make a record for it. This includes
4000 taking a copy of its current state, in case this is needed for undo later.
4002 lists[al] = AutomationRecord (&al->get_state ());
4006 if (op == Cut || op == Copy) {
4007 /* This operation will involve putting things in the cut buffer, so create an empty
4008 ControlList for each of our source lists to put the cut buffer data in.
4010 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
4011 i->second.copy = i->first->create (i->first->parameter ());
4014 /* Add all selected points to the relevant copy ControlLists */
4015 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
4016 boost::shared_ptr<AutomationList> al = (*i)->line().the_list();
4017 AutomationList::const_iterator j = (*i)->model ();
4018 lists[al].copy->add ((*j)->when, (*j)->value);
4021 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
4022 /* Correct this copy list so that it starts at time 0 */
4023 double const start = i->second.copy->front()->when;
4024 for (AutomationList::iterator j = i->second.copy->begin(); j != i->second.copy->end(); ++j) {
4025 (*j)->when -= start;
4028 /* And add it to the cut buffer */
4029 cut_buffer->add (i->second.copy);
4033 if (op == Delete || op == Cut) {
4034 /* This operation needs to remove things from the main AutomationList, so do that now */
4036 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
4037 i->first->freeze ();
4040 /* Remove each selected point from its AutomationList */
4041 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
4042 boost::shared_ptr<AutomationList> al = (*i)->line().the_list();
4043 al->erase ((*i)->model ());
4046 /* Thaw the lists and add undo records for them */
4047 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
4048 boost::shared_ptr<AutomationList> al = i->first;
4050 _session->add_command (new MementoCommand<AutomationList> (*al.get(), i->second.state, &(al->get_state ())));
4055 /** Cut, copy or clear selected automation points.
4056 * @param op Operation (Cut, Copy or Clear)
4059 Editor::cut_copy_midi (CutCopyOp op)
4061 for (MidiRegionSelection::iterator i = selection->midi_regions.begin(); i != selection->midi_regions.end(); ++i) {
4062 MidiRegionView* mrv = *i;
4063 mrv->cut_copy_clear (op);
4069 struct lt_playlist {
4070 bool operator () (const PlaylistState& a, const PlaylistState& b) {
4071 return a.playlist < b.playlist;
4075 struct PlaylistMapping {
4077 boost::shared_ptr<Playlist> pl;
4079 PlaylistMapping (TimeAxisView* tvp) : tv (tvp) {}
4082 /** Remove `clicked_regionview' */
4084 Editor::remove_clicked_region ()
4086 if (clicked_routeview == 0 || clicked_regionview == 0) {
4090 boost::shared_ptr<Playlist> playlist = clicked_routeview->playlist();
4092 begin_reversible_command (_("remove region"));
4093 playlist->clear_changes ();
4094 playlist->clear_owned_changes ();
4095 playlist->remove_region (clicked_regionview->region());
4097 /* We might have removed regions, which alters other regions' layering_index,
4098 so we need to do a recursive diff here.
4100 vector<Command*> cmds;
4101 playlist->rdiff (cmds);
4102 _session->add_commands (cmds);
4104 _session->add_command(new StatefulDiffCommand (playlist));
4105 commit_reversible_command ();
4109 /** Remove the selected regions */
4111 Editor::remove_selected_regions ()
4113 RegionSelection rs = get_regions_from_selection_and_entered ();
4115 if (!_session || rs.empty()) {
4119 begin_reversible_command (_("remove region"));
4121 list<boost::shared_ptr<Region> > regions_to_remove;
4123 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
4124 // we can't just remove the region(s) in this loop because
4125 // this removes them from the RegionSelection, and they thus
4126 // disappear from underneath the iterator, and the ++i above
4127 // SEGVs in a puzzling fashion.
4129 // so, first iterate over the regions to be removed from rs and
4130 // add them to the regions_to_remove list, and then
4131 // iterate over the list to actually remove them.
4133 regions_to_remove.push_back ((*i)->region());
4136 vector<boost::shared_ptr<Playlist> > playlists;
4138 for (list<boost::shared_ptr<Region> >::iterator rl = regions_to_remove.begin(); rl != regions_to_remove.end(); ++rl) {
4140 boost::shared_ptr<Playlist> playlist = (*rl)->playlist();
4143 // is this check necessary?
4147 /* get_regions_from_selection_and_entered() guarantees that
4148 the playlists involved are unique, so there is no need
4152 playlists.push_back (playlist);
4154 playlist->clear_changes ();
4155 playlist->clear_owned_changes ();
4156 playlist->freeze ();
4157 playlist->remove_region (*rl);
4160 vector<boost::shared_ptr<Playlist> >::iterator pl;
4162 for (pl = playlists.begin(); pl != playlists.end(); ++pl) {
4165 /* We might have removed regions, which alters other regions' layering_index,
4166 so we need to do a recursive diff here.
4168 vector<Command*> cmds;
4169 (*pl)->rdiff (cmds);
4170 _session->add_commands (cmds);
4172 _session->add_command(new StatefulDiffCommand (*pl));
4175 commit_reversible_command ();
4178 /** Cut, copy or clear selected regions.
4179 * @param op Operation (Cut, Copy or Clear)
4182 Editor::cut_copy_regions (CutCopyOp op, RegionSelection& rs)
4184 /* we can't use a std::map here because the ordering is important, and we can't trivially sort
4185 a map when we want ordered access to both elements. i think.
4188 vector<PlaylistMapping> pmap;
4190 framepos_t first_position = max_framepos;
4192 typedef set<boost::shared_ptr<Playlist> > FreezeList;
4193 FreezeList freezelist;
4195 /* get ordering correct before we cut/copy */
4197 rs.sort_by_position_and_track ();
4199 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
4201 first_position = min ((framepos_t) (*x)->region()->position(), first_position);
4203 if (op == Cut || op == Clear || op == Delete) {
4204 boost::shared_ptr<Playlist> pl = (*x)->region()->playlist();
4207 FreezeList::iterator fl;
4209 // only take state if this is a new playlist.
4210 for (fl = freezelist.begin(); fl != freezelist.end(); ++fl) {
4216 if (fl == freezelist.end()) {
4217 pl->clear_changes();
4218 pl->clear_owned_changes ();
4220 freezelist.insert (pl);
4225 TimeAxisView* tv = &(*x)->get_time_axis_view();
4226 vector<PlaylistMapping>::iterator z;
4228 for (z = pmap.begin(); z != pmap.end(); ++z) {
4229 if ((*z).tv == tv) {
4234 if (z == pmap.end()) {
4235 pmap.push_back (PlaylistMapping (tv));
4239 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ) {
4241 boost::shared_ptr<Playlist> pl = (*x)->region()->playlist();
4244 /* region not yet associated with a playlist (e.g. unfinished
4251 TimeAxisView& tv = (*x)->get_time_axis_view();
4252 boost::shared_ptr<Playlist> npl;
4253 RegionSelection::iterator tmp;
4260 vector<PlaylistMapping>::iterator z;
4262 for (z = pmap.begin(); z != pmap.end(); ++z) {
4263 if ((*z).tv == &tv) {
4268 assert (z != pmap.end());
4271 npl = PlaylistFactory::create (pl->data_type(), *_session, "cutlist", true);
4279 boost::shared_ptr<Region> r = (*x)->region();
4280 boost::shared_ptr<Region> _xx;
4286 pl->remove_region (r);
4290 _xx = RegionFactory::create (r);
4291 npl->add_region (_xx, r->position() - first_position);
4292 pl->remove_region (r);
4296 /* copy region before adding, so we're not putting same object into two different playlists */
4297 npl->add_region (RegionFactory::create (r), r->position() - first_position);
4301 pl->remove_region (r);
4310 list<boost::shared_ptr<Playlist> > foo;
4312 /* the pmap is in the same order as the tracks in which selected regions occured */
4314 for (vector<PlaylistMapping>::iterator i = pmap.begin(); i != pmap.end(); ++i) {
4317 foo.push_back ((*i).pl);
4322 cut_buffer->set (foo);
4326 _last_cut_copy_source_track = 0;
4328 _last_cut_copy_source_track = pmap.front().tv;
4332 for (FreezeList::iterator pl = freezelist.begin(); pl != freezelist.end(); ++pl) {
4335 /* We might have removed regions, which alters other regions' layering_index,
4336 so we need to do a recursive diff here.
4338 vector<Command*> cmds;
4339 (*pl)->rdiff (cmds);
4340 _session->add_commands (cmds);
4342 _session->add_command (new StatefulDiffCommand (*pl));
4347 Editor::cut_copy_ranges (CutCopyOp op)
4349 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4351 /* Sort the track selection now, so that it if is used, the playlists
4352 selected by the calls below to cut_copy_clear are in the order that
4353 their tracks appear in the editor. This makes things like paste
4354 of ranges work properly.
4357 sort_track_selection (ts);
4360 if (!entered_track) {
4363 ts.push_back (entered_track);
4366 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4367 (*i)->cut_copy_clear (*selection, op);
4372 Editor::paste (float times, bool from_context)
4374 DEBUG_TRACE (DEBUG::CutNPaste, "paste to preferred edit pos\n");
4376 paste_internal (get_preferred_edit_position (false, from_context), times);
4380 Editor::mouse_paste ()
4385 if (!mouse_frame (where, ignored)) {
4390 paste_internal (where, 1);
4394 Editor::paste_internal (framepos_t position, float times)
4396 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("apparent paste position is %1\n", position));
4398 if (internal_editing()) {
4399 if (cut_buffer->midi_notes.empty()) {
4403 if (cut_buffer->empty()) {
4408 if (position == max_framepos) {
4409 position = get_preferred_edit_position();
4410 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("preferred edit position is %1\n", position));
4414 TrackViewList::iterator i;
4417 /* get everything in the correct order */
4419 if (_edit_point == Editing::EditAtMouse && entered_track) {
4420 /* With the mouse edit point, paste onto the track under the mouse */
4421 ts.push_back (entered_track);
4422 } else if (!selection->tracks.empty()) {
4423 /* Otherwise, if there are some selected tracks, paste to them */
4424 ts = selection->tracks.filter_to_unique_playlists ();
4425 sort_track_selection (ts);
4426 } else if (_last_cut_copy_source_track) {
4427 /* Otherwise paste to the track that the cut/copy came from;
4428 see discussion in mantis #3333.
4430 ts.push_back (_last_cut_copy_source_track);
4433 if (internal_editing ()) {
4435 /* undo/redo is handled by individual tracks/regions */
4437 for (nth = 0, i = ts.begin(); i != ts.end(); ++i, ++nth) {
4440 RegionSelection::iterator r;
4441 MidiNoteSelection::iterator cb;
4443 get_regions_at (rs, position, ts);
4445 for (cb = cut_buffer->midi_notes.begin(), r = rs.begin();
4446 cb != cut_buffer->midi_notes.end() && r != rs.end(); ++r) {
4447 MidiRegionView* mrv = dynamic_cast<MidiRegionView*> (*r);
4449 mrv->paste (position, times, **cb);
4457 /* we do redo (do you do voodoo?) */
4459 begin_reversible_command (Operations::paste);
4461 for (nth = 0, i = ts.begin(); i != ts.end(); ++i, ++nth) {
4462 (*i)->paste (position, times, *cut_buffer, nth);
4465 commit_reversible_command ();
4470 Editor::duplicate_some_regions (RegionSelection& regions, float times)
4472 boost::shared_ptr<Playlist> playlist;
4473 RegionSelection sel = regions; // clear (below) may clear the argument list if its the current region selection
4474 RegionSelection foo;
4476 framepos_t const start_frame = regions.start ();
4477 framepos_t const end_frame = regions.end_frame ();
4479 begin_reversible_command (Operations::duplicate_region);
4481 selection->clear_regions ();
4483 for (RegionSelection::iterator i = sel.begin(); i != sel.end(); ++i) {
4485 boost::shared_ptr<Region> r ((*i)->region());
4487 TimeAxisView& tv = (*i)->get_time_axis_view();
4488 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (&tv);
4489 latest_regionviews.clear ();
4490 sigc::connection c = rtv->view()->RegionViewAdded.connect (sigc::mem_fun(*this, &Editor::collect_new_region_view));
4492 playlist = (*i)->region()->playlist();
4493 playlist->clear_changes ();
4494 playlist->duplicate (r, end_frame + (r->first_frame() - start_frame), times);
4495 _session->add_command(new StatefulDiffCommand (playlist));
4499 foo.insert (foo.end(), latest_regionviews.begin(), latest_regionviews.end());
4502 commit_reversible_command ();
4505 selection->set (foo);
4510 Editor::duplicate_selection (float times)
4512 if (selection->time.empty() || selection->tracks.empty()) {
4516 boost::shared_ptr<Playlist> playlist;
4517 vector<boost::shared_ptr<Region> > new_regions;
4518 vector<boost::shared_ptr<Region> >::iterator ri;
4520 create_region_from_selection (new_regions);
4522 if (new_regions.empty()) {
4526 begin_reversible_command (_("duplicate selection"));
4528 ri = new_regions.begin();
4530 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4532 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4533 if ((playlist = (*i)->playlist()) == 0) {
4536 playlist->clear_changes ();
4537 playlist->duplicate (*ri, selection->time[clicked_selection].end, times);
4538 _session->add_command (new StatefulDiffCommand (playlist));
4541 if (ri == new_regions.end()) {
4546 commit_reversible_command ();
4549 /** Reset all selected points to the relevant default value */
4551 Editor::reset_point_selection ()
4553 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
4554 ARDOUR::AutomationList::iterator j = (*i)->model ();
4555 (*j)->value = (*i)->line().the_list()->default_value ();
4560 Editor::center_playhead ()
4562 float const page = _visible_canvas_width * samples_per_pixel;
4563 center_screen_internal (playhead_cursor->current_frame (), page);
4567 Editor::center_edit_point ()
4569 float const page = _visible_canvas_width * samples_per_pixel;
4570 center_screen_internal (get_preferred_edit_position(), page);
4573 /** Caller must begin and commit a reversible command */
4575 Editor::clear_playlist (boost::shared_ptr<Playlist> playlist)
4577 playlist->clear_changes ();
4579 _session->add_command (new StatefulDiffCommand (playlist));
4583 Editor::nudge_track (bool use_edit, bool forwards)
4585 boost::shared_ptr<Playlist> playlist;
4586 framepos_t distance;
4587 framepos_t next_distance;
4591 start = get_preferred_edit_position();
4596 if ((distance = get_nudge_distance (start, next_distance)) == 0) {
4600 if (selection->tracks.empty()) {
4604 begin_reversible_command (_("nudge track"));
4606 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4608 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4610 if ((playlist = (*i)->playlist()) == 0) {
4614 playlist->clear_changes ();
4615 playlist->clear_owned_changes ();
4617 playlist->nudge_after (start, distance, forwards);
4619 vector<Command*> cmds;
4621 playlist->rdiff (cmds);
4622 _session->add_commands (cmds);
4624 _session->add_command (new StatefulDiffCommand (playlist));
4627 commit_reversible_command ();
4631 Editor::remove_last_capture ()
4633 vector<string> choices;
4640 if (Config->get_verify_remove_last_capture()) {
4641 prompt = _("Do you really want to destroy the last capture?"
4642 "\n(This is destructive and cannot be undone)");
4644 choices.push_back (_("No, do nothing."));
4645 choices.push_back (_("Yes, destroy it."));
4647 Gtkmm2ext::Choice prompter (_("Destroy last capture"), prompt, choices);
4649 if (prompter.run () == 1) {
4650 _session->remove_last_capture ();
4651 _regions->redisplay ();
4655 _session->remove_last_capture();
4656 _regions->redisplay ();
4661 Editor::normalize_region ()
4667 RegionSelection rs = get_regions_from_selection_and_entered ();
4673 NormalizeDialog dialog (rs.size() > 1);
4675 if (dialog.run () == RESPONSE_CANCEL) {
4679 set_canvas_cursor (_cursors->wait);
4682 /* XXX: should really only count audio regions here */
4683 int const regions = rs.size ();
4685 /* Make a list of the selected audio regions' maximum amplitudes, and also
4686 obtain the maximum amplitude of them all.
4688 list<double> max_amps;
4690 for (RegionSelection::const_iterator i = rs.begin(); i != rs.end(); ++i) {
4691 AudioRegionView const * arv = dynamic_cast<AudioRegionView const *> (*i);
4693 dialog.descend (1.0 / regions);
4694 double const a = arv->audio_region()->maximum_amplitude (&dialog);
4697 /* the user cancelled the operation */
4698 set_canvas_cursor (current_canvas_cursor);
4702 max_amps.push_back (a);
4703 max_amp = max (max_amp, a);
4708 begin_reversible_command (_("normalize"));
4710 list<double>::const_iterator a = max_amps.begin ();
4712 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
4713 AudioRegionView* const arv = dynamic_cast<AudioRegionView*> (*r);
4718 arv->region()->clear_changes ();
4720 double const amp = dialog.normalize_individually() ? *a : max_amp;
4722 arv->audio_region()->normalize (amp, dialog.target ());
4723 _session->add_command (new StatefulDiffCommand (arv->region()));
4728 commit_reversible_command ();
4729 set_canvas_cursor (current_canvas_cursor);
4734 Editor::reset_region_scale_amplitude ()
4740 RegionSelection rs = get_regions_from_selection_and_entered ();
4746 begin_reversible_command ("reset gain");
4748 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
4749 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
4752 arv->region()->clear_changes ();
4753 arv->audio_region()->set_scale_amplitude (1.0f);
4754 _session->add_command (new StatefulDiffCommand (arv->region()));
4757 commit_reversible_command ();
4761 Editor::adjust_region_gain (bool up)
4763 RegionSelection rs = get_regions_from_selection_and_entered ();
4765 if (!_session || rs.empty()) {
4769 begin_reversible_command ("adjust region gain");
4771 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
4772 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
4777 arv->region()->clear_changes ();
4779 double dB = accurate_coefficient_to_dB (arv->audio_region()->scale_amplitude ());
4787 arv->audio_region()->set_scale_amplitude (dB_to_coefficient (dB));
4788 _session->add_command (new StatefulDiffCommand (arv->region()));
4791 commit_reversible_command ();
4796 Editor::reverse_region ()
4802 Reverse rev (*_session);
4803 apply_filter (rev, _("reverse regions"));
4807 Editor::strip_region_silence ()
4813 RegionSelection rs = get_regions_from_selection_and_entered ();
4819 std::list<RegionView*> audio_only;
4821 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
4822 AudioRegionView* const arv = dynamic_cast<AudioRegionView*> (*i);
4824 audio_only.push_back (arv);
4828 StripSilenceDialog d (_session, audio_only);
4829 int const r = d.run ();
4833 if (r == Gtk::RESPONSE_OK) {
4834 ARDOUR::AudioIntervalMap silences;
4835 d.silences (silences);
4836 StripSilence s (*_session, silences, d.fade_length());
4837 apply_filter (s, _("strip silence"), &d);
4842 Editor::apply_midi_note_edit_op_to_region (MidiOperator& op, MidiRegionView& mrv)
4844 Evoral::Sequence<Evoral::MusicalTime>::Notes selected;
4845 mrv.selection_as_notelist (selected, true);
4847 vector<Evoral::Sequence<Evoral::MusicalTime>::Notes> v;
4848 v.push_back (selected);
4850 framepos_t pos_frames = mrv.midi_region()->position() - mrv.midi_region()->start();
4851 double pos_beats = _session->tempo_map().framewalk_to_beats(0, pos_frames);
4853 return op (mrv.midi_region()->model(), pos_beats, v);
4857 Editor::apply_midi_note_edit_op (MidiOperator& op)
4861 RegionSelection rs = get_regions_from_selection_and_entered ();
4867 begin_reversible_command (op.name ());
4869 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
4870 RegionSelection::iterator tmp = r;
4873 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*r);
4876 cmd = apply_midi_note_edit_op_to_region (op, *mrv);
4879 _session->add_command (cmd);
4886 commit_reversible_command ();
4890 Editor::fork_region ()
4892 RegionSelection rs = get_regions_from_selection_and_entered ();
4898 begin_reversible_command (_("Fork Region(s)"));
4900 set_canvas_cursor (_cursors->wait);
4903 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
4904 RegionSelection::iterator tmp = r;
4907 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*>(*r);
4911 boost::shared_ptr<Playlist> playlist = mrv->region()->playlist();
4912 boost::shared_ptr<MidiSource> new_source = _session->create_midi_source_by_stealing_name (mrv->midi_view()->track());
4913 boost::shared_ptr<MidiRegion> newregion = mrv->midi_region()->clone (new_source);
4915 playlist->clear_changes ();
4916 playlist->replace_region (mrv->region(), newregion, mrv->region()->position());
4917 _session->add_command(new StatefulDiffCommand (playlist));
4919 error << string_compose (_("Could not unlink %1"), mrv->region()->name()) << endmsg;
4926 commit_reversible_command ();
4928 set_canvas_cursor (current_canvas_cursor);
4932 Editor::quantize_region ()
4934 int selected_midi_region_cnt = 0;
4940 RegionSelection rs = get_regions_from_selection_and_entered ();
4946 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
4947 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*r);
4949 selected_midi_region_cnt++;
4953 if (selected_midi_region_cnt == 0) {
4957 QuantizeDialog* qd = new QuantizeDialog (*this);
4960 const int r = qd->run ();
4963 if (r == Gtk::RESPONSE_OK) {
4964 Quantize quant (*_session, qd->snap_start(), qd->snap_end(),
4965 qd->start_grid_size(), qd->end_grid_size(),
4966 qd->strength(), qd->swing(), qd->threshold());
4968 apply_midi_note_edit_op (quant);
4973 Editor::insert_patch_change (bool from_context)
4975 RegionSelection rs = get_regions_from_selection_and_entered ();
4981 const framepos_t p = get_preferred_edit_position (false, from_context);
4983 /* XXX: bit of a hack; use the MIDNAM from the first selected region;
4984 there may be more than one, but the PatchChangeDialog can only offer
4985 one set of patch menus.
4987 MidiRegionView* first = dynamic_cast<MidiRegionView*> (rs.front ());
4989 Evoral::PatchChange<Evoral::MusicalTime> empty (0, 0, 0, 0);
4990 PatchChangeDialog d (0, _session, empty, first->instrument_info(), Gtk::Stock::ADD);
4992 if (d.run() == RESPONSE_CANCEL) {
4996 for (RegionSelection::iterator i = rs.begin (); i != rs.end(); ++i) {
4997 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*i);
4999 if (p >= mrv->region()->first_frame() && p <= mrv->region()->last_frame()) {
5000 mrv->add_patch_change (p - mrv->region()->position(), d.patch ());
5007 Editor::apply_filter (Filter& filter, string command, ProgressReporter* progress)
5009 RegionSelection rs = get_regions_from_selection_and_entered ();
5015 begin_reversible_command (command);
5017 set_canvas_cursor (_cursors->wait);
5021 int const N = rs.size ();
5023 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
5024 RegionSelection::iterator tmp = r;
5027 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
5029 boost::shared_ptr<Playlist> playlist = arv->region()->playlist();
5032 progress->descend (1.0 / N);
5035 if (arv->audio_region()->apply (filter, progress) == 0) {
5037 playlist->clear_changes ();
5038 playlist->clear_owned_changes ();
5040 if (filter.results.empty ()) {
5042 /* no regions returned; remove the old one */
5043 playlist->remove_region (arv->region ());
5047 std::vector<boost::shared_ptr<Region> >::iterator res = filter.results.begin ();
5049 /* first region replaces the old one */
5050 playlist->replace_region (arv->region(), *res, (*res)->position());
5054 while (res != filter.results.end()) {
5055 playlist->add_region (*res, (*res)->position());
5061 /* We might have removed regions, which alters other regions' layering_index,
5062 so we need to do a recursive diff here.
5064 vector<Command*> cmds;
5065 playlist->rdiff (cmds);
5066 _session->add_commands (cmds);
5068 _session->add_command(new StatefulDiffCommand (playlist));
5074 progress->ascend ();
5082 commit_reversible_command ();
5085 set_canvas_cursor (current_canvas_cursor);
5089 Editor::external_edit_region ()
5095 Editor::reset_region_gain_envelopes ()
5097 RegionSelection rs = get_regions_from_selection_and_entered ();
5099 if (!_session || rs.empty()) {
5103 _session->begin_reversible_command (_("reset region gain"));
5105 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5106 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
5108 boost::shared_ptr<AutomationList> alist (arv->audio_region()->envelope());
5109 XMLNode& before (alist->get_state());
5111 arv->audio_region()->set_default_envelope ();
5112 _session->add_command (new MementoCommand<AutomationList>(*arv->audio_region()->envelope().get(), &before, &alist->get_state()));
5116 _session->commit_reversible_command ();
5120 Editor::set_region_gain_visibility (RegionView* rv)
5122 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (rv);
5124 arv->update_envelope_visibility();
5129 Editor::set_gain_envelope_visibility ()
5135 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5136 AudioTimeAxisView* v = dynamic_cast<AudioTimeAxisView*>(*i);
5138 v->audio_view()->foreach_regionview (sigc::mem_fun (this, &Editor::set_region_gain_visibility));
5144 Editor::toggle_gain_envelope_active ()
5146 if (_ignore_region_action) {
5150 RegionSelection rs = get_regions_from_selection_and_entered ();
5152 if (!_session || rs.empty()) {
5156 _session->begin_reversible_command (_("region gain envelope active"));
5158 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5159 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
5161 arv->region()->clear_changes ();
5162 arv->audio_region()->set_envelope_active (!arv->audio_region()->envelope_active());
5163 _session->add_command (new StatefulDiffCommand (arv->region()));
5167 _session->commit_reversible_command ();
5171 Editor::toggle_region_lock ()
5173 if (_ignore_region_action) {
5177 RegionSelection rs = get_regions_from_selection_and_entered ();
5179 if (!_session || rs.empty()) {
5183 _session->begin_reversible_command (_("toggle region lock"));
5185 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5186 (*i)->region()->clear_changes ();
5187 (*i)->region()->set_locked (!(*i)->region()->locked());
5188 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5191 _session->commit_reversible_command ();
5195 Editor::toggle_region_video_lock ()
5197 if (_ignore_region_action) {
5201 RegionSelection rs = get_regions_from_selection_and_entered ();
5203 if (!_session || rs.empty()) {
5207 _session->begin_reversible_command (_("Toggle Video Lock"));
5209 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5210 (*i)->region()->clear_changes ();
5211 (*i)->region()->set_video_locked (!(*i)->region()->video_locked());
5212 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5215 _session->commit_reversible_command ();
5219 Editor::toggle_region_lock_style ()
5221 if (_ignore_region_action) {
5225 RegionSelection rs = get_regions_from_selection_and_entered ();
5227 if (!_session || rs.empty()) {
5231 _session->begin_reversible_command (_("region lock style"));
5233 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5234 (*i)->region()->clear_changes ();
5235 PositionLockStyle const ns = (*i)->region()->position_lock_style() == AudioTime ? MusicTime : AudioTime;
5236 (*i)->region()->set_position_lock_style (ns);
5237 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5240 _session->commit_reversible_command ();
5244 Editor::toggle_opaque_region ()
5246 if (_ignore_region_action) {
5250 RegionSelection rs = get_regions_from_selection_and_entered ();
5252 if (!_session || rs.empty()) {
5256 _session->begin_reversible_command (_("change region opacity"));
5258 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5259 (*i)->region()->clear_changes ();
5260 (*i)->region()->set_opaque (!(*i)->region()->opaque());
5261 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5264 _session->commit_reversible_command ();
5268 Editor::toggle_record_enable ()
5270 bool new_state = false;
5272 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5273 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5276 if (!rtav->is_track())
5280 new_state = !rtav->track()->record_enabled();
5284 rtav->track()->set_record_enabled (new_state, this);
5289 Editor::toggle_solo ()
5291 bool new_state = false;
5293 boost::shared_ptr<RouteList> rl (new RouteList);
5295 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5296 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5303 new_state = !rtav->route()->soloed ();
5307 rl->push_back (rtav->route());
5310 _session->set_solo (rl, new_state, Session::rt_cleanup, true);
5314 Editor::toggle_mute ()
5316 bool new_state = false;
5318 boost::shared_ptr<RouteList> rl (new RouteList);
5320 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5321 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5328 new_state = !rtav->route()->muted();
5332 rl->push_back (rtav->route());
5335 _session->set_mute (rl, new_state, Session::rt_cleanup, true);
5339 Editor::toggle_solo_isolate ()
5344 Editor::set_fade_length (bool in)
5346 RegionSelection rs = get_regions_from_selection_and_entered ();
5352 /* we need a region to measure the offset from the start */
5354 RegionView* rv = rs.front ();
5356 framepos_t pos = get_preferred_edit_position();
5360 if (pos > rv->region()->last_frame() || pos < rv->region()->first_frame()) {
5361 /* edit point is outside the relevant region */
5366 if (pos <= rv->region()->position()) {
5370 len = pos - rv->region()->position();
5371 cmd = _("set fade in length");
5373 if (pos >= rv->region()->last_frame()) {
5377 len = rv->region()->last_frame() - pos;
5378 cmd = _("set fade out length");
5381 begin_reversible_command (cmd);
5383 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5384 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5390 boost::shared_ptr<AutomationList> alist;
5392 alist = tmp->audio_region()->fade_in();
5394 alist = tmp->audio_region()->fade_out();
5397 XMLNode &before = alist->get_state();
5400 tmp->audio_region()->set_fade_in_length (len);
5401 tmp->audio_region()->set_fade_in_active (true);
5403 tmp->audio_region()->set_fade_out_length (len);
5404 tmp->audio_region()->set_fade_out_active (true);
5407 XMLNode &after = alist->get_state();
5408 _session->add_command(new MementoCommand<AutomationList>(*alist, &before, &after));
5411 commit_reversible_command ();
5415 Editor::set_fade_in_shape (FadeShape shape)
5417 RegionSelection rs = get_regions_from_selection_and_entered ();
5423 begin_reversible_command (_("set fade in shape"));
5425 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5426 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5432 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_in();
5433 XMLNode &before = alist->get_state();
5435 tmp->audio_region()->set_fade_in_shape (shape);
5437 XMLNode &after = alist->get_state();
5438 _session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
5441 commit_reversible_command ();
5446 Editor::set_fade_out_shape (FadeShape shape)
5448 RegionSelection rs = get_regions_from_selection_and_entered ();
5454 begin_reversible_command (_("set fade out shape"));
5456 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5457 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5463 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_out();
5464 XMLNode &before = alist->get_state();
5466 tmp->audio_region()->set_fade_out_shape (shape);
5468 XMLNode &after = alist->get_state();
5469 _session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
5472 commit_reversible_command ();
5476 Editor::set_fade_in_active (bool yn)
5478 RegionSelection rs = get_regions_from_selection_and_entered ();
5484 begin_reversible_command (_("set fade in active"));
5486 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5487 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5494 boost::shared_ptr<AudioRegion> ar (tmp->audio_region());
5496 ar->clear_changes ();
5497 ar->set_fade_in_active (yn);
5498 _session->add_command (new StatefulDiffCommand (ar));
5501 commit_reversible_command ();
5505 Editor::set_fade_out_active (bool yn)
5507 RegionSelection rs = get_regions_from_selection_and_entered ();
5513 begin_reversible_command (_("set fade out active"));
5515 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5516 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5522 boost::shared_ptr<AudioRegion> ar (tmp->audio_region());
5524 ar->clear_changes ();
5525 ar->set_fade_out_active (yn);
5526 _session->add_command(new StatefulDiffCommand (ar));
5529 commit_reversible_command ();
5533 Editor::toggle_region_fades (int dir)
5535 if (_ignore_region_action) {
5539 boost::shared_ptr<AudioRegion> ar;
5542 RegionSelection rs = get_regions_from_selection_and_entered ();
5548 RegionSelection::iterator i;
5549 for (i = rs.begin(); i != rs.end(); ++i) {
5550 if ((ar = boost::dynamic_pointer_cast<AudioRegion>((*i)->region())) != 0) {
5552 yn = ar->fade_out_active ();
5554 yn = ar->fade_in_active ();
5560 if (i == rs.end()) {
5564 /* XXX should this undo-able? */
5566 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5567 if ((ar = boost::dynamic_pointer_cast<AudioRegion>((*i)->region())) == 0) {
5570 if (dir == 1 || dir == 0) {
5571 ar->set_fade_in_active (!yn);
5574 if (dir == -1 || dir == 0) {
5575 ar->set_fade_out_active (!yn);
5581 /** Update region fade visibility after its configuration has been changed */
5583 Editor::update_region_fade_visibility ()
5585 bool _fade_visibility = _session->config.get_show_region_fades ();
5587 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5588 AudioTimeAxisView* v = dynamic_cast<AudioTimeAxisView*>(*i);
5590 if (_fade_visibility) {
5591 v->audio_view()->show_all_fades ();
5593 v->audio_view()->hide_all_fades ();
5600 Editor::set_edit_point ()
5605 if (!mouse_frame (where, ignored)) {
5611 if (selection->markers.empty()) {
5613 mouse_add_new_marker (where);
5618 Location* loc = find_location_from_marker (selection->markers.front(), ignored);
5621 loc->move_to (where);
5627 Editor::set_playhead_cursor ()
5629 if (entered_marker) {
5630 _session->request_locate (entered_marker->position(), _session->transport_rolling());
5635 if (!mouse_frame (where, ignored)) {
5642 _session->request_locate (where, _session->transport_rolling());
5646 if ( Config->get_always_play_range() )
5647 cancel_time_selection();
5651 Editor::split_region ()
5653 if ( !selection->time.empty()) {
5654 separate_regions_between (selection->time);
5658 RegionSelection rs = get_regions_from_selection_and_edit_point ();
5660 framepos_t where = get_preferred_edit_position ();
5666 split_regions_at (where, rs);
5669 struct EditorOrderRouteSorter {
5670 bool operator() (boost::shared_ptr<Route> a, boost::shared_ptr<Route> b) {
5671 return a->order_key () < b->order_key ();
5676 Editor::select_next_route()
5678 if (selection->tracks.empty()) {
5679 selection->set (track_views.front());
5683 TimeAxisView* current = selection->tracks.front();
5687 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5688 if (*i == current) {
5690 if (i != track_views.end()) {
5693 current = (*(track_views.begin()));
5694 //selection->set (*(track_views.begin()));
5699 rui = dynamic_cast<RouteUI *>(current);
5700 } while ( current->hidden() || (rui != NULL && !rui->route()->active()));
5702 selection->set(current);
5704 ensure_track_visible(current);
5708 Editor::select_prev_route()
5710 if (selection->tracks.empty()) {
5711 selection->set (track_views.front());
5715 TimeAxisView* current = selection->tracks.front();
5719 for (TrackViewList::reverse_iterator i = track_views.rbegin(); i != track_views.rend(); ++i) {
5720 if (*i == current) {
5722 if (i != track_views.rend()) {
5725 current = *(track_views.rbegin());
5730 rui = dynamic_cast<RouteUI *>(current);
5731 } while ( current->hidden() || (rui != NULL && !rui->route()->active()));
5733 selection->set (current);
5735 ensure_track_visible(current);
5739 Editor::ensure_track_visible(TimeAxisView *track)
5741 if (track->hidden()) {
5745 /* compute visible area of trackview group, as offsets from top of
5749 double const current_view_min_y = vertical_adjustment.get_value();
5750 double const current_view_max_y = current_view_min_y + vertical_adjustment.get_page_size();
5752 double const track_min_y = track->y_position ();
5753 double const track_max_y = track->y_position () + track->effective_height ();
5755 if (track_min_y > current_view_min_y &&
5756 track_max_y <= current_view_max_y) {
5762 if (track_min_y < current_view_min_y) {
5763 // Track is above the current view
5764 new_value = track_min_y;
5766 // Track is below the current view
5767 new_value = track->y_position () + track->effective_height() - vertical_adjustment.get_page_size();
5770 vertical_adjustment.set_value(new_value);
5774 Editor::set_loop_from_selection (bool play)
5776 if (_session == 0 || selection->time.empty()) {
5780 framepos_t start = selection->time[clicked_selection].start;
5781 framepos_t end = selection->time[clicked_selection].end;
5783 set_loop_range (start, end, _("set loop range from selection"));
5786 _session->request_play_loop (true);
5787 _session->request_locate (start, true);
5792 Editor::set_loop_from_edit_range (bool play)
5794 if (_session == 0) {
5801 if (!get_edit_op_range (start, end)) {
5805 set_loop_range (start, end, _("set loop range from edit range"));
5808 _session->request_play_loop (true);
5809 _session->request_locate (start, true);
5814 Editor::set_loop_from_region (bool play)
5816 framepos_t start = max_framepos;
5819 RegionSelection rs = get_regions_from_selection_and_entered ();
5825 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5826 if ((*i)->region()->position() < start) {
5827 start = (*i)->region()->position();
5829 if ((*i)->region()->last_frame() + 1 > end) {
5830 end = (*i)->region()->last_frame() + 1;
5834 set_loop_range (start, end, _("set loop range from region"));
5837 _session->request_play_loop (true);
5838 _session->request_locate (start, true);
5843 Editor::set_punch_from_selection ()
5845 if (_session == 0 || selection->time.empty()) {
5849 framepos_t start = selection->time[clicked_selection].start;
5850 framepos_t end = selection->time[clicked_selection].end;
5852 set_punch_range (start, end, _("set punch range from selection"));
5856 Editor::set_punch_from_edit_range ()
5858 if (_session == 0) {
5865 if (!get_edit_op_range (start, end)) {
5869 set_punch_range (start, end, _("set punch range from edit range"));
5873 Editor::set_punch_from_region ()
5875 framepos_t start = max_framepos;
5878 RegionSelection rs = get_regions_from_selection_and_entered ();
5884 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5885 if ((*i)->region()->position() < start) {
5886 start = (*i)->region()->position();
5888 if ((*i)->region()->last_frame() + 1 > end) {
5889 end = (*i)->region()->last_frame() + 1;
5893 set_punch_range (start, end, _("set punch range from region"));
5897 Editor::pitch_shift_region ()
5899 RegionSelection rs = get_regions_from_selection_and_entered ();
5901 RegionSelection audio_rs;
5902 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5903 if (dynamic_cast<AudioRegionView*> (*i)) {
5904 audio_rs.push_back (*i);
5908 if (audio_rs.empty()) {
5912 pitch_shift (audio_rs, 1.2);
5916 Editor::transpose_region ()
5918 RegionSelection rs = get_regions_from_selection_and_entered ();
5920 list<MidiRegionView*> midi_region_views;
5921 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5922 MidiRegionView* mrv = dynamic_cast<MidiRegionView*> (*i);
5924 midi_region_views.push_back (mrv);
5929 int const r = d.run ();
5930 if (r != RESPONSE_ACCEPT) {
5934 for (list<MidiRegionView*>::iterator i = midi_region_views.begin(); i != midi_region_views.end(); ++i) {
5935 (*i)->midi_region()->transpose (d.semitones ());
5940 Editor::set_tempo_from_region ()
5942 RegionSelection rs = get_regions_from_selection_and_entered ();
5944 if (!_session || rs.empty()) {
5948 RegionView* rv = rs.front();
5950 define_one_bar (rv->region()->position(), rv->region()->last_frame() + 1);
5954 Editor::use_range_as_bar ()
5956 framepos_t start, end;
5957 if (get_edit_op_range (start, end)) {
5958 define_one_bar (start, end);
5963 Editor::define_one_bar (framepos_t start, framepos_t end)
5965 framepos_t length = end - start;
5967 const Meter& m (_session->tempo_map().meter_at (start));
5969 /* length = 1 bar */
5971 /* now we want frames per beat.
5972 we have frames per bar, and beats per bar, so ...
5975 /* XXXX METER MATH */
5977 double frames_per_beat = length / m.divisions_per_bar();
5979 /* beats per minute = */
5981 double beats_per_minute = (_session->frame_rate() * 60.0) / frames_per_beat;
5983 /* now decide whether to:
5985 (a) set global tempo
5986 (b) add a new tempo marker
5990 const TempoSection& t (_session->tempo_map().tempo_section_at (start));
5992 bool do_global = false;
5994 if ((_session->tempo_map().n_tempos() == 1) && (_session->tempo_map().n_meters() == 1)) {
5996 /* only 1 tempo & 1 meter: ask if the user wants to set the tempo
5997 at the start, or create a new marker
6000 vector<string> options;
6001 options.push_back (_("Cancel"));
6002 options.push_back (_("Add new marker"));
6003 options.push_back (_("Set global tempo"));
6006 _("Define one bar"),
6007 _("Do you want to set the global tempo or add a new tempo marker?"),
6011 c.set_default_response (2);
6027 /* more than 1 tempo and/or meter section already, go ahead do the "usual":
6028 if the marker is at the region starter, change it, otherwise add
6033 begin_reversible_command (_("set tempo from region"));
6034 XMLNode& before (_session->tempo_map().get_state());
6037 _session->tempo_map().change_initial_tempo (beats_per_minute, t.note_type());
6038 } else if (t.frame() == start) {
6039 _session->tempo_map().change_existing_tempo_at (start, beats_per_minute, t.note_type());
6041 Timecode::BBT_Time bbt;
6042 _session->tempo_map().bbt_time (start, bbt);
6043 _session->tempo_map().add_tempo (Tempo (beats_per_minute, t.note_type()), bbt);
6046 XMLNode& after (_session->tempo_map().get_state());
6048 _session->add_command (new MementoCommand<TempoMap>(_session->tempo_map(), &before, &after));
6049 commit_reversible_command ();
6053 Editor::split_region_at_transients ()
6055 AnalysisFeatureList positions;
6057 RegionSelection rs = get_regions_from_selection_and_entered ();
6059 if (!_session || rs.empty()) {
6063 _session->begin_reversible_command (_("split regions"));
6065 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ) {
6067 RegionSelection::iterator tmp;
6072 boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion> ((*i)->region());
6074 if (ar && (ar->get_transients (positions) == 0)) {
6075 split_region_at_points ((*i)->region(), positions, true);
6082 _session->commit_reversible_command ();
6087 Editor::split_region_at_points (boost::shared_ptr<Region> r, AnalysisFeatureList& positions, bool can_ferret, bool select_new)
6089 bool use_rhythmic_rodent = false;
6091 boost::shared_ptr<Playlist> pl = r->playlist();
6093 list<boost::shared_ptr<Region> > new_regions;
6099 if (positions.empty()) {
6104 if (positions.size() > 20 && can_ferret) {
6105 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);
6106 MessageDialog msg (msgstr,
6109 Gtk::BUTTONS_OK_CANCEL);
6112 msg.add_button (_("Call for the Ferret!"), RESPONSE_APPLY);
6113 msg.set_secondary_text (_("Press OK to continue with this split operation\nor ask the Ferret dialog to tune the analysis"));
6115 msg.set_secondary_text (_("Press OK to continue with this split operation"));
6118 msg.set_title (_("Excessive split?"));
6121 int response = msg.run();
6127 case RESPONSE_APPLY:
6128 use_rhythmic_rodent = true;
6135 if (use_rhythmic_rodent) {
6136 show_rhythm_ferret ();
6140 AnalysisFeatureList::const_iterator x;
6142 pl->clear_changes ();
6143 pl->clear_owned_changes ();
6145 x = positions.begin();
6147 if (x == positions.end()) {
6152 pl->remove_region (r);
6156 while (x != positions.end()) {
6158 /* deal with positons that are out of scope of present region bounds */
6159 if (*x <= 0 || *x > r->length()) {
6164 /* file start = original start + how far we from the initial position ?
6167 framepos_t file_start = r->start() + pos;
6169 /* length = next position - current position
6172 framepos_t len = (*x) - pos;
6174 /* XXX we do we really want to allow even single-sample regions?
6175 shouldn't we have some kind of lower limit on region size?
6184 if (RegionFactory::region_name (new_name, r->name())) {
6188 /* do NOT announce new regions 1 by one, just wait till they are all done */
6192 plist.add (ARDOUR::Properties::start, file_start);
6193 plist.add (ARDOUR::Properties::length, len);
6194 plist.add (ARDOUR::Properties::name, new_name);
6195 plist.add (ARDOUR::Properties::layer, 0);
6197 boost::shared_ptr<Region> nr = RegionFactory::create (r->sources(), plist, false);
6198 /* because we set annouce to false, manually add the new region to the
6201 RegionFactory::map_add (nr);
6203 pl->add_region (nr, r->position() + pos);
6206 new_regions.push_front(nr);
6215 RegionFactory::region_name (new_name, r->name());
6217 /* Add the final region */
6220 plist.add (ARDOUR::Properties::start, r->start() + pos);
6221 plist.add (ARDOUR::Properties::length, r->last_frame() - (r->position() + pos) + 1);
6222 plist.add (ARDOUR::Properties::name, new_name);
6223 plist.add (ARDOUR::Properties::layer, 0);
6225 boost::shared_ptr<Region> nr = RegionFactory::create (r->sources(), plist, false);
6226 /* because we set annouce to false, manually add the new region to the
6229 RegionFactory::map_add (nr);
6230 pl->add_region (nr, r->position() + pos);
6233 new_regions.push_front(nr);
6238 /* We might have removed regions, which alters other regions' layering_index,
6239 so we need to do a recursive diff here.
6241 vector<Command*> cmds;
6243 _session->add_commands (cmds);
6245 _session->add_command (new StatefulDiffCommand (pl));
6249 for (list<boost::shared_ptr<Region> >::iterator i = new_regions.begin(); i != new_regions.end(); ++i){
6250 set_selected_regionview_from_region_list ((*i), Selection::Add);
6256 Editor::place_transient()
6262 RegionSelection rs = get_regions_from_selection_and_edit_point ();
6268 framepos_t where = get_preferred_edit_position();
6270 _session->begin_reversible_command (_("place transient"));
6272 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6273 framepos_t position = (*r)->region()->position();
6274 (*r)->region()->add_transient(where - position);
6277 _session->commit_reversible_command ();
6281 Editor::remove_transient(ArdourCanvas::Item* item)
6287 ArdourCanvas::Line* _line = reinterpret_cast<ArdourCanvas::Line*> (item);
6290 AudioRegionView* _arv = reinterpret_cast<AudioRegionView*> (item->get_data ("regionview"));
6291 _arv->remove_transient (*(float*) _line->get_data ("position"));
6295 Editor::snap_regions_to_grid ()
6297 list <boost::shared_ptr<Playlist > > used_playlists;
6299 RegionSelection rs = get_regions_from_selection_and_entered ();
6301 if (!_session || rs.empty()) {
6305 _session->begin_reversible_command (_("snap regions to grid"));
6307 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6309 boost::shared_ptr<Playlist> pl = (*r)->region()->playlist();
6311 if (!pl->frozen()) {
6312 /* we haven't seen this playlist before */
6314 /* remember used playlists so we can thaw them later */
6315 used_playlists.push_back(pl);
6319 framepos_t start_frame = (*r)->region()->first_frame ();
6320 snap_to (start_frame);
6321 (*r)->region()->set_position (start_frame);
6324 while (used_playlists.size() > 0) {
6325 list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
6327 used_playlists.pop_front();
6330 _session->commit_reversible_command ();
6334 Editor::close_region_gaps ()
6336 list <boost::shared_ptr<Playlist > > used_playlists;
6338 RegionSelection rs = get_regions_from_selection_and_entered ();
6340 if (!_session || rs.empty()) {
6344 Dialog dialog (_("Close Region Gaps"));
6347 table.set_spacings (12);
6348 table.set_border_width (12);
6349 Label* l = manage (left_aligned_label (_("Crossfade length")));
6350 table.attach (*l, 0, 1, 0, 1);
6352 SpinButton spin_crossfade (1, 0);
6353 spin_crossfade.set_range (0, 15);
6354 spin_crossfade.set_increments (1, 1);
6355 spin_crossfade.set_value (5);
6356 table.attach (spin_crossfade, 1, 2, 0, 1);
6358 table.attach (*manage (new Label (_("ms"))), 2, 3, 0, 1);
6360 l = manage (left_aligned_label (_("Pull-back length")));
6361 table.attach (*l, 0, 1, 1, 2);
6363 SpinButton spin_pullback (1, 0);
6364 spin_pullback.set_range (0, 100);
6365 spin_pullback.set_increments (1, 1);
6366 spin_pullback.set_value(30);
6367 table.attach (spin_pullback, 1, 2, 1, 2);
6369 table.attach (*manage (new Label (_("ms"))), 2, 3, 1, 2);
6371 dialog.get_vbox()->pack_start (table);
6372 dialog.add_button (Stock::CANCEL, RESPONSE_CANCEL);
6373 dialog.add_button (_("Ok"), RESPONSE_ACCEPT);
6376 if (dialog.run () == RESPONSE_CANCEL) {
6380 framepos_t crossfade_len = spin_crossfade.get_value();
6381 framepos_t pull_back_frames = spin_pullback.get_value();
6383 crossfade_len = lrintf (crossfade_len * _session->frame_rate()/1000);
6384 pull_back_frames = lrintf (pull_back_frames * _session->frame_rate()/1000);
6386 /* Iterate over the region list and make adjacent regions overlap by crossfade_len_ms */
6388 _session->begin_reversible_command (_("close region gaps"));
6391 boost::shared_ptr<Region> last_region;
6393 rs.sort_by_position_and_track();
6395 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6397 boost::shared_ptr<Playlist> pl = (*r)->region()->playlist();
6399 if (!pl->frozen()) {
6400 /* we haven't seen this playlist before */
6402 /* remember used playlists so we can thaw them later */
6403 used_playlists.push_back(pl);
6407 framepos_t position = (*r)->region()->position();
6409 if (idx == 0 || position < last_region->position()){
6410 last_region = (*r)->region();
6415 (*r)->region()->trim_front( (position - pull_back_frames));
6416 last_region->trim_end( (position - pull_back_frames + crossfade_len));
6418 last_region = (*r)->region();
6423 while (used_playlists.size() > 0) {
6424 list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
6426 used_playlists.pop_front();
6429 _session->commit_reversible_command ();
6433 Editor::tab_to_transient (bool forward)
6435 AnalysisFeatureList positions;
6437 RegionSelection rs = get_regions_from_selection_and_entered ();
6443 framepos_t pos = _session->audible_frame ();
6445 if (!selection->tracks.empty()) {
6447 /* don't waste time searching for transients in duplicate playlists.
6450 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
6452 for (TrackViewList::iterator t = ts.begin(); t != ts.end(); ++t) {
6454 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*t);
6457 boost::shared_ptr<Track> tr = rtv->track();
6459 boost::shared_ptr<Playlist> pl = tr->playlist ();
6461 framepos_t result = pl->find_next_transient (pos, forward ? 1 : -1);
6464 positions.push_back (result);
6477 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6478 (*r)->region()->get_transients (positions);
6482 TransientDetector::cleanup_transients (positions, _session->frame_rate(), 3.0);
6485 AnalysisFeatureList::iterator x;
6487 for (x = positions.begin(); x != positions.end(); ++x) {
6493 if (x != positions.end ()) {
6494 _session->request_locate (*x);
6498 AnalysisFeatureList::reverse_iterator x;
6500 for (x = positions.rbegin(); x != positions.rend(); ++x) {
6506 if (x != positions.rend ()) {
6507 _session->request_locate (*x);
6513 Editor::playhead_forward_to_grid ()
6519 framepos_t pos = playhead_cursor->current_frame ();
6520 if (pos < max_framepos - 1) {
6522 snap_to_internal (pos, 1, false);
6523 _session->request_locate (pos);
6529 Editor::playhead_backward_to_grid ()
6535 framepos_t pos = playhead_cursor->current_frame ();
6538 snap_to_internal (pos, -1, false);
6539 _session->request_locate (pos);
6544 Editor::set_track_height (Height h)
6546 TrackSelection& ts (selection->tracks);
6548 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
6549 (*x)->set_height_enum (h);
6554 Editor::toggle_tracks_active ()
6556 TrackSelection& ts (selection->tracks);
6558 bool target = false;
6564 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
6565 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*x);
6569 target = !rtv->_route->active();
6572 rtv->_route->set_active (target, this);
6578 Editor::remove_tracks ()
6580 TrackSelection& ts (selection->tracks);
6586 vector<string> choices;
6590 const char* trackstr;
6592 vector<boost::shared_ptr<Route> > routes;
6593 bool special_bus = false;
6595 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
6596 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*x);
6600 if (rtv->is_track()) {
6605 routes.push_back (rtv->_route);
6607 if (rtv->route()->is_master() || rtv->route()->is_monitor()) {
6612 if (special_bus && !Config->get_allow_special_bus_removal()) {
6613 MessageDialog msg (_("That would be bad news ...."),
6617 msg.set_secondary_text (string_compose (_(
6618 "Removing the master or monitor bus is such a bad idea\n\
6619 that %1 is not going to allow it.\n\
6621 If you really want to do this sort of thing\n\
6622 edit your ardour.rc file to set the\n\
6623 \"allow-special-bus-removal\" option to be \"yes\""), PROGRAM_NAME));
6630 if (ntracks + nbusses == 0) {
6635 trackstr = _("tracks");
6637 trackstr = _("track");
6641 busstr = _("busses");
6648 prompt = string_compose (_("Do you really want to remove %1 %2 and %3 %4?\n"
6649 "(You may also lose the playlists associated with the %2)\n\n"
6650 "This action cannot be undone, and the session file will be overwritten!"),
6651 ntracks, trackstr, nbusses, busstr);
6653 prompt = string_compose (_("Do you really want to remove %1 %2?\n"
6654 "(You may also lose the playlists associated with the %2)\n\n"
6655 "This action cannot be undone, and the session file will be overwritten!"),
6658 } else if (nbusses) {
6659 prompt = string_compose (_("Do you really want to remove %1 %2?\n\n"
6660 "This action cannot be undon, and the session file will be overwritten"),
6664 choices.push_back (_("No, do nothing."));
6665 if (ntracks + nbusses > 1) {
6666 choices.push_back (_("Yes, remove them."));
6668 choices.push_back (_("Yes, remove it."));
6673 title = string_compose (_("Remove %1"), trackstr);
6675 title = string_compose (_("Remove %1"), busstr);
6678 Choice prompter (title, prompt, choices);
6680 if (prompter.run () != 1) {
6684 for (vector<boost::shared_ptr<Route> >::iterator x = routes.begin(); x != routes.end(); ++x) {
6685 _session->remove_route (*x);
6690 Editor::do_insert_time ()
6692 if (selection->tracks.empty()) {
6696 InsertTimeDialog d (*this);
6697 int response = d.run ();
6699 if (response != RESPONSE_OK) {
6703 if (d.distance() == 0) {
6707 InsertTimeOption opt = d.intersected_region_action ();
6710 get_preferred_edit_position(),
6716 d.move_glued_markers(),
6717 d.move_locked_markers(),
6723 Editor::insert_time (
6724 framepos_t pos, framecnt_t frames, InsertTimeOption opt,
6725 bool all_playlists, bool ignore_music_glue, bool markers_too, bool glued_markers_too, bool locked_markers_too, bool tempo_too
6728 bool commit = false;
6730 if (Config->get_edit_mode() == Lock) {
6734 begin_reversible_command (_("insert time"));
6736 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
6738 for (TrackViewList::iterator x = ts.begin(); x != ts.end(); ++x) {
6742 /* don't operate on any playlist more than once, which could
6743 * happen if "all playlists" is enabled, but there is more
6744 * than 1 track using playlists "from" a given track.
6747 set<boost::shared_ptr<Playlist> > pl;
6749 if (all_playlists) {
6750 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*x);
6752 vector<boost::shared_ptr<Playlist> > all = _session->playlists->playlists_for_track (rtav->track ());
6753 for (vector<boost::shared_ptr<Playlist> >::iterator p = all.begin(); p != all.end(); ++p) {
6758 if ((*x)->playlist ()) {
6759 pl.insert ((*x)->playlist ());
6763 for (set<boost::shared_ptr<Playlist> >::iterator i = pl.begin(); i != pl.end(); ++i) {
6765 (*i)->clear_changes ();
6766 (*i)->clear_owned_changes ();
6768 if (opt == SplitIntersected) {
6772 (*i)->shift (pos, frames, (opt == MoveIntersected), ignore_music_glue);
6774 vector<Command*> cmds;
6776 _session->add_commands (cmds);
6778 _session->add_command (new StatefulDiffCommand (*i));
6783 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*x);
6785 rtav->route ()->shift (pos, frames);
6793 XMLNode& before (_session->locations()->get_state());
6794 Locations::LocationList copy (_session->locations()->list());
6796 for (Locations::LocationList::iterator i = copy.begin(); i != copy.end(); ++i) {
6798 Locations::LocationList::const_iterator tmp;
6800 bool const was_locked = (*i)->locked ();
6801 if (locked_markers_too) {
6805 if ((*i)->position_lock_style() == AudioTime || glued_markers_too) {
6807 if ((*i)->start() >= pos) {
6808 (*i)->set_start ((*i)->start() + frames);
6809 if (!(*i)->is_mark()) {
6810 (*i)->set_end ((*i)->end() + frames);
6823 XMLNode& after (_session->locations()->get_state());
6824 _session->add_command (new MementoCommand<Locations>(*_session->locations(), &before, &after));
6829 _session->tempo_map().insert_time (pos, frames);
6833 commit_reversible_command ();
6838 Editor::fit_selected_tracks ()
6840 if (!selection->tracks.empty()) {
6841 fit_tracks (selection->tracks);
6845 /* no selected tracks - use tracks with selected regions */
6847 if (!selection->regions.empty()) {
6848 for (RegionSelection::iterator r = selection->regions.begin(); r != selection->regions.end(); ++r) {
6849 tvl.push_back (&(*r)->get_time_axis_view ());
6855 } else if (internal_editing()) {
6856 /* no selected tracks, or regions, but in internal edit mode, so follow the mouse and use
6859 if (entered_track) {
6860 tvl.push_back (entered_track);
6868 Editor::fit_tracks (TrackViewList & tracks)
6870 if (tracks.empty()) {
6874 uint32_t child_heights = 0;
6875 int visible_tracks = 0;
6877 for (TrackSelection::iterator t = tracks.begin(); t != tracks.end(); ++t) {
6879 if (!(*t)->marked_for_display()) {
6883 child_heights += (*t)->effective_height() - (*t)->current_height();
6887 /* compute the per-track height from:
6889 total canvas visible height -
6890 height that will be taken by visible children of selected
6891 tracks - height of the ruler/hscroll area
6893 uint32_t h = (uint32_t) floor ((_visible_canvas_height - (child_heights + _trackview_group->canvas_origin().y)) / visible_tracks);
6894 double first_y_pos = DBL_MAX;
6896 if (h < TimeAxisView::preset_height (HeightSmall)) {
6897 MessageDialog msg (*this, _("There are too many tracks to fit in the current window"));
6898 /* too small to be displayed */
6902 undo_visual_stack.push_back (current_visual_state (true));
6903 no_save_visual = true;
6905 /* build a list of all tracks, including children */
6908 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
6910 TimeAxisView::Children c = (*i)->get_child_list ();
6911 for (TimeAxisView::Children::iterator j = c.begin(); j != c.end(); ++j) {
6912 all.push_back (j->get());
6916 /* operate on all tracks, hide unselected ones that are in the middle of selected ones */
6918 bool within_selected = false;
6920 for (TrackViewList::iterator t = all.begin(); t != all.end(); ++t) {
6922 TrackViewList::iterator next;
6927 if ((*t)->marked_for_display ()) {
6928 if (tracks.contains (*t)) {
6929 (*t)->set_height (h);
6930 first_y_pos = std::min ((*t)->y_position (), first_y_pos);
6931 within_selected = true;
6932 } else if (within_selected) {
6933 hide_track_in_display (*t);
6939 set the controls_layout height now, because waiting for its size
6940 request signal handler will cause the vertical adjustment setting to fail
6943 controls_layout.property_height () = _full_canvas_height;
6944 vertical_adjustment.set_value (first_y_pos);
6946 redo_visual_stack.push_back (current_visual_state (true));
6950 Editor::save_visual_state (uint32_t n)
6952 while (visual_states.size() <= n) {
6953 visual_states.push_back (0);
6956 if (visual_states[n] != 0) {
6957 delete visual_states[n];
6960 visual_states[n] = current_visual_state (true);
6965 Editor::goto_visual_state (uint32_t n)
6967 if (visual_states.size() <= n) {
6971 if (visual_states[n] == 0) {
6975 use_visual_state (*visual_states[n]);
6979 Editor::start_visual_state_op (uint32_t n)
6981 save_visual_state (n);
6983 PopUp* pup = new PopUp (WIN_POS_MOUSE, 1000, true);
6985 snprintf (buf, sizeof (buf), _("Saved view %u"), n+1);
6986 pup->set_text (buf);
6991 Editor::cancel_visual_state_op (uint32_t n)
6993 goto_visual_state (n);
6997 Editor::toggle_region_mute ()
6999 if (_ignore_region_action) {
7003 RegionSelection rs = get_regions_from_selection_and_entered ();
7009 if (rs.size() > 1) {
7010 begin_reversible_command (_("mute regions"));
7012 begin_reversible_command (_("mute region"));
7015 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
7017 (*i)->region()->playlist()->clear_changes ();
7018 (*i)->region()->set_muted (!(*i)->region()->muted ());
7019 _session->add_command (new StatefulDiffCommand ((*i)->region()->playlist()));
7023 commit_reversible_command ();
7027 Editor::combine_regions ()
7029 /* foreach track with selected regions, take all selected regions
7030 and join them into a new region containing the subregions (as a
7034 typedef set<RouteTimeAxisView*> RTVS;
7037 if (selection->regions.empty()) {
7041 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
7042 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(&(*i)->get_time_axis_view());
7045 tracks.insert (rtv);
7049 begin_reversible_command (_("combine regions"));
7051 vector<RegionView*> new_selection;
7053 for (RTVS::iterator i = tracks.begin(); i != tracks.end(); ++i) {
7056 if ((rv = (*i)->combine_regions ()) != 0) {
7057 new_selection.push_back (rv);
7061 selection->clear_regions ();
7062 for (vector<RegionView*>::iterator i = new_selection.begin(); i != new_selection.end(); ++i) {
7063 selection->add (*i);
7066 commit_reversible_command ();
7070 Editor::uncombine_regions ()
7072 typedef set<RouteTimeAxisView*> RTVS;
7075 if (selection->regions.empty()) {
7079 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
7080 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(&(*i)->get_time_axis_view());
7083 tracks.insert (rtv);
7087 begin_reversible_command (_("uncombine regions"));
7089 for (RTVS::iterator i = tracks.begin(); i != tracks.end(); ++i) {
7090 (*i)->uncombine_regions ();
7093 commit_reversible_command ();
7097 Editor::toggle_midi_input_active (bool flip_others)
7100 boost::shared_ptr<RouteList> rl (new RouteList);
7102 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
7103 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
7109 boost::shared_ptr<MidiTrack> mt = rtav->midi_track();
7112 rl->push_back (rtav->route());
7113 onoff = !mt->input_active();
7117 _session->set_exclusive_input_active (rl, onoff, flip_others);