2 Copyright (C) 2000-2004 Paul Davis
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 /* Note: public Editor methods are documented in public_editor.h */
30 #include "pbd/error.h"
31 #include "pbd/basename.h"
32 #include "pbd/pthread_utils.h"
33 #include "pbd/memento_command.h"
34 #include "pbd/unwind.h"
35 #include "pbd/whitespace.h"
36 #include "pbd/stateful_diff_command.h"
38 #include <gtkmm2ext/utils.h>
39 #include <gtkmm2ext/choice.h>
40 #include <gtkmm2ext/popup.h>
42 #include "ardour/audio_track.h"
43 #include "ardour/audioregion.h"
44 #include "ardour/dB.h"
45 #include "ardour/location.h"
46 #include "ardour/midi_region.h"
47 #include "ardour/midi_track.h"
48 #include "ardour/operations.h"
49 #include "ardour/playlist_factory.h"
50 #include "ardour/quantize.h"
51 #include "ardour/region_factory.h"
52 #include "ardour/reverse.h"
53 #include "ardour/session.h"
54 #include "ardour/session_playlists.h"
55 #include "ardour/strip_silence.h"
56 #include "ardour/transient_detector.h"
58 #include "canvas/canvas.h"
61 #include "ardour_ui.h"
62 #include "audio_region_view.h"
63 #include "audio_streamview.h"
64 #include "audio_time_axis.h"
65 #include "automation_time_axis.h"
66 #include "control_point.h"
70 #include "editor_cursors.h"
71 #include "editor_drag.h"
72 #include "editor_regions.h"
73 #include "editor_routes.h"
74 #include "gui_thread.h"
75 #include "insert_time_dialog.h"
76 #include "interthread_progress_window.h"
78 #include "midi_region_view.h"
79 #include "mixer_strip.h"
80 #include "mouse_cursors.h"
81 #include "normalize_dialog.h"
82 #include "patch_change_dialog.h"
83 #include "quantize_dialog.h"
84 #include "region_gain_line.h"
85 #include "rgb_macros.h"
86 #include "route_time_axis.h"
87 #include "selection.h"
88 #include "selection_templates.h"
89 #include "streamview.h"
90 #include "strip_silence_dialog.h"
91 #include "time_axis_view.h"
92 #include "transpose_dialog.h"
97 using namespace ARDOUR;
100 using namespace Gtkmm2ext;
101 using namespace Editing;
102 using Gtkmm2ext::Keyboard;
104 /***********************************************************************
106 ***********************************************************************/
109 Editor::undo (uint32_t n)
111 if (_drags->active ()) {
121 Editor::redo (uint32_t n)
123 if (_drags->active ()) {
133 Editor::split_regions_at (framepos_t where, RegionSelection& regions)
137 RegionSelection pre_selected_regions = selection->regions;
138 bool working_on_selection = !pre_selected_regions.empty();
140 list<boost::shared_ptr<Playlist> > used_playlists;
141 list<RouteTimeAxisView*> used_trackviews;
143 if (regions.empty()) {
147 begin_reversible_command (_("split"));
149 // if splitting a single region, and snap-to is using
150 // region boundaries, don't pay attention to them
152 if (regions.size() == 1) {
153 switch (_snap_type) {
154 case SnapToRegionStart:
155 case SnapToRegionSync:
156 case SnapToRegionEnd:
165 EditorFreeze(); /* Emit Signal */
168 for (RegionSelection::iterator a = regions.begin(); a != regions.end(); ) {
170 RegionSelection::iterator tmp;
172 /* XXX this test needs to be more complicated, to make sure we really
173 have something to split.
176 if (!(*a)->region()->covers (where)) {
184 boost::shared_ptr<Playlist> pl = (*a)->region()->playlist();
192 /* we haven't seen this playlist before */
194 /* remember used playlists so we can thaw them later */
195 used_playlists.push_back(pl);
197 TimeAxisView& tv = (*a)->get_time_axis_view();
198 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (&tv);
200 used_trackviews.push_back (rtv);
207 pl->clear_changes ();
208 pl->split_region ((*a)->region(), where);
209 _session->add_command (new StatefulDiffCommand (pl));
215 vector<sigc::connection> region_added_connections;
217 for (list<RouteTimeAxisView*>::iterator i = used_trackviews.begin(); i != used_trackviews.end(); ++i) {
218 region_added_connections.push_back ((*i)->view()->RegionViewAdded.connect (sigc::mem_fun(*this, &Editor::collect_new_region_view)));
221 latest_regionviews.clear ();
223 while (used_playlists.size() > 0) {
224 list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
226 used_playlists.pop_front();
229 for (vector<sigc::connection>::iterator c = region_added_connections.begin(); c != region_added_connections.end(); ++c) {
233 commit_reversible_command ();
236 EditorThaw(); /* Emit Signal */
239 //IFF we were working on selected regions, try to reinstate the other region selections that existed before the freeze/thaw.
240 _ignore_follow_edits = true; //a split will change the region selection in mysterious ways; its not practical or wanted to follow this edit
241 if( working_on_selection ) {
242 selection->add ( pre_selected_regions );
243 selection->add (latest_regionviews); //these are the new regions created after the split
245 _ignore_follow_edits = false;
249 /** Move one extreme of the current range selection. If more than one range is selected,
250 * the start of the earliest range or the end of the latest range is moved.
252 * @param move_end true to move the end of the current range selection, false to move
254 * @param next true to move the extreme to the next region boundary, false to move to
258 Editor::move_range_selection_start_or_end_to_region_boundary (bool move_end, bool next)
260 if (selection->time.start() == selection->time.end_frame()) {
264 framepos_t start = selection->time.start ();
265 framepos_t end = selection->time.end_frame ();
267 /* the position of the thing we may move */
268 framepos_t pos = move_end ? end : start;
269 int dir = next ? 1 : -1;
271 /* so we don't find the current region again */
272 if (dir > 0 || pos > 0) {
276 framepos_t const target = get_region_boundary (pos, dir, true, false);
291 begin_reversible_command (_("alter selection"));
292 selection->set_preserving_all_ranges (start, end);
293 commit_reversible_command ();
297 Editor::nudge_forward_release (GdkEventButton* ev)
299 if (ev->state & Keyboard::PrimaryModifier) {
300 nudge_forward (false, true);
302 nudge_forward (false, false);
308 Editor::nudge_backward_release (GdkEventButton* ev)
310 if (ev->state & Keyboard::PrimaryModifier) {
311 nudge_backward (false, true);
313 nudge_backward (false, false);
320 Editor::nudge_forward (bool next, bool force_playhead)
323 framepos_t next_distance;
329 RegionSelection rs = get_regions_from_selection_and_entered ();
331 if (!force_playhead && !rs.empty()) {
333 begin_reversible_command (_("nudge regions forward"));
335 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
336 boost::shared_ptr<Region> r ((*i)->region());
338 distance = get_nudge_distance (r->position(), next_distance);
341 distance = next_distance;
345 r->set_position (r->position() + distance);
346 _session->add_command (new StatefulDiffCommand (r));
349 commit_reversible_command ();
352 } else if (!force_playhead && !selection->markers.empty()) {
356 begin_reversible_command (_("nudge location forward"));
358 for (MarkerSelection::iterator i = selection->markers.begin(); i != selection->markers.end(); ++i) {
360 Location* loc = find_location_from_marker ((*i), is_start);
364 XMLNode& before (loc->get_state());
367 distance = get_nudge_distance (loc->start(), next_distance);
369 distance = next_distance;
371 if (max_framepos - distance > loc->start() + loc->length()) {
372 loc->set_start (loc->start() + distance);
374 loc->set_start (max_framepos - loc->length());
377 distance = get_nudge_distance (loc->end(), next_distance);
379 distance = next_distance;
381 if (max_framepos - distance > loc->end()) {
382 loc->set_end (loc->end() + distance);
384 loc->set_end (max_framepos);
387 XMLNode& after (loc->get_state());
388 _session->add_command (new MementoCommand<Location>(*loc, &before, &after));
392 commit_reversible_command ();
395 distance = get_nudge_distance (playhead_cursor->current_frame (), next_distance);
396 _session->request_locate (playhead_cursor->current_frame () + distance);
401 Editor::nudge_backward (bool next, bool force_playhead)
404 framepos_t next_distance;
410 RegionSelection rs = get_regions_from_selection_and_entered ();
412 if (!force_playhead && !rs.empty()) {
414 begin_reversible_command (_("nudge regions backward"));
416 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
417 boost::shared_ptr<Region> r ((*i)->region());
419 distance = get_nudge_distance (r->position(), next_distance);
422 distance = next_distance;
427 if (r->position() > distance) {
428 r->set_position (r->position() - distance);
432 _session->add_command (new StatefulDiffCommand (r));
435 commit_reversible_command ();
437 } else if (!force_playhead && !selection->markers.empty()) {
441 begin_reversible_command (_("nudge location forward"));
443 for (MarkerSelection::iterator i = selection->markers.begin(); i != selection->markers.end(); ++i) {
445 Location* loc = find_location_from_marker ((*i), is_start);
449 XMLNode& before (loc->get_state());
452 distance = get_nudge_distance (loc->start(), next_distance);
454 distance = next_distance;
456 if (distance < loc->start()) {
457 loc->set_start (loc->start() - distance);
462 distance = get_nudge_distance (loc->end(), next_distance);
465 distance = next_distance;
468 if (distance < loc->end() - loc->length()) {
469 loc->set_end (loc->end() - distance);
471 loc->set_end (loc->length());
475 XMLNode& after (loc->get_state());
476 _session->add_command (new MementoCommand<Location>(*loc, &before, &after));
480 commit_reversible_command ();
484 distance = get_nudge_distance (playhead_cursor->current_frame (), next_distance);
486 if (playhead_cursor->current_frame () > distance) {
487 _session->request_locate (playhead_cursor->current_frame () - distance);
489 _session->goto_start();
495 Editor::nudge_forward_capture_offset ()
497 RegionSelection rs = get_regions_from_selection_and_entered ();
499 if (!_session || rs.empty()) {
503 begin_reversible_command (_("nudge forward"));
505 framepos_t const distance = _session->worst_output_latency();
507 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
508 boost::shared_ptr<Region> r ((*i)->region());
511 r->set_position (r->position() + distance);
512 _session->add_command(new StatefulDiffCommand (r));
515 commit_reversible_command ();
519 Editor::nudge_backward_capture_offset ()
521 RegionSelection rs = get_regions_from_selection_and_entered ();
523 if (!_session || rs.empty()) {
527 begin_reversible_command (_("nudge backward"));
529 framepos_t const distance = _session->worst_output_latency();
531 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
532 boost::shared_ptr<Region> r ((*i)->region());
536 if (r->position() > distance) {
537 r->set_position (r->position() - distance);
541 _session->add_command(new StatefulDiffCommand (r));
544 commit_reversible_command ();
547 struct RegionSelectionPositionSorter {
548 bool operator() (RegionView* a, RegionView* b) {
549 return a->region()->position() < b->region()->position();
554 Editor::sequence_regions ()
557 framepos_t r_end_prev;
565 RegionSelection rs = get_regions_from_selection_and_entered ();
566 rs.sort(RegionSelectionPositionSorter());
570 begin_reversible_command (_("sequence regions"));
571 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
572 boost::shared_ptr<Region> r ((*i)->region());
580 if(r->position_locked())
587 r->set_position(r_end_prev);
590 _session->add_command (new StatefulDiffCommand (r));
592 r_end=r->position() + r->length();
596 commit_reversible_command ();
604 Editor::move_to_start ()
606 _session->goto_start ();
610 Editor::move_to_end ()
613 _session->request_locate (_session->current_end_frame());
617 Editor::build_region_boundary_cache ()
620 vector<RegionPoint> interesting_points;
621 boost::shared_ptr<Region> r;
622 TrackViewList tracks;
625 region_boundary_cache.clear ();
631 switch (_snap_type) {
632 case SnapToRegionStart:
633 interesting_points.push_back (Start);
635 case SnapToRegionEnd:
636 interesting_points.push_back (End);
638 case SnapToRegionSync:
639 interesting_points.push_back (SyncPoint);
641 case SnapToRegionBoundary:
642 interesting_points.push_back (Start);
643 interesting_points.push_back (End);
646 fatal << string_compose (_("build_region_boundary_cache called with snap_type = %1"), _snap_type) << endmsg;
651 TimeAxisView *ontrack = 0;
654 if (!selection->tracks.empty()) {
655 tlist = selection->tracks.filter_to_unique_playlists ();
657 tlist = track_views.filter_to_unique_playlists ();
660 while (pos < _session->current_end_frame() && !at_end) {
663 framepos_t lpos = max_framepos;
665 for (vector<RegionPoint>::iterator p = interesting_points.begin(); p != interesting_points.end(); ++p) {
667 if ((r = find_next_region (pos, *p, 1, tlist, &ontrack)) == 0) {
668 if (*p == interesting_points.back()) {
671 /* move to next point type */
677 rpos = r->first_frame();
681 rpos = r->last_frame();
685 rpos = r->sync_position ();
693 RouteTimeAxisView *rtav;
695 if (ontrack != 0 && (rtav = dynamic_cast<RouteTimeAxisView*>(ontrack)) != 0 ) {
696 if (rtav->track() != 0) {
697 speed = rtav->track()->speed();
701 rpos = track_frame_to_session_frame (rpos, speed);
707 /* prevent duplicates, but we don't use set<> because we want to be able
711 vector<framepos_t>::iterator ri;
713 for (ri = region_boundary_cache.begin(); ri != region_boundary_cache.end(); ++ri) {
719 if (ri == region_boundary_cache.end()) {
720 region_boundary_cache.push_back (rpos);
727 /* finally sort to be sure that the order is correct */
729 sort (region_boundary_cache.begin(), region_boundary_cache.end());
732 boost::shared_ptr<Region>
733 Editor::find_next_region (framepos_t frame, RegionPoint point, int32_t dir, TrackViewList& tracks, TimeAxisView **ontrack)
735 TrackViewList::iterator i;
736 framepos_t closest = max_framepos;
737 boost::shared_ptr<Region> ret;
741 framepos_t track_frame;
742 RouteTimeAxisView *rtav;
744 for (i = tracks.begin(); i != tracks.end(); ++i) {
747 boost::shared_ptr<Region> r;
750 if ( (rtav = dynamic_cast<RouteTimeAxisView*>(*i)) != 0 ) {
751 if (rtav->track()!=0)
752 track_speed = rtav->track()->speed();
755 track_frame = session_frame_to_track_frame(frame, track_speed);
757 if ((r = (*i)->find_next_region (track_frame, point, dir)) == 0) {
763 rpos = r->first_frame ();
767 rpos = r->last_frame ();
771 rpos = r->sync_position ();
775 // rpos is a "track frame", converting it to "_session frame"
776 rpos = track_frame_to_session_frame(rpos, track_speed);
779 distance = rpos - frame;
781 distance = frame - rpos;
784 if (distance < closest) {
796 Editor::find_next_region_boundary (framepos_t pos, int32_t dir, const TrackViewList& tracks)
798 framecnt_t distance = max_framepos;
799 framepos_t current_nearest = -1;
801 for (TrackViewList::const_iterator i = tracks.begin(); i != tracks.end(); ++i) {
802 framepos_t contender;
805 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*i);
811 if ((contender = rtv->find_next_region_boundary (pos, dir)) < 0) {
815 d = ::llabs (pos - contender);
818 current_nearest = contender;
823 return current_nearest;
827 Editor::get_region_boundary (framepos_t pos, int32_t dir, bool with_selection, bool only_onscreen)
832 if (with_selection && Config->get_region_boundaries_from_selected_tracks()) {
834 if (!selection->tracks.empty()) {
836 target = find_next_region_boundary (pos, dir, selection->tracks);
840 if (only_onscreen || Config->get_region_boundaries_from_onscreen_tracks()) {
841 get_onscreen_tracks (tvl);
842 target = find_next_region_boundary (pos, dir, tvl);
844 target = find_next_region_boundary (pos, dir, track_views);
850 if (only_onscreen || Config->get_region_boundaries_from_onscreen_tracks()) {
851 get_onscreen_tracks (tvl);
852 target = find_next_region_boundary (pos, dir, tvl);
854 target = find_next_region_boundary (pos, dir, track_views);
862 Editor::cursor_to_region_boundary (bool with_selection, int32_t dir)
864 framepos_t pos = playhead_cursor->current_frame ();
871 // so we don't find the current region again..
872 if (dir > 0 || pos > 0) {
876 if ((target = get_region_boundary (pos, dir, with_selection, false)) < 0) {
880 _session->request_locate (target);
884 Editor::cursor_to_next_region_boundary (bool with_selection)
886 cursor_to_region_boundary (with_selection, 1);
890 Editor::cursor_to_previous_region_boundary (bool with_selection)
892 cursor_to_region_boundary (with_selection, -1);
896 Editor::cursor_to_region_point (EditorCursor* cursor, RegionPoint point, int32_t dir)
898 boost::shared_ptr<Region> r;
899 framepos_t pos = cursor->current_frame ();
905 TimeAxisView *ontrack = 0;
907 // so we don't find the current region again..
911 if (!selection->tracks.empty()) {
913 r = find_next_region (pos, point, dir, selection->tracks, &ontrack);
915 } else if (clicked_axisview) {
918 t.push_back (clicked_axisview);
920 r = find_next_region (pos, point, dir, t, &ontrack);
924 r = find_next_region (pos, point, dir, track_views, &ontrack);
933 pos = r->first_frame ();
937 pos = r->last_frame ();
941 pos = r->sync_position ();
946 RouteTimeAxisView *rtav;
948 if ( ontrack != 0 && (rtav = dynamic_cast<RouteTimeAxisView*>(ontrack)) != 0 ) {
949 if (rtav->track() != 0) {
950 speed = rtav->track()->speed();
954 pos = track_frame_to_session_frame(pos, speed);
956 if (cursor == playhead_cursor) {
957 _session->request_locate (pos);
959 cursor->set_position (pos);
964 Editor::cursor_to_next_region_point (EditorCursor* cursor, RegionPoint point)
966 cursor_to_region_point (cursor, point, 1);
970 Editor::cursor_to_previous_region_point (EditorCursor* cursor, RegionPoint point)
972 cursor_to_region_point (cursor, point, -1);
976 Editor::cursor_to_selection_start (EditorCursor *cursor)
980 switch (mouse_mode) {
982 if (!selection->regions.empty()) {
983 pos = selection->regions.start();
988 if (!selection->time.empty()) {
989 pos = selection->time.start ();
997 if (cursor == playhead_cursor) {
998 _session->request_locate (pos);
1000 cursor->set_position (pos);
1005 Editor::cursor_to_selection_end (EditorCursor *cursor)
1009 switch (mouse_mode) {
1011 if (!selection->regions.empty()) {
1012 pos = selection->regions.end_frame();
1017 if (!selection->time.empty()) {
1018 pos = selection->time.end_frame ();
1026 if (cursor == playhead_cursor) {
1027 _session->request_locate (pos);
1029 cursor->set_position (pos);
1034 Editor::selected_marker_to_region_boundary (bool with_selection, int32_t dir)
1044 if (selection->markers.empty()) {
1048 if (!mouse_frame (mouse, ignored)) {
1052 add_location_mark (mouse);
1055 if ((loc = find_location_from_marker (selection->markers.front(), ignored)) == 0) {
1059 framepos_t pos = loc->start();
1061 // so we don't find the current region again..
1062 if (dir > 0 || pos > 0) {
1066 if ((target = get_region_boundary (pos, dir, with_selection, false)) < 0) {
1070 loc->move_to (target);
1074 Editor::selected_marker_to_next_region_boundary (bool with_selection)
1076 selected_marker_to_region_boundary (with_selection, 1);
1080 Editor::selected_marker_to_previous_region_boundary (bool with_selection)
1082 selected_marker_to_region_boundary (with_selection, -1);
1086 Editor::selected_marker_to_region_point (RegionPoint point, int32_t dir)
1088 boost::shared_ptr<Region> r;
1093 if (!_session || selection->markers.empty()) {
1097 if ((loc = find_location_from_marker (selection->markers.front(), ignored)) == 0) {
1101 TimeAxisView *ontrack = 0;
1105 // so we don't find the current region again..
1109 if (!selection->tracks.empty()) {
1111 r = find_next_region (pos, point, dir, selection->tracks, &ontrack);
1115 r = find_next_region (pos, point, dir, track_views, &ontrack);
1124 pos = r->first_frame ();
1128 pos = r->last_frame ();
1132 pos = r->adjust_to_sync (r->first_frame());
1137 RouteTimeAxisView *rtav;
1139 if (ontrack != 0 && (rtav = dynamic_cast<RouteTimeAxisView*>(ontrack)) != 0) {
1140 if (rtav->track() != 0) {
1141 speed = rtav->track()->speed();
1145 pos = track_frame_to_session_frame(pos, speed);
1151 Editor::selected_marker_to_next_region_point (RegionPoint point)
1153 selected_marker_to_region_point (point, 1);
1157 Editor::selected_marker_to_previous_region_point (RegionPoint point)
1159 selected_marker_to_region_point (point, -1);
1163 Editor::selected_marker_to_selection_start ()
1169 if (!_session || selection->markers.empty()) {
1173 if ((loc = find_location_from_marker (selection->markers.front(), ignored)) == 0) {
1177 switch (mouse_mode) {
1179 if (!selection->regions.empty()) {
1180 pos = selection->regions.start();
1185 if (!selection->time.empty()) {
1186 pos = selection->time.start ();
1198 Editor::selected_marker_to_selection_end ()
1204 if (!_session || selection->markers.empty()) {
1208 if ((loc = find_location_from_marker (selection->markers.front(), ignored)) == 0) {
1212 switch (mouse_mode) {
1214 if (!selection->regions.empty()) {
1215 pos = selection->regions.end_frame();
1220 if (!selection->time.empty()) {
1221 pos = selection->time.end_frame ();
1233 Editor::scroll_playhead (bool forward)
1235 framepos_t pos = playhead_cursor->current_frame ();
1236 framecnt_t delta = (framecnt_t) floor (current_page_samples() / 0.8);
1239 if (pos == max_framepos) {
1243 if (pos < max_framepos - delta) {
1262 _session->request_locate (pos);
1266 Editor::cursor_align (bool playhead_to_edit)
1272 if (playhead_to_edit) {
1274 if (selection->markers.empty()) {
1278 _session->request_locate (selection->markers.front()->position(), _session->transport_rolling());
1281 /* move selected markers to playhead */
1283 for (MarkerSelection::iterator i = selection->markers.begin(); i != selection->markers.end(); ++i) {
1286 Location* loc = find_location_from_marker (*i, ignored);
1288 if (loc->is_mark()) {
1289 loc->set_start (playhead_cursor->current_frame ());
1291 loc->set (playhead_cursor->current_frame (),
1292 playhead_cursor->current_frame () + loc->length());
1299 Editor::scroll_backward (float pages)
1301 framepos_t const one_page = (framepos_t) rint (_visible_canvas_width * samples_per_pixel);
1302 framepos_t const cnt = (framepos_t) floor (pages * one_page);
1305 if (leftmost_frame < cnt) {
1308 frame = leftmost_frame - cnt;
1311 reset_x_origin (frame);
1315 Editor::scroll_forward (float pages)
1317 framepos_t const one_page = (framepos_t) rint (_visible_canvas_width * samples_per_pixel);
1318 framepos_t const cnt = (framepos_t) floor (pages * one_page);
1321 if (max_framepos - cnt < leftmost_frame) {
1322 frame = max_framepos - cnt;
1324 frame = leftmost_frame + cnt;
1327 reset_x_origin (frame);
1331 Editor::scroll_tracks_down ()
1333 double vert_value = vertical_adjustment.get_value() + vertical_adjustment.get_page_size();
1334 if (vert_value > vertical_adjustment.get_upper() - _visible_canvas_height) {
1335 vert_value = vertical_adjustment.get_upper() - _visible_canvas_height;
1338 vertical_adjustment.set_value (vert_value);
1342 Editor::scroll_tracks_up ()
1344 vertical_adjustment.set_value (vertical_adjustment.get_value() - vertical_adjustment.get_page_size());
1348 Editor::scroll_tracks_down_line ()
1350 double vert_value = vertical_adjustment.get_value() + 60;
1352 if (vert_value > vertical_adjustment.get_upper() - _visible_canvas_height) {
1353 vert_value = vertical_adjustment.get_upper() - _visible_canvas_height;
1356 vertical_adjustment.set_value (vert_value);
1360 Editor::scroll_tracks_up_line ()
1362 reset_y_origin (vertical_adjustment.get_value() - 60);
1366 Editor::scroll_down_one_track ()
1368 TrackViewList::reverse_iterator next = track_views.rbegin();
1369 std::pair<TimeAxisView*,double> res;
1370 const double top_of_trackviews = vertical_adjustment.get_value();
1372 for (TrackViewList::reverse_iterator t = track_views.rbegin(); t != track_views.rend(); ++t) {
1373 if ((*t)->hidden()) {
1378 if (next != track_views.rbegin()) {
1379 --next; // moves "next" towards the lower/later tracks since it is a reverse iterator
1382 /* If this is the upper-most visible trackview, we want to display
1383 the one above it (next)
1386 res = (*t)->covers_y_position (top_of_trackviews);
1393 /* move to the track below the first one that covers the */
1395 if (next != track_views.rbegin()) {
1396 ensure_time_axis_view_is_visible (**next, true);
1404 Editor::scroll_up_one_track ()
1406 TrackViewList::iterator prev = track_views.end();
1407 std::pair<TimeAxisView*,double> res;
1408 double top_of_trackviews = vertical_adjustment.get_value ();
1410 for (TrackViewList::iterator t = track_views.begin(); t != track_views.end(); ++t) {
1412 if ((*t)->hidden()) {
1416 /* find the trackview at the top of the trackview group */
1417 res = (*t)->covers_y_position (top_of_trackviews);
1426 if (prev != track_views.end()) {
1427 ensure_time_axis_view_is_visible (**prev, true);
1437 Editor::tav_zoom_step (bool coarser)
1439 DisplaySuspender ds;
1443 if (selection->tracks.empty()) {
1446 ts = &selection->tracks;
1449 for (TrackViewList::iterator i = ts->begin(); i != ts->end(); ++i) {
1450 TimeAxisView *tv = (static_cast<TimeAxisView*>(*i));
1451 tv->step_height (coarser);
1456 Editor::tav_zoom_smooth (bool coarser, bool force_all)
1458 DisplaySuspender ds;
1462 if (selection->tracks.empty() || force_all) {
1465 ts = &selection->tracks;
1468 for (TrackViewList::iterator i = ts->begin(); i != ts->end(); ++i) {
1469 TimeAxisView *tv = (static_cast<TimeAxisView*>(*i));
1470 uint32_t h = tv->current_height ();
1475 if (h >= TimeAxisView::preset_height (HeightSmall)) {
1480 tv->set_height (h + 5);
1487 Editor::temporal_zoom_step (bool coarser)
1489 ENSURE_GUI_THREAD (*this, &Editor::temporal_zoom_step, coarser)
1491 framecnt_t nspp = samples_per_pixel;
1499 temporal_zoom (nspp);
1503 Editor::temporal_zoom (framecnt_t fpp)
1509 framepos_t current_page = current_page_samples();
1510 framepos_t current_leftmost = leftmost_frame;
1511 framepos_t current_rightmost;
1512 framepos_t current_center;
1513 framepos_t new_page_size;
1514 framepos_t half_page_size;
1515 framepos_t leftmost_after_zoom = 0;
1517 bool in_track_canvas;
1521 if (fpp == samples_per_pixel) {
1525 // Imposing an arbitrary limit to zoom out as too much zoom out produces
1526 // segfaults for lack of memory. If somebody decides this is not high enough I
1527 // believe it can be raisen to higher values but some limit must be in place.
1529 // This constant represents 1 day @ 48kHz on a 1600 pixel wide display
1530 // all of which is used for the editor track displays. The whole day
1531 // would be 4147200000 samples, so 2592000 samples per pixel.
1533 nfpp = min (fpp, (framecnt_t) 2592000);
1534 nfpp = max ((framecnt_t) 1, fpp);
1536 new_page_size = (framepos_t) floor (_visible_canvas_width * nfpp);
1537 half_page_size = new_page_size / 2;
1539 switch (zoom_focus) {
1541 leftmost_after_zoom = current_leftmost;
1544 case ZoomFocusRight:
1545 current_rightmost = leftmost_frame + current_page;
1546 if (current_rightmost < new_page_size) {
1547 leftmost_after_zoom = 0;
1549 leftmost_after_zoom = current_rightmost - new_page_size;
1553 case ZoomFocusCenter:
1554 current_center = current_leftmost + (current_page/2);
1555 if (current_center < half_page_size) {
1556 leftmost_after_zoom = 0;
1558 leftmost_after_zoom = current_center - half_page_size;
1562 case ZoomFocusPlayhead:
1563 /* centre playhead */
1564 l = playhead_cursor->current_frame () - (new_page_size * 0.5);
1567 leftmost_after_zoom = 0;
1568 } else if (l > max_framepos) {
1569 leftmost_after_zoom = max_framepos - new_page_size;
1571 leftmost_after_zoom = (framepos_t) l;
1575 case ZoomFocusMouse:
1576 /* try to keep the mouse over the same point in the display */
1578 if (!mouse_frame (where, in_track_canvas)) {
1579 /* use playhead instead */
1580 where = playhead_cursor->current_frame ();
1582 if (where < half_page_size) {
1583 leftmost_after_zoom = 0;
1585 leftmost_after_zoom = where - half_page_size;
1590 l = - ((new_page_size * ((where - current_leftmost)/(double)current_page)) - where);
1593 leftmost_after_zoom = 0;
1594 } else if (l > max_framepos) {
1595 leftmost_after_zoom = max_framepos - new_page_size;
1597 leftmost_after_zoom = (framepos_t) l;
1604 /* try to keep the edit point in the same place */
1605 where = get_preferred_edit_position ();
1609 double l = - ((new_page_size * ((where - current_leftmost)/(double)current_page)) - where);
1612 leftmost_after_zoom = 0;
1613 } else if (l > max_framepos) {
1614 leftmost_after_zoom = max_framepos - new_page_size;
1616 leftmost_after_zoom = (framepos_t) l;
1620 /* edit point not defined */
1627 // leftmost_after_zoom = min (leftmost_after_zoom, _session->current_end_frame());
1629 reposition_and_zoom (leftmost_after_zoom, nfpp);
1633 Editor::calc_extra_zoom_edges(framepos_t &start, framepos_t &end)
1635 /* this func helps make sure we leave a little space
1636 at each end of the editor so that the zoom doesn't fit the region
1637 precisely to the screen.
1640 GdkScreen* screen = gdk_screen_get_default ();
1641 gint pixwidth = gdk_screen_get_width (screen);
1642 gint mmwidth = gdk_screen_get_width_mm (screen);
1643 double pix_per_mm = (double) pixwidth/ (double) mmwidth;
1644 double one_centimeter_in_pixels = pix_per_mm * 10.0;
1646 framepos_t range = end - start;
1647 double new_fpp = (double) range / (double) _visible_canvas_width;
1648 framepos_t extra_samples = (framepos_t) floor (one_centimeter_in_pixels * new_fpp);
1650 if (start > extra_samples) {
1651 start -= extra_samples;
1656 if (max_framepos - extra_samples > end) {
1657 end += extra_samples;
1665 Editor::temporal_zoom_region (bool both_axes)
1667 framepos_t start = max_framepos;
1669 set<TimeAxisView*> tracks;
1671 RegionSelection rs = get_regions_from_selection_and_entered ();
1677 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
1679 if ((*i)->region()->position() < start) {
1680 start = (*i)->region()->position();
1683 if ((*i)->region()->last_frame() + 1 > end) {
1684 end = (*i)->region()->last_frame() + 1;
1687 tracks.insert (&((*i)->get_time_axis_view()));
1690 if ((start == 0 && end == 0) || end < start) {
1694 calc_extra_zoom_edges(start, end);
1696 /* if we're zooming on both axes we need to save track heights etc.
1699 undo_visual_stack.push_back (current_visual_state (both_axes));
1701 PBD::Unwinder<bool> nsv (no_save_visual, true);
1703 temporal_zoom_by_frame (start, end);
1706 uint32_t per_track_height = (uint32_t) floor ((_visible_canvas_height - 10.0) / tracks.size());
1708 /* set visible track heights appropriately */
1710 for (set<TimeAxisView*>::iterator t = tracks.begin(); t != tracks.end(); ++t) {
1711 (*t)->set_height (per_track_height);
1714 /* hide irrelevant tracks */
1716 DisplaySuspender ds;
1718 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1719 if (find (tracks.begin(), tracks.end(), (*i)) == tracks.end()) {
1720 hide_track_in_display (*i);
1724 vertical_adjustment.set_value (0.0);
1727 redo_visual_stack.push_back (current_visual_state (both_axes));
1731 Editor::zoom_to_region (bool both_axes)
1733 temporal_zoom_region (both_axes);
1737 Editor::temporal_zoom_selection (bool both_axes)
1739 if (!selection) return;
1741 //if a range is selected, zoom to that
1742 if (!selection->time.empty()) {
1744 framepos_t start = selection->time.start();
1745 framepos_t end = selection->time.end_frame();
1747 calc_extra_zoom_edges(start, end);
1749 temporal_zoom_by_frame (start, end);
1752 fit_selected_tracks();
1755 temporal_zoom_region(both_axes);
1762 Editor::temporal_zoom_session ()
1764 ENSURE_GUI_THREAD (*this, &Editor::temporal_zoom_session)
1767 framecnt_t start = _session->current_start_frame();
1768 framecnt_t end = _session->current_end_frame();
1770 if (_session->actively_recording () ) {
1771 framepos_t cur = playhead_cursor->current_frame ();
1773 /* recording beyond the end marker; zoom out
1774 * by 5 seconds more so that if 'follow
1775 * playhead' is active we don't immediately
1778 end = cur + _session->frame_rate() * 5;
1782 if ((start == 0 && end == 0) || end < start) {
1786 calc_extra_zoom_edges(start, end);
1788 temporal_zoom_by_frame (start, end);
1793 Editor::temporal_zoom_by_frame (framepos_t start, framepos_t end)
1795 if (!_session) return;
1797 if ((start == 0 && end == 0) || end < start) {
1801 framepos_t range = end - start;
1803 double const new_fpp = (double) range / (double) _visible_canvas_width;
1805 framepos_t new_page = (framepos_t) floor (_visible_canvas_width * new_fpp);
1806 framepos_t middle = (framepos_t) floor ((double) start + ((double) range / 2.0f));
1807 framepos_t new_leftmost = (framepos_t) floor ((double) middle - ((double) new_page / 2.0f));
1809 if (new_leftmost > middle) {
1813 if (new_leftmost < 0) {
1817 reposition_and_zoom (new_leftmost, new_fpp);
1821 Editor::temporal_zoom_to_frame (bool coarser, framepos_t frame)
1827 framecnt_t range_before = frame - leftmost_frame;
1831 if (samples_per_pixel <= 1) {
1834 new_spp = samples_per_pixel + (samples_per_pixel/2);
1836 range_before += range_before/2;
1838 if (samples_per_pixel >= 1) {
1839 new_spp = samples_per_pixel - (samples_per_pixel/2);
1841 /* could bail out here since we cannot zoom any finer,
1842 but leave that to the equality test below
1844 new_spp = samples_per_pixel;
1847 range_before -= range_before/2;
1850 if (new_spp == samples_per_pixel) {
1854 /* zoom focus is automatically taken as @param frame when this
1858 framepos_t new_leftmost = frame - (framepos_t)range_before;
1860 if (new_leftmost > frame) {
1864 if (new_leftmost < 0) {
1868 reposition_and_zoom (new_leftmost, new_spp);
1873 Editor::choose_new_marker_name(string &name) {
1875 if (!Config->get_name_new_markers()) {
1876 /* don't prompt user for a new name */
1880 ArdourPrompter dialog (true);
1882 dialog.set_prompt (_("New Name:"));
1884 dialog.set_title (_("New Location Marker"));
1886 dialog.set_name ("MarkNameWindow");
1887 dialog.set_size_request (250, -1);
1888 dialog.set_position (Gtk::WIN_POS_MOUSE);
1890 dialog.add_button (Stock::OK, RESPONSE_ACCEPT);
1891 dialog.set_initial_text (name);
1895 switch (dialog.run ()) {
1896 case RESPONSE_ACCEPT:
1902 dialog.get_result(name);
1909 Editor::add_location_from_selection ()
1913 if (selection->time.empty()) {
1917 if (_session == 0 || clicked_axisview == 0) {
1921 framepos_t start = selection->time[clicked_selection].start;
1922 framepos_t end = selection->time[clicked_selection].end;
1924 _session->locations()->next_available_name(rangename,"selection");
1925 Location *location = new Location (*_session, start, end, rangename, Location::IsRangeMarker);
1927 _session->begin_reversible_command (_("add marker"));
1928 XMLNode &before = _session->locations()->get_state();
1929 _session->locations()->add (location, true);
1930 XMLNode &after = _session->locations()->get_state();
1931 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
1932 _session->commit_reversible_command ();
1936 Editor::add_location_mark (framepos_t where)
1940 select_new_marker = true;
1942 _session->locations()->next_available_name(markername,"mark");
1943 if (!choose_new_marker_name(markername)) {
1946 Location *location = new Location (*_session, where, where, markername, Location::IsMark);
1947 _session->begin_reversible_command (_("add marker"));
1948 XMLNode &before = _session->locations()->get_state();
1949 _session->locations()->add (location, true);
1950 XMLNode &after = _session->locations()->get_state();
1951 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
1952 _session->commit_reversible_command ();
1956 Editor::add_location_from_playhead_cursor ()
1958 add_location_mark (_session->audible_frame());
1962 Editor::remove_location_at_playhead_cursor ()
1967 _session->begin_reversible_command (_("remove marker"));
1968 XMLNode &before = _session->locations()->get_state();
1969 bool removed = false;
1971 //find location(s) at this time
1972 Locations::LocationList locs;
1973 _session->locations()->find_all_between (_session->audible_frame(), _session->audible_frame()+1, locs, Location::Flags(0));
1974 for (Locations::LocationList::iterator i = locs.begin(); i != locs.end(); ++i) {
1975 if ((*i)->is_mark()) {
1976 _session->locations()->remove (*i);
1983 XMLNode &after = _session->locations()->get_state();
1984 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
1985 _session->commit_reversible_command ();
1990 /** Add a range marker around each selected region */
1992 Editor::add_locations_from_region ()
1994 RegionSelection rs = get_regions_from_selection_and_entered ();
2000 _session->begin_reversible_command (selection->regions.size () > 1 ? _("add markers") : _("add marker"));
2001 XMLNode &before = _session->locations()->get_state();
2003 for (RegionSelection::iterator i = rs.begin (); i != rs.end (); ++i) {
2005 boost::shared_ptr<Region> region = (*i)->region ();
2007 Location *location = new Location (*_session, region->position(), region->last_frame(), region->name(), Location::IsRangeMarker);
2009 _session->locations()->add (location, true);
2012 XMLNode &after = _session->locations()->get_state();
2013 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2014 _session->commit_reversible_command ();
2017 /** Add a single range marker around all selected regions */
2019 Editor::add_location_from_region ()
2021 RegionSelection rs = get_regions_from_selection_and_entered ();
2027 _session->begin_reversible_command (_("add marker"));
2028 XMLNode &before = _session->locations()->get_state();
2032 if (rs.size() > 1) {
2033 _session->locations()->next_available_name(markername, "regions");
2035 RegionView* rv = *(rs.begin());
2036 boost::shared_ptr<Region> region = rv->region();
2037 markername = region->name();
2040 if (!choose_new_marker_name(markername)) {
2044 // single range spanning all selected
2045 Location *location = new Location (*_session, selection->regions.start(), selection->regions.end_frame(), markername, Location::IsRangeMarker);
2046 _session->locations()->add (location, true);
2048 XMLNode &after = _session->locations()->get_state();
2049 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2050 _session->commit_reversible_command ();
2056 Editor::jump_forward_to_mark ()
2062 framepos_t pos = _session->locations()->first_mark_after (playhead_cursor->current_frame());
2068 _session->request_locate (pos, _session->transport_rolling());
2072 Editor::jump_backward_to_mark ()
2078 framepos_t pos = _session->locations()->first_mark_before (playhead_cursor->current_frame());
2084 _session->request_locate (pos, _session->transport_rolling());
2090 framepos_t const pos = _session->audible_frame ();
2093 _session->locations()->next_available_name (markername, "mark");
2095 if (!choose_new_marker_name (markername)) {
2099 _session->locations()->add (new Location (*_session, pos, 0, markername, Location::IsMark), true);
2103 Editor::clear_markers ()
2106 _session->begin_reversible_command (_("clear markers"));
2107 XMLNode &before = _session->locations()->get_state();
2108 _session->locations()->clear_markers ();
2109 XMLNode &after = _session->locations()->get_state();
2110 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2111 _session->commit_reversible_command ();
2116 Editor::clear_ranges ()
2119 _session->begin_reversible_command (_("clear ranges"));
2120 XMLNode &before = _session->locations()->get_state();
2122 Location * looploc = _session->locations()->auto_loop_location();
2123 Location * punchloc = _session->locations()->auto_punch_location();
2124 Location * sessionloc = _session->locations()->session_range_location();
2126 _session->locations()->clear_ranges ();
2128 if (looploc) _session->locations()->add (looploc);
2129 if (punchloc) _session->locations()->add (punchloc);
2130 if (sessionloc) _session->locations()->add (sessionloc);
2132 XMLNode &after = _session->locations()->get_state();
2133 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2134 _session->commit_reversible_command ();
2139 Editor::clear_locations ()
2141 _session->begin_reversible_command (_("clear locations"));
2142 XMLNode &before = _session->locations()->get_state();
2143 _session->locations()->clear ();
2144 XMLNode &after = _session->locations()->get_state();
2145 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2146 _session->commit_reversible_command ();
2147 _session->locations()->clear ();
2151 Editor::unhide_markers ()
2153 for (LocationMarkerMap::iterator i = location_markers.begin(); i != location_markers.end(); ++i) {
2154 Location *l = (*i).first;
2155 if (l->is_hidden() && l->is_mark()) {
2156 l->set_hidden(false, this);
2162 Editor::unhide_ranges ()
2164 for (LocationMarkerMap::iterator i = location_markers.begin(); i != location_markers.end(); ++i) {
2165 Location *l = (*i).first;
2166 if (l->is_hidden() && l->is_range_marker()) {
2167 l->set_hidden(false, this);
2172 /* INSERT/REPLACE */
2175 Editor::insert_region_list_selection (float times)
2177 RouteTimeAxisView *tv = 0;
2178 boost::shared_ptr<Playlist> playlist;
2180 if (clicked_routeview != 0) {
2181 tv = clicked_routeview;
2182 } else if (!selection->tracks.empty()) {
2183 if ((tv = dynamic_cast<RouteTimeAxisView*>(selection->tracks.front())) == 0) {
2186 } else if (entered_track != 0) {
2187 if ((tv = dynamic_cast<RouteTimeAxisView*>(entered_track)) == 0) {
2194 if ((playlist = tv->playlist()) == 0) {
2198 boost::shared_ptr<Region> region = _regions->get_single_selection ();
2203 begin_reversible_command (_("insert region"));
2204 playlist->clear_changes ();
2205 playlist->add_region ((RegionFactory::create (region, true)), get_preferred_edit_position(), times);
2206 if (Config->get_edit_mode() == Ripple)
2207 playlist->ripple (get_preferred_edit_position(), region->length() * times, boost::shared_ptr<Region>());
2209 _session->add_command(new StatefulDiffCommand (playlist));
2210 commit_reversible_command ();
2213 /* BUILT-IN EFFECTS */
2216 Editor::reverse_selection ()
2221 /* GAIN ENVELOPE EDITING */
2224 Editor::edit_envelope ()
2231 Editor::transition_to_rolling (bool fwd)
2237 if (_session->config.get_external_sync()) {
2238 switch (Config->get_sync_source()) {
2242 /* transport controlled by the master */
2247 if (_session->is_auditioning()) {
2248 _session->cancel_audition ();
2252 _session->request_transport_speed (fwd ? 1.0f : -1.0f);
2256 Editor::play_from_start ()
2258 _session->request_locate (_session->current_start_frame(), true);
2262 Editor::play_from_edit_point ()
2264 _session->request_locate (get_preferred_edit_position(), true);
2268 Editor::play_from_edit_point_and_return ()
2270 framepos_t start_frame;
2271 framepos_t return_frame;
2273 start_frame = get_preferred_edit_position (true);
2275 if (_session->transport_rolling()) {
2276 _session->request_locate (start_frame, false);
2280 /* don't reset the return frame if its already set */
2282 if ((return_frame = _session->requested_return_frame()) < 0) {
2283 return_frame = _session->audible_frame();
2286 if (start_frame >= 0) {
2287 _session->request_roll_at_and_return (start_frame, return_frame);
2292 Editor::play_selection ()
2294 if (selection->time.empty()) {
2298 _session->request_play_range (&selection->time, true);
2302 Editor::get_preroll ()
2304 return 1.0 /*Config->get_edit_preroll_seconds()*/ * _session->frame_rate();
2309 Editor::maybe_locate_with_edit_preroll ( framepos_t location )
2311 if ( _session->transport_rolling() || !Config->get_follow_edits() || _ignore_follow_edits )
2314 location -= get_preroll();
2316 //don't try to locate before the beginning of time
2320 //if follow_playhead is on, keep the playhead on the screen
2321 if ( _follow_playhead )
2322 if ( location < leftmost_frame )
2323 location = leftmost_frame;
2325 _session->request_locate( location );
2329 Editor::play_with_preroll ()
2331 if (selection->time.empty()) {
2334 framepos_t preroll = get_preroll();
2336 framepos_t start = 0;
2337 if (selection->time[clicked_selection].start > preroll)
2338 start = selection->time[clicked_selection].start - preroll;
2340 framepos_t end = selection->time[clicked_selection].end + preroll;
2342 AudioRange ar (start, end, 0);
2343 list<AudioRange> lar;
2346 _session->request_play_range (&lar, true);
2351 Editor::play_location (Location& location)
2353 if (location.start() <= location.end()) {
2357 _session->request_bounded_roll (location.start(), location.end());
2361 Editor::loop_location (Location& location)
2363 if (location.start() <= location.end()) {
2369 if ((tll = transport_loop_location()) != 0) {
2370 tll->set (location.start(), location.end());
2372 // enable looping, reposition and start rolling
2373 _session->request_locate (tll->start(), true);
2374 _session->request_play_loop (true);
2379 Editor::do_layer_operation (LayerOperation op)
2381 if (selection->regions.empty ()) {
2385 bool const multiple = selection->regions.size() > 1;
2389 begin_reversible_command (_("raise regions"));
2391 begin_reversible_command (_("raise region"));
2397 begin_reversible_command (_("raise regions to top"));
2399 begin_reversible_command (_("raise region to top"));
2405 begin_reversible_command (_("lower regions"));
2407 begin_reversible_command (_("lower region"));
2413 begin_reversible_command (_("lower regions to bottom"));
2415 begin_reversible_command (_("lower region"));
2420 set<boost::shared_ptr<Playlist> > playlists = selection->regions.playlists ();
2421 for (set<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
2422 (*i)->clear_owned_changes ();
2425 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
2426 boost::shared_ptr<Region> r = (*i)->region ();
2438 r->lower_to_bottom ();
2442 for (set<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
2443 vector<Command*> cmds;
2445 _session->add_commands (cmds);
2448 commit_reversible_command ();
2452 Editor::raise_region ()
2454 do_layer_operation (Raise);
2458 Editor::raise_region_to_top ()
2460 do_layer_operation (RaiseToTop);
2464 Editor::lower_region ()
2466 do_layer_operation (Lower);
2470 Editor::lower_region_to_bottom ()
2472 do_layer_operation (LowerToBottom);
2475 /** Show the region editor for the selected regions */
2477 Editor::show_region_properties ()
2479 selection->foreach_regionview (&RegionView::show_region_editor);
2482 /** Show the midi list editor for the selected MIDI regions */
2484 Editor::show_midi_list_editor ()
2486 selection->foreach_midi_regionview (&MidiRegionView::show_list_editor);
2490 Editor::rename_region ()
2492 RegionSelection rs = get_regions_from_selection_and_entered ();
2498 ArdourDialog d (*this, _("Rename Region"), true, false);
2500 Label label (_("New name:"));
2503 hbox.set_spacing (6);
2504 hbox.pack_start (label, false, false);
2505 hbox.pack_start (entry, true, true);
2507 d.get_vbox()->set_border_width (12);
2508 d.get_vbox()->pack_start (hbox, false, false);
2510 d.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
2511 d.add_button(Gtk::Stock::OK, Gtk::RESPONSE_OK);
2513 d.set_size_request (300, -1);
2515 entry.set_text (rs.front()->region()->name());
2516 entry.select_region (0, -1);
2518 entry.signal_activate().connect (sigc::bind (sigc::mem_fun (d, &Dialog::response), RESPONSE_OK));
2524 int const ret = d.run();
2528 if (ret != RESPONSE_OK) {
2532 std::string str = entry.get_text();
2533 strip_whitespace_edges (str);
2535 rs.front()->region()->set_name (str);
2536 _regions->redisplay ();
2541 Editor::audition_playlist_region_via_route (boost::shared_ptr<Region> region, Route& route)
2543 if (_session->is_auditioning()) {
2544 _session->cancel_audition ();
2547 // note: some potential for creativity here, because region doesn't
2548 // have to belong to the playlist that Route is handling
2550 // bool was_soloed = route.soloed();
2552 route.set_solo (true, this);
2554 _session->request_bounded_roll (region->position(), region->position() + region->length());
2556 /* XXX how to unset the solo state ? */
2559 /** Start an audition of the first selected region */
2561 Editor::play_edit_range ()
2563 framepos_t start, end;
2565 if (get_edit_op_range (start, end)) {
2566 _session->request_bounded_roll (start, end);
2571 Editor::play_selected_region ()
2573 framepos_t start = max_framepos;
2576 RegionSelection rs = get_regions_from_selection_and_entered ();
2582 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
2583 if ((*i)->region()->position() < start) {
2584 start = (*i)->region()->position();
2586 if ((*i)->region()->last_frame() + 1 > end) {
2587 end = (*i)->region()->last_frame() + 1;
2591 _session->request_bounded_roll (start, end);
2595 Editor::audition_playlist_region_standalone (boost::shared_ptr<Region> region)
2597 _session->audition_region (region);
2601 Editor::region_from_selection ()
2603 if (clicked_axisview == 0) {
2607 if (selection->time.empty()) {
2611 framepos_t start = selection->time[clicked_selection].start;
2612 framepos_t end = selection->time[clicked_selection].end;
2614 TrackViewList tracks = get_tracks_for_range_action ();
2616 framepos_t selection_cnt = end - start + 1;
2618 for (TrackSelection::iterator i = tracks.begin(); i != tracks.end(); ++i) {
2619 boost::shared_ptr<Region> current;
2620 boost::shared_ptr<Playlist> pl;
2621 framepos_t internal_start;
2624 if ((pl = (*i)->playlist()) == 0) {
2628 if ((current = pl->top_region_at (start)) == 0) {
2632 internal_start = start - current->position();
2633 RegionFactory::region_name (new_name, current->name(), true);
2637 plist.add (ARDOUR::Properties::start, current->start() + internal_start);
2638 plist.add (ARDOUR::Properties::length, selection_cnt);
2639 plist.add (ARDOUR::Properties::name, new_name);
2640 plist.add (ARDOUR::Properties::layer, 0);
2642 boost::shared_ptr<Region> region (RegionFactory::create (current, plist));
2647 Editor::create_region_from_selection (vector<boost::shared_ptr<Region> >& new_regions)
2649 if (selection->time.empty() || selection->tracks.empty()) {
2653 framepos_t start = selection->time[clicked_selection].start;
2654 framepos_t end = selection->time[clicked_selection].end;
2656 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
2657 sort_track_selection (ts);
2659 for (TrackSelection::iterator i = ts.begin(); i != ts.end(); ++i) {
2660 boost::shared_ptr<Region> current;
2661 boost::shared_ptr<Playlist> playlist;
2662 framepos_t internal_start;
2665 if ((playlist = (*i)->playlist()) == 0) {
2669 if ((current = playlist->top_region_at(start)) == 0) {
2673 internal_start = start - current->position();
2674 RegionFactory::region_name (new_name, current->name(), true);
2678 plist.add (ARDOUR::Properties::start, current->start() + internal_start);
2679 plist.add (ARDOUR::Properties::length, end - start + 1);
2680 plist.add (ARDOUR::Properties::name, new_name);
2682 new_regions.push_back (RegionFactory::create (current, plist));
2687 Editor::split_multichannel_region ()
2689 RegionSelection rs = get_regions_from_selection_and_entered ();
2695 vector< boost::shared_ptr<Region> > v;
2697 for (list<RegionView*>::iterator x = rs.begin(); x != rs.end(); ++x) {
2698 (*x)->region()->separate_by_channel (*_session, v);
2703 Editor::new_region_from_selection ()
2705 region_from_selection ();
2706 cancel_selection ();
2710 add_if_covered (RegionView* rv, const AudioRange* ar, RegionSelection* rs)
2712 switch (rv->region()->coverage (ar->start, ar->end - 1)) {
2713 case Evoral::OverlapNone:
2721 * - selected tracks, or if there are none...
2722 * - tracks containing selected regions, or if there are none...
2727 Editor::get_tracks_for_range_action () const
2731 if (selection->tracks.empty()) {
2733 /* use tracks with selected regions */
2735 RegionSelection rs = selection->regions;
2737 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
2738 TimeAxisView* tv = &(*i)->get_time_axis_view();
2740 if (!t.contains (tv)) {
2746 /* no regions and no tracks: use all tracks */
2752 t = selection->tracks;
2755 return t.filter_to_unique_playlists();
2759 Editor::separate_regions_between (const TimeSelection& ts)
2761 bool in_command = false;
2762 boost::shared_ptr<Playlist> playlist;
2763 RegionSelection new_selection;
2765 TrackViewList tmptracks = get_tracks_for_range_action ();
2766 sort_track_selection (tmptracks);
2768 for (TrackSelection::iterator i = tmptracks.begin(); i != tmptracks.end(); ++i) {
2770 RouteTimeAxisView* rtv;
2772 if ((rtv = dynamic_cast<RouteTimeAxisView*> ((*i))) != 0) {
2774 if (rtv->is_track()) {
2776 /* no edits to destructive tracks */
2778 if (rtv->track()->destructive()) {
2782 if ((playlist = rtv->playlist()) != 0) {
2784 playlist->clear_changes ();
2786 /* XXX need to consider musical time selections here at some point */
2788 double speed = rtv->track()->speed();
2791 for (list<AudioRange>::const_iterator t = ts.begin(); t != ts.end(); ++t) {
2793 sigc::connection c = rtv->view()->RegionViewAdded.connect (
2794 sigc::mem_fun(*this, &Editor::collect_new_region_view));
2796 latest_regionviews.clear ();
2798 playlist->partition ((framepos_t)((*t).start * speed),
2799 (framepos_t)((*t).end * speed), false);
2803 if (!latest_regionviews.empty()) {
2805 rtv->view()->foreach_regionview (sigc::bind (
2806 sigc::ptr_fun (add_if_covered),
2807 &(*t), &new_selection));
2810 begin_reversible_command (_("separate"));
2814 /* pick up changes to existing regions */
2816 vector<Command*> cmds;
2817 playlist->rdiff (cmds);
2818 _session->add_commands (cmds);
2820 /* pick up changes to the playlist itself (adds/removes)
2823 _session->add_command(new StatefulDiffCommand (playlist));
2832 // selection->set (new_selection);
2834 commit_reversible_command ();
2838 struct PlaylistState {
2839 boost::shared_ptr<Playlist> playlist;
2843 /** Take tracks from get_tracks_for_range_action and cut any regions
2844 * on those tracks so that the tracks are empty over the time
2848 Editor::separate_region_from_selection ()
2850 /* preferentially use *all* ranges in the time selection if we're in range mode
2851 to allow discontiguous operation, since get_edit_op_range() currently
2852 returns a single range.
2855 if (!selection->time.empty()) {
2857 separate_regions_between (selection->time);
2864 if (get_edit_op_range (start, end)) {
2866 AudioRange ar (start, end, 1);
2870 separate_regions_between (ts);
2876 Editor::separate_region_from_punch ()
2878 Location* loc = _session->locations()->auto_punch_location();
2880 separate_regions_using_location (*loc);
2885 Editor::separate_region_from_loop ()
2887 Location* loc = _session->locations()->auto_loop_location();
2889 separate_regions_using_location (*loc);
2894 Editor::separate_regions_using_location (Location& loc)
2896 if (loc.is_mark()) {
2900 AudioRange ar (loc.start(), loc.end(), 1);
2905 separate_regions_between (ts);
2908 /** Separate regions under the selected region */
2910 Editor::separate_under_selected_regions ()
2912 vector<PlaylistState> playlists;
2916 rs = get_regions_from_selection_and_entered();
2918 if (!_session || rs.empty()) {
2922 begin_reversible_command (_("separate region under"));
2924 list<boost::shared_ptr<Region> > regions_to_remove;
2926 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
2927 // we can't just remove the region(s) in this loop because
2928 // this removes them from the RegionSelection, and they thus
2929 // disappear from underneath the iterator, and the ++i above
2930 // SEGVs in a puzzling fashion.
2932 // so, first iterate over the regions to be removed from rs and
2933 // add them to the regions_to_remove list, and then
2934 // iterate over the list to actually remove them.
2936 regions_to_remove.push_back ((*i)->region());
2939 for (list<boost::shared_ptr<Region> >::iterator rl = regions_to_remove.begin(); rl != regions_to_remove.end(); ++rl) {
2941 boost::shared_ptr<Playlist> playlist = (*rl)->playlist();
2944 // is this check necessary?
2948 vector<PlaylistState>::iterator i;
2950 //only take state if this is a new playlist.
2951 for (i = playlists.begin(); i != playlists.end(); ++i) {
2952 if ((*i).playlist == playlist) {
2957 if (i == playlists.end()) {
2959 PlaylistState before;
2960 before.playlist = playlist;
2961 before.before = &playlist->get_state();
2963 playlist->freeze ();
2964 playlists.push_back(before);
2967 //Partition on the region bounds
2968 playlist->partition ((*rl)->first_frame() - 1, (*rl)->last_frame() + 1, true);
2970 //Re-add region that was just removed due to the partition operation
2971 playlist->add_region( (*rl), (*rl)->first_frame() );
2974 vector<PlaylistState>::iterator pl;
2976 for (pl = playlists.begin(); pl != playlists.end(); ++pl) {
2977 (*pl).playlist->thaw ();
2978 _session->add_command(new MementoCommand<Playlist>(*(*pl).playlist, (*pl).before, &(*pl).playlist->get_state()));
2981 commit_reversible_command ();
2985 Editor::crop_region_to_selection ()
2987 if (!selection->time.empty()) {
2989 crop_region_to (selection->time.start(), selection->time.end_frame());
2996 if (get_edit_op_range (start, end)) {
2997 crop_region_to (start, end);
3004 Editor::crop_region_to (framepos_t start, framepos_t end)
3006 vector<boost::shared_ptr<Playlist> > playlists;
3007 boost::shared_ptr<Playlist> playlist;
3010 if (selection->tracks.empty()) {
3011 ts = track_views.filter_to_unique_playlists();
3013 ts = selection->tracks.filter_to_unique_playlists ();
3016 sort_track_selection (ts);
3018 for (TrackSelection::iterator i = ts.begin(); i != ts.end(); ++i) {
3020 RouteTimeAxisView* rtv;
3022 if ((rtv = dynamic_cast<RouteTimeAxisView*> ((*i))) != 0) {
3024 boost::shared_ptr<Track> t = rtv->track();
3026 if (t != 0 && ! t->destructive()) {
3028 if ((playlist = rtv->playlist()) != 0) {
3029 playlists.push_back (playlist);
3035 if (playlists.empty()) {
3039 framepos_t the_start;
3043 begin_reversible_command (_("trim to selection"));
3045 for (vector<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
3047 boost::shared_ptr<Region> region;
3051 if ((region = (*i)->top_region_at(the_start)) == 0) {
3055 /* now adjust lengths to that we do the right thing
3056 if the selection extends beyond the region
3059 the_start = max (the_start, (framepos_t) region->position());
3060 if (max_framepos - the_start < region->length()) {
3061 the_end = the_start + region->length() - 1;
3063 the_end = max_framepos;
3065 the_end = min (end, the_end);
3066 cnt = the_end - the_start + 1;
3068 region->clear_changes ();
3069 region->trim_to (the_start, cnt);
3070 _session->add_command (new StatefulDiffCommand (region));
3073 commit_reversible_command ();
3077 Editor::region_fill_track ()
3079 RegionSelection rs = get_regions_from_selection_and_entered ();
3081 if (!_session || rs.empty()) {
3085 framepos_t const end = _session->current_end_frame ();
3087 begin_reversible_command (Operations::region_fill);
3089 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3091 boost::shared_ptr<Region> region ((*i)->region());
3093 boost::shared_ptr<Playlist> pl = region->playlist();
3095 if (end <= region->last_frame()) {
3099 double times = (double) (end - region->last_frame()) / (double) region->length();
3105 pl->clear_changes ();
3106 pl->add_region (RegionFactory::create (region, true), region->last_frame(), times);
3107 _session->add_command (new StatefulDiffCommand (pl));
3110 commit_reversible_command ();
3114 Editor::region_fill_selection ()
3116 if (clicked_routeview == 0 || !clicked_routeview->is_audio_track()) {
3120 if (selection->time.empty()) {
3124 boost::shared_ptr<Region> region = _regions->get_single_selection ();
3129 framepos_t start = selection->time[clicked_selection].start;
3130 framepos_t end = selection->time[clicked_selection].end;
3132 boost::shared_ptr<Playlist> playlist;
3134 if (selection->tracks.empty()) {
3138 framepos_t selection_length = end - start;
3139 float times = (float)selection_length / region->length();
3141 begin_reversible_command (Operations::fill_selection);
3143 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
3145 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
3147 if ((playlist = (*i)->playlist()) == 0) {
3151 playlist->clear_changes ();
3152 playlist->add_region (RegionFactory::create (region, true), start, times);
3153 _session->add_command (new StatefulDiffCommand (playlist));
3156 commit_reversible_command ();
3160 Editor::set_region_sync_position ()
3162 set_sync_point (get_preferred_edit_position (), get_regions_from_selection_and_edit_point ());
3166 Editor::set_sync_point (framepos_t where, const RegionSelection& rs)
3168 bool in_command = false;
3170 for (RegionSelection::const_iterator r = rs.begin(); r != rs.end(); ++r) {
3172 if (!(*r)->region()->covers (where)) {
3176 boost::shared_ptr<Region> region ((*r)->region());
3179 begin_reversible_command (_("set sync point"));
3183 region->clear_changes ();
3184 region->set_sync_position (where);
3185 _session->add_command(new StatefulDiffCommand (region));
3189 commit_reversible_command ();
3193 /** Remove the sync positions of the selection */
3195 Editor::remove_region_sync ()
3197 RegionSelection rs = get_regions_from_selection_and_entered ();
3203 begin_reversible_command (_("remove region sync"));
3205 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3207 (*i)->region()->clear_changes ();
3208 (*i)->region()->clear_sync_position ();
3209 _session->add_command(new StatefulDiffCommand ((*i)->region()));
3212 commit_reversible_command ();
3216 Editor::naturalize_region ()
3218 RegionSelection rs = get_regions_from_selection_and_entered ();
3224 if (rs.size() > 1) {
3225 begin_reversible_command (_("move regions to original position"));
3227 begin_reversible_command (_("move region to original position"));
3230 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3231 (*i)->region()->clear_changes ();
3232 (*i)->region()->move_to_natural_position ();
3233 _session->add_command (new StatefulDiffCommand ((*i)->region()));
3236 commit_reversible_command ();
3240 Editor::align_regions (RegionPoint what)
3242 RegionSelection const rs = get_regions_from_selection_and_edit_point ();
3248 begin_reversible_command (_("align selection"));
3250 framepos_t const position = get_preferred_edit_position ();
3252 for (RegionSelection::const_iterator i = rs.begin(); i != rs.end(); ++i) {
3253 align_region_internal ((*i)->region(), what, position);
3256 commit_reversible_command ();
3259 struct RegionSortByTime {
3260 bool operator() (const RegionView* a, const RegionView* b) {
3261 return a->region()->position() < b->region()->position();
3266 Editor::align_regions_relative (RegionPoint point)
3268 RegionSelection const rs = get_regions_from_selection_and_edit_point ();
3274 framepos_t const position = get_preferred_edit_position ();
3276 framepos_t distance = 0;
3280 list<RegionView*> sorted;
3281 rs.by_position (sorted);
3283 boost::shared_ptr<Region> r ((*sorted.begin())->region());
3288 if (position > r->position()) {
3289 distance = position - r->position();
3291 distance = r->position() - position;
3297 if (position > r->last_frame()) {
3298 distance = position - r->last_frame();
3299 pos = r->position() + distance;
3301 distance = r->last_frame() - position;
3302 pos = r->position() - distance;
3308 pos = r->adjust_to_sync (position);
3309 if (pos > r->position()) {
3310 distance = pos - r->position();
3312 distance = r->position() - pos;
3318 if (pos == r->position()) {
3322 begin_reversible_command (_("align selection (relative)"));
3324 /* move first one specially */
3326 r->clear_changes ();
3327 r->set_position (pos);
3328 _session->add_command(new StatefulDiffCommand (r));
3330 /* move rest by the same amount */
3334 for (list<RegionView*>::iterator i = sorted.begin(); i != sorted.end(); ++i) {
3336 boost::shared_ptr<Region> region ((*i)->region());
3338 region->clear_changes ();
3341 region->set_position (region->position() + distance);
3343 region->set_position (region->position() - distance);
3346 _session->add_command(new StatefulDiffCommand (region));
3350 commit_reversible_command ();
3354 Editor::align_region (boost::shared_ptr<Region> region, RegionPoint point, framepos_t position)
3356 begin_reversible_command (_("align region"));
3357 align_region_internal (region, point, position);
3358 commit_reversible_command ();
3362 Editor::align_region_internal (boost::shared_ptr<Region> region, RegionPoint point, framepos_t position)
3364 region->clear_changes ();
3368 region->set_position (region->adjust_to_sync (position));
3372 if (position > region->length()) {
3373 region->set_position (position - region->length());
3378 region->set_position (position);
3382 _session->add_command(new StatefulDiffCommand (region));
3386 Editor::trim_region_front ()
3392 Editor::trim_region_back ()
3394 trim_region (false);
3398 Editor::trim_region (bool front)
3400 framepos_t where = get_preferred_edit_position();
3401 RegionSelection rs = get_regions_from_selection_and_edit_point ();
3407 begin_reversible_command (front ? _("trim front") : _("trim back"));
3409 for (list<RegionView*>::const_iterator i = rs.by_layer().begin(); i != rs.by_layer().end(); ++i) {
3410 if (!(*i)->region()->locked()) {
3412 (*i)->region()->clear_changes ();
3415 (*i)->region()->trim_front (where);
3416 maybe_locate_with_edit_preroll ( where );
3418 (*i)->region()->trim_end (where);
3419 maybe_locate_with_edit_preroll ( where );
3422 _session->add_command (new StatefulDiffCommand ((*i)->region()));
3426 commit_reversible_command ();
3429 /** Trim the end of the selected regions to the position of the edit cursor */
3431 Editor::trim_region_to_loop ()
3433 Location* loc = _session->locations()->auto_loop_location();
3437 trim_region_to_location (*loc, _("trim to loop"));
3441 Editor::trim_region_to_punch ()
3443 Location* loc = _session->locations()->auto_punch_location();
3447 trim_region_to_location (*loc, _("trim to punch"));
3451 Editor::trim_region_to_location (const Location& loc, const char* str)
3453 RegionSelection rs = get_regions_from_selection_and_entered ();
3455 begin_reversible_command (str);
3457 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
3458 RegionView* rv = (*x);
3460 /* require region to span proposed trim */
3461 switch (rv->region()->coverage (loc.start(), loc.end())) {
3462 case Evoral::OverlapInternal:
3468 RouteTimeAxisView* tav = dynamic_cast<RouteTimeAxisView*> (&rv->get_time_axis_view());
3477 if (tav->track() != 0) {
3478 speed = tav->track()->speed();
3481 start = session_frame_to_track_frame (loc.start(), speed);
3482 end = session_frame_to_track_frame (loc.end(), speed);
3484 rv->region()->clear_changes ();
3485 rv->region()->trim_to (start, (end - start));
3486 _session->add_command(new StatefulDiffCommand (rv->region()));
3489 commit_reversible_command ();
3493 Editor::trim_region_to_previous_region_end ()
3495 return trim_to_region(false);
3499 Editor::trim_region_to_next_region_start ()
3501 return trim_to_region(true);
3505 Editor::trim_to_region(bool forward)
3507 RegionSelection rs = get_regions_from_selection_and_entered ();
3509 begin_reversible_command (_("trim to region"));
3511 boost::shared_ptr<Region> next_region;
3513 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
3515 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*x);
3521 AudioTimeAxisView* atav = dynamic_cast<AudioTimeAxisView*> (&arv->get_time_axis_view());
3529 if (atav->track() != 0) {
3530 speed = atav->track()->speed();
3534 boost::shared_ptr<Region> region = arv->region();
3535 boost::shared_ptr<Playlist> playlist (region->playlist());
3537 region->clear_changes ();
3541 next_region = playlist->find_next_region (region->first_frame(), Start, 1);
3547 region->trim_end((framepos_t) ( (next_region->first_frame() - 1) * speed));
3548 arv->region_changed (PropertyChange (ARDOUR::Properties::length));
3552 next_region = playlist->find_next_region (region->first_frame(), Start, 0);
3558 region->trim_front((framepos_t) ((next_region->last_frame() + 1) * speed));
3560 arv->region_changed (ARDOUR::bounds_change);
3563 _session->add_command(new StatefulDiffCommand (region));
3566 commit_reversible_command ();
3570 Editor::unfreeze_route ()
3572 if (clicked_routeview == 0 || !clicked_routeview->is_track()) {
3576 clicked_routeview->track()->unfreeze ();
3580 Editor::_freeze_thread (void* arg)
3582 return static_cast<Editor*>(arg)->freeze_thread ();
3586 Editor::freeze_thread ()
3588 /* create event pool because we may need to talk to the session */
3589 SessionEvent::create_per_thread_pool ("freeze events", 64);
3590 /* create per-thread buffers for process() tree to use */
3591 clicked_routeview->audio_track()->freeze_me (*current_interthread_info);
3592 current_interthread_info->done = true;
3597 Editor::freeze_route ()
3603 /* stop transport before we start. this is important */
3605 _session->request_transport_speed (0.0);
3607 /* wait for just a little while, because the above call is asynchronous */
3609 Glib::usleep (250000);
3611 if (clicked_routeview == 0 || !clicked_routeview->is_audio_track()) {
3615 if (!clicked_routeview->track()->bounceable (clicked_routeview->track()->main_outs(), true)) {
3617 _("This track/bus cannot be frozen because the signal adds or loses channels before reaching the outputs.\n"
3618 "This is typically caused by plugins that generate stereo output from mono input or vice versa.")
3620 d.set_title (_("Cannot freeze"));
3625 if (clicked_routeview->track()->has_external_redirects()) {
3626 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"
3627 "Freezing will only process the signal as far as the first send/insert/return."),
3628 clicked_routeview->track()->name()), true, MESSAGE_INFO, BUTTONS_NONE, true);
3630 d.add_button (_("Freeze anyway"), Gtk::RESPONSE_OK);
3631 d.add_button (_("Don't freeze"), Gtk::RESPONSE_CANCEL);
3632 d.set_title (_("Freeze Limits"));
3634 int response = d.run ();
3637 case Gtk::RESPONSE_CANCEL:
3644 InterThreadInfo itt;
3645 current_interthread_info = &itt;
3647 InterthreadProgressWindow ipw (current_interthread_info, _("Freeze"), _("Cancel Freeze"));
3649 pthread_create_and_store (X_("freezer"), &itt.thread, _freeze_thread, this);
3651 set_canvas_cursor (_cursors->wait);
3653 while (!itt.done && !itt.cancel) {
3654 gtk_main_iteration ();
3657 current_interthread_info = 0;
3658 set_canvas_cursor (current_canvas_cursor);
3662 Editor::bounce_range_selection (bool replace, bool enable_processing)
3664 if (selection->time.empty()) {
3668 TrackSelection views = selection->tracks;
3670 for (TrackViewList::iterator i = views.begin(); i != views.end(); ++i) {
3672 if (enable_processing) {
3674 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*i);
3676 if (rtv && rtv->track() && replace && enable_processing && !rtv->track()->bounceable (rtv->track()->main_outs(), false)) {
3678 _("You can't perform this operation because the processing of the signal "
3679 "will cause one or more of the tracks to end up with a region with more channels than this track has inputs.\n\n"
3680 "You can do this without processing, which is a different operation.")
3682 d.set_title (_("Cannot bounce"));
3689 framepos_t start = selection->time[clicked_selection].start;
3690 framepos_t end = selection->time[clicked_selection].end;
3691 framepos_t cnt = end - start + 1;
3693 begin_reversible_command (_("bounce range"));
3695 for (TrackViewList::iterator i = views.begin(); i != views.end(); ++i) {
3697 RouteTimeAxisView* rtv;
3699 if ((rtv = dynamic_cast<RouteTimeAxisView*> (*i)) == 0) {
3703 boost::shared_ptr<Playlist> playlist;
3705 if ((playlist = rtv->playlist()) == 0) {
3709 InterThreadInfo itt;
3711 playlist->clear_changes ();
3712 playlist->clear_owned_changes ();
3714 boost::shared_ptr<Region> r;
3716 if (enable_processing) {
3717 r = rtv->track()->bounce_range (start, start+cnt, itt, rtv->track()->main_outs(), false);
3719 r = rtv->track()->bounce_range (start, start+cnt, itt, boost::shared_ptr<Processor>(), false);
3727 list<AudioRange> ranges;
3728 ranges.push_back (AudioRange (start, start+cnt, 0));
3729 playlist->cut (ranges); // discard result
3730 playlist->add_region (r, start);
3733 vector<Command*> cmds;
3734 playlist->rdiff (cmds);
3735 _session->add_commands (cmds);
3737 _session->add_command (new StatefulDiffCommand (playlist));
3740 commit_reversible_command ();
3743 /** Delete selected regions, automation points or a time range */
3747 //special case: if the user is pointing in the editor/mixer strip, they may be trying to delete a plugin.
3748 //we need this because the editor-mixer strip is in the editor window, so it doesn't get the bindings from the mix window
3749 bool deleted = false;
3750 if ( current_mixer_strip && current_mixer_strip == MixerStrip::entered_mixer_strip() )
3751 deleted = current_mixer_strip->delete_processors ();
3757 /** Cut selected regions, automation points or a time range */
3764 /** Copy selected regions, automation points or a time range */
3772 /** @return true if a Cut, Copy or Clear is possible */
3774 Editor::can_cut_copy () const
3776 if (!selection->time.empty() || !selection->regions.empty() || !selection->points.empty())
3783 /** Cut, copy or clear selected regions, automation points or a time range.
3784 * @param op Operation (Delete, Cut, Copy or Clear)
3787 Editor::cut_copy (CutCopyOp op)
3789 /* only cancel selection if cut/copy is successful.*/
3795 opname = _("delete");
3804 opname = _("clear");
3808 /* if we're deleting something, and the mouse is still pressed,
3809 the thing we started a drag for will be gone when we release
3810 the mouse button(s). avoid this. see part 2 at the end of
3814 if (op == Delete || op == Cut || op == Clear) {
3815 if (_drags->active ()) {
3820 if ( op != Delete ) //"Delete" doesn't change copy/paste buf
3821 cut_buffer->clear ();
3823 if (entered_marker) {
3825 /* cut/delete op while pointing at a marker */
3828 Location* loc = find_location_from_marker (entered_marker, ignored);
3830 if (_session && loc) {
3831 Glib::signal_idle().connect (sigc::bind (sigc::mem_fun(*this, &Editor::really_remove_marker), loc));
3838 if (internal_editing()) {
3840 switch (effective_mouse_mode()) {
3843 begin_reversible_command (opname + ' ' + X_("MIDI"));
3845 commit_reversible_command ();
3854 bool did_edit = false;
3856 if (!selection->points.empty()) {
3857 begin_reversible_command (opname + _(" points"));
3859 cut_copy_points (op);
3860 if (op == Cut || op == Delete) {
3861 selection->clear_points ();
3863 } else if (!selection->regions.empty() || !selection->points.empty()) {
3867 if (selection->regions.empty()) {
3868 thing_name = _("points");
3869 } else if (selection->points.empty()) {
3870 thing_name = _("regions");
3872 thing_name = _("objects");
3875 begin_reversible_command (opname + ' ' + thing_name);
3878 if (!selection->regions.empty()) {
3879 cut_copy_regions (op, selection->regions);
3881 if (op == Cut || op == Delete) {
3882 selection->clear_regions ();
3886 if (!selection->points.empty()) {
3887 cut_copy_points (op);
3889 if (op == Cut || op == Delete) {
3890 selection->clear_points ();
3893 } else if (selection->time.empty()) {
3894 framepos_t start, end;
3895 /* no time selection, see if we can get an edit range
3898 if (get_edit_op_range (start, end)) {
3899 selection->set (start, end);
3901 } else if (!selection->time.empty()) {
3902 begin_reversible_command (opname + _(" range"));
3905 cut_copy_ranges (op);
3907 if (op == Cut || op == Delete) {
3908 selection->clear_time ();
3913 commit_reversible_command ();
3916 if (op == Delete || op == Cut || op == Clear) {
3921 struct AutomationRecord {
3922 AutomationRecord () : state (0) {}
3923 AutomationRecord (XMLNode* s) : state (s) {}
3925 XMLNode* state; ///< state before any operation
3926 boost::shared_ptr<Evoral::ControlList> copy; ///< copied events for the cut buffer
3929 /** Cut, copy or clear selected automation points.
3930 * @param op Operation (Cut, Copy or Clear)
3933 Editor::cut_copy_points (CutCopyOp op)
3935 if (selection->points.empty ()) {
3939 /* XXX: not ideal, as there may be more than one track involved in the point selection */
3940 _last_cut_copy_source_track = &selection->points.front()->line().trackview;
3942 /* Keep a record of the AutomationLists that we end up using in this operation */
3943 typedef std::map<boost::shared_ptr<AutomationList>, AutomationRecord> Lists;
3946 /* Go through all selected points, making an AutomationRecord for each distinct AutomationList */
3947 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
3948 boost::shared_ptr<AutomationList> al = (*i)->line().the_list();
3949 if (lists.find (al) == lists.end ()) {
3950 /* We haven't seen this list yet, so make a record for it. This includes
3951 taking a copy of its current state, in case this is needed for undo later.
3953 lists[al] = AutomationRecord (&al->get_state ());
3957 if (op == Cut || op == Copy) {
3958 /* This operation will involve putting things in the cut buffer, so create an empty
3959 ControlList for each of our source lists to put the cut buffer data in.
3961 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
3962 i->second.copy = i->first->create (i->first->parameter ());
3965 /* Add all selected points to the relevant copy ControlLists */
3966 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
3967 boost::shared_ptr<AutomationList> al = (*i)->line().the_list();
3968 AutomationList::const_iterator j = (*i)->model ();
3969 lists[al].copy->add ((*j)->when, (*j)->value);
3972 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
3973 /* Correct this copy list so that it starts at time 0 */
3974 double const start = i->second.copy->front()->when;
3975 for (AutomationList::iterator j = i->second.copy->begin(); j != i->second.copy->end(); ++j) {
3976 (*j)->when -= start;
3979 /* And add it to the cut buffer */
3980 cut_buffer->add (i->second.copy);
3984 if (op == Delete || op == Cut) {
3985 /* This operation needs to remove things from the main AutomationList, so do that now */
3987 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
3988 i->first->freeze ();
3991 /* Remove each selected point from its AutomationList */
3992 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
3993 boost::shared_ptr<AutomationList> al = (*i)->line().the_list();
3994 al->erase ((*i)->model ());
3997 /* Thaw the lists and add undo records for them */
3998 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
3999 boost::shared_ptr<AutomationList> al = i->first;
4001 _session->add_command (new MementoCommand<AutomationList> (*al.get(), i->second.state, &(al->get_state ())));
4006 /** Cut, copy or clear selected automation points.
4007 * @param op Operation (Cut, Copy or Clear)
4010 Editor::cut_copy_midi (CutCopyOp op)
4012 for (MidiRegionSelection::iterator i = selection->midi_regions.begin(); i != selection->midi_regions.end(); ++i) {
4013 MidiRegionView* mrv = *i;
4014 mrv->cut_copy_clear (op);
4020 struct lt_playlist {
4021 bool operator () (const PlaylistState& a, const PlaylistState& b) {
4022 return a.playlist < b.playlist;
4026 struct PlaylistMapping {
4028 boost::shared_ptr<Playlist> pl;
4030 PlaylistMapping (TimeAxisView* tvp) : tv (tvp) {}
4033 /** Remove `clicked_regionview' */
4035 Editor::remove_clicked_region ()
4037 if (clicked_routeview == 0 || clicked_regionview == 0) {
4041 boost::shared_ptr<Playlist> playlist = clicked_routeview->playlist();
4043 playlist->clear_changes ();
4044 playlist->clear_owned_changes ();
4045 playlist->remove_region (clicked_regionview->region());
4046 if (Config->get_edit_mode() == Ripple)
4047 playlist->ripple (clicked_regionview->region()->position(), -clicked_regionview->region()->length(), boost::shared_ptr<Region>());
4049 /* We might have removed regions, which alters other regions' layering_index,
4050 so we need to do a recursive diff here.
4052 vector<Command*> cmds;
4053 playlist->rdiff (cmds);
4054 _session->add_commands (cmds);
4056 _session->add_command(new StatefulDiffCommand (playlist));
4057 commit_reversible_command ();
4061 /** Remove the selected regions */
4063 Editor::remove_selected_regions ()
4065 RegionSelection rs = get_regions_from_selection_and_entered ();
4067 if (!_session || rs.empty()) {
4071 begin_reversible_command (_("remove region"));
4073 list<boost::shared_ptr<Region> > regions_to_remove;
4075 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
4076 // we can't just remove the region(s) in this loop because
4077 // this removes them from the RegionSelection, and they thus
4078 // disappear from underneath the iterator, and the ++i above
4079 // SEGVs in a puzzling fashion.
4081 // so, first iterate over the regions to be removed from rs and
4082 // add them to the regions_to_remove list, and then
4083 // iterate over the list to actually remove them.
4085 regions_to_remove.push_back ((*i)->region());
4088 vector<boost::shared_ptr<Playlist> > playlists;
4090 for (list<boost::shared_ptr<Region> >::iterator rl = regions_to_remove.begin(); rl != regions_to_remove.end(); ++rl) {
4092 boost::shared_ptr<Playlist> playlist = (*rl)->playlist();
4095 // is this check necessary?
4099 /* get_regions_from_selection_and_entered() guarantees that
4100 the playlists involved are unique, so there is no need
4104 playlists.push_back (playlist);
4106 playlist->clear_changes ();
4107 playlist->clear_owned_changes ();
4108 playlist->freeze ();
4109 playlist->remove_region (*rl);
4110 if (Config->get_edit_mode() == Ripple)
4111 playlist->ripple ((*rl)->position(), -(*rl)->length(), boost::shared_ptr<Region>());
4115 vector<boost::shared_ptr<Playlist> >::iterator pl;
4117 for (pl = playlists.begin(); pl != playlists.end(); ++pl) {
4120 /* We might have removed regions, which alters other regions' layering_index,
4121 so we need to do a recursive diff here.
4123 vector<Command*> cmds;
4124 (*pl)->rdiff (cmds);
4125 _session->add_commands (cmds);
4127 _session->add_command(new StatefulDiffCommand (*pl));
4130 commit_reversible_command ();
4133 /** Cut, copy or clear selected regions.
4134 * @param op Operation (Cut, Copy or Clear)
4137 Editor::cut_copy_regions (CutCopyOp op, RegionSelection& rs)
4139 /* we can't use a std::map here because the ordering is important, and we can't trivially sort
4140 a map when we want ordered access to both elements. i think.
4143 vector<PlaylistMapping> pmap;
4145 framepos_t first_position = max_framepos;
4147 typedef set<boost::shared_ptr<Playlist> > FreezeList;
4148 FreezeList freezelist;
4150 /* get ordering correct before we cut/copy */
4152 rs.sort_by_position_and_track ();
4154 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
4156 first_position = min ((framepos_t) (*x)->region()->position(), first_position);
4158 if (op == Cut || op == Clear || op == Delete) {
4159 boost::shared_ptr<Playlist> pl = (*x)->region()->playlist();
4162 FreezeList::iterator fl;
4164 // only take state if this is a new playlist.
4165 for (fl = freezelist.begin(); fl != freezelist.end(); ++fl) {
4171 if (fl == freezelist.end()) {
4172 pl->clear_changes();
4173 pl->clear_owned_changes ();
4175 freezelist.insert (pl);
4180 TimeAxisView* tv = &(*x)->get_time_axis_view();
4181 vector<PlaylistMapping>::iterator z;
4183 for (z = pmap.begin(); z != pmap.end(); ++z) {
4184 if ((*z).tv == tv) {
4189 if (z == pmap.end()) {
4190 pmap.push_back (PlaylistMapping (tv));
4194 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ) {
4196 boost::shared_ptr<Playlist> pl = (*x)->region()->playlist();
4199 /* region not yet associated with a playlist (e.g. unfinished
4206 TimeAxisView& tv = (*x)->get_time_axis_view();
4207 boost::shared_ptr<Playlist> npl;
4208 RegionSelection::iterator tmp;
4215 vector<PlaylistMapping>::iterator z;
4217 for (z = pmap.begin(); z != pmap.end(); ++z) {
4218 if ((*z).tv == &tv) {
4223 assert (z != pmap.end());
4226 npl = PlaylistFactory::create (pl->data_type(), *_session, "cutlist", true);
4234 boost::shared_ptr<Region> r = (*x)->region();
4235 boost::shared_ptr<Region> _xx;
4241 pl->remove_region (r);
4242 if (Config->get_edit_mode() == Ripple)
4243 pl->ripple (r->position(), -r->length(), boost::shared_ptr<Region>());
4247 _xx = RegionFactory::create (r);
4248 npl->add_region (_xx, r->position() - first_position);
4249 pl->remove_region (r);
4250 if (Config->get_edit_mode() == Ripple)
4251 pl->ripple (r->position(), -r->length(), boost::shared_ptr<Region>());
4255 /* copy region before adding, so we're not putting same object into two different playlists */
4256 npl->add_region (RegionFactory::create (r), r->position() - first_position);
4260 pl->remove_region (r);
4261 if (Config->get_edit_mode() == Ripple)
4262 pl->ripple (r->position(), -r->length(), boost::shared_ptr<Region>());
4271 list<boost::shared_ptr<Playlist> > foo;
4273 /* the pmap is in the same order as the tracks in which selected regions occured */
4275 for (vector<PlaylistMapping>::iterator i = pmap.begin(); i != pmap.end(); ++i) {
4278 foo.push_back ((*i).pl);
4283 cut_buffer->set (foo);
4287 _last_cut_copy_source_track = 0;
4289 _last_cut_copy_source_track = pmap.front().tv;
4293 for (FreezeList::iterator pl = freezelist.begin(); pl != freezelist.end(); ++pl) {
4296 /* We might have removed regions, which alters other regions' layering_index,
4297 so we need to do a recursive diff here.
4299 vector<Command*> cmds;
4300 (*pl)->rdiff (cmds);
4301 _session->add_commands (cmds);
4303 _session->add_command (new StatefulDiffCommand (*pl));
4308 Editor::cut_copy_ranges (CutCopyOp op)
4310 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4312 /* Sort the track selection now, so that it if is used, the playlists
4313 selected by the calls below to cut_copy_clear are in the order that
4314 their tracks appear in the editor. This makes things like paste
4315 of ranges work properly.
4318 sort_track_selection (ts);
4321 if (!entered_track) {
4324 ts.push_back (entered_track);
4327 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4328 (*i)->cut_copy_clear (*selection, op);
4333 Editor::paste (float times, bool from_context)
4335 DEBUG_TRACE (DEBUG::CutNPaste, "paste to preferred edit pos\n");
4337 paste_internal (get_preferred_edit_position (false, from_context), times);
4341 Editor::mouse_paste ()
4346 if (!mouse_frame (where, ignored)) {
4351 paste_internal (where, 1);
4355 Editor::paste_internal (framepos_t position, float times)
4357 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("apparent paste position is %1\n", position));
4359 if (internal_editing()) {
4360 if (cut_buffer->midi_notes.empty()) {
4364 if (cut_buffer->empty()) {
4369 if (position == max_framepos) {
4370 position = get_preferred_edit_position();
4371 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("preferred edit position is %1\n", position));
4375 TrackViewList::iterator i;
4378 /* get everything in the correct order */
4380 if (_edit_point == Editing::EditAtMouse && entered_track) {
4381 /* With the mouse edit point, paste onto the track under the mouse */
4382 ts.push_back (entered_track);
4383 } else if (!selection->tracks.empty()) {
4384 /* Otherwise, if there are some selected tracks, paste to them */
4385 ts = selection->tracks.filter_to_unique_playlists ();
4386 sort_track_selection (ts);
4387 } else if (_last_cut_copy_source_track) {
4388 /* Otherwise paste to the track that the cut/copy came from;
4389 see discussion in mantis #3333.
4391 ts.push_back (_last_cut_copy_source_track);
4394 if (internal_editing ()) {
4396 /* undo/redo is handled by individual tracks/regions */
4398 for (nth = 0, i = ts.begin(); i != ts.end(); ++i, ++nth) {
4401 RegionSelection::iterator r;
4402 MidiNoteSelection::iterator cb;
4404 get_regions_at (rs, position, ts);
4406 for (cb = cut_buffer->midi_notes.begin(), r = rs.begin();
4407 cb != cut_buffer->midi_notes.end() && r != rs.end(); ++r) {
4408 MidiRegionView* mrv = dynamic_cast<MidiRegionView*> (*r);
4410 mrv->paste (position, times, **cb);
4418 /* we do redo (do you do voodoo?) */
4420 begin_reversible_command (Operations::paste);
4422 for (nth = 0, i = ts.begin(); i != ts.end(); ++i, ++nth) {
4423 (*i)->paste (position, times, *cut_buffer, nth);
4426 commit_reversible_command ();
4431 Editor::duplicate_some_regions (RegionSelection& regions, float times)
4433 boost::shared_ptr<Playlist> playlist;
4434 RegionSelection sel = regions; // clear (below) may clear the argument list if its the current region selection
4435 RegionSelection foo;
4437 framepos_t const start_frame = regions.start ();
4438 framepos_t const end_frame = regions.end_frame ();
4440 begin_reversible_command (Operations::duplicate_region);
4442 selection->clear_regions ();
4444 for (RegionSelection::iterator i = sel.begin(); i != sel.end(); ++i) {
4446 boost::shared_ptr<Region> r ((*i)->region());
4448 TimeAxisView& tv = (*i)->get_time_axis_view();
4449 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (&tv);
4450 latest_regionviews.clear ();
4451 sigc::connection c = rtv->view()->RegionViewAdded.connect (sigc::mem_fun(*this, &Editor::collect_new_region_view));
4453 playlist = (*i)->region()->playlist();
4454 playlist->clear_changes ();
4455 playlist->duplicate (r, end_frame + (r->first_frame() - start_frame), times);
4456 _session->add_command(new StatefulDiffCommand (playlist));
4460 foo.insert (foo.end(), latest_regionviews.begin(), latest_regionviews.end());
4463 commit_reversible_command ();
4466 selection->set (foo);
4471 Editor::duplicate_selection (float times)
4473 if (selection->time.empty() || selection->tracks.empty()) {
4477 boost::shared_ptr<Playlist> playlist;
4478 vector<boost::shared_ptr<Region> > new_regions;
4479 vector<boost::shared_ptr<Region> >::iterator ri;
4481 create_region_from_selection (new_regions);
4483 if (new_regions.empty()) {
4487 begin_reversible_command (_("duplicate selection"));
4489 ri = new_regions.begin();
4491 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4493 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4494 if ((playlist = (*i)->playlist()) == 0) {
4497 playlist->clear_changes ();
4498 playlist->duplicate (*ri, selection->time[clicked_selection].end, times);
4499 _session->add_command (new StatefulDiffCommand (playlist));
4502 if (ri == new_regions.end()) {
4507 commit_reversible_command ();
4510 /** Reset all selected points to the relevant default value */
4512 Editor::reset_point_selection ()
4514 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
4515 ARDOUR::AutomationList::iterator j = (*i)->model ();
4516 (*j)->value = (*i)->line().the_list()->default_value ();
4521 Editor::center_playhead ()
4523 float const page = _visible_canvas_width * samples_per_pixel;
4524 center_screen_internal (playhead_cursor->current_frame (), page);
4528 Editor::center_edit_point ()
4530 float const page = _visible_canvas_width * samples_per_pixel;
4531 center_screen_internal (get_preferred_edit_position(), page);
4534 /** Caller must begin and commit a reversible command */
4536 Editor::clear_playlist (boost::shared_ptr<Playlist> playlist)
4538 playlist->clear_changes ();
4540 _session->add_command (new StatefulDiffCommand (playlist));
4544 Editor::nudge_track (bool use_edit, bool forwards)
4546 boost::shared_ptr<Playlist> playlist;
4547 framepos_t distance;
4548 framepos_t next_distance;
4552 start = get_preferred_edit_position();
4557 if ((distance = get_nudge_distance (start, next_distance)) == 0) {
4561 if (selection->tracks.empty()) {
4565 begin_reversible_command (_("nudge track"));
4567 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4569 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4571 if ((playlist = (*i)->playlist()) == 0) {
4575 playlist->clear_changes ();
4576 playlist->clear_owned_changes ();
4578 playlist->nudge_after (start, distance, forwards);
4580 vector<Command*> cmds;
4582 playlist->rdiff (cmds);
4583 _session->add_commands (cmds);
4585 _session->add_command (new StatefulDiffCommand (playlist));
4588 commit_reversible_command ();
4592 Editor::remove_last_capture ()
4594 vector<string> choices;
4601 if (Config->get_verify_remove_last_capture()) {
4602 prompt = _("Do you really want to destroy the last capture?"
4603 "\n(This is destructive and cannot be undone)");
4605 choices.push_back (_("No, do nothing."));
4606 choices.push_back (_("Yes, destroy it."));
4608 Gtkmm2ext::Choice prompter (_("Destroy last capture"), prompt, choices);
4610 if (prompter.run () == 1) {
4611 _session->remove_last_capture ();
4612 _regions->redisplay ();
4616 _session->remove_last_capture();
4617 _regions->redisplay ();
4622 Editor::normalize_region ()
4628 RegionSelection rs = get_regions_from_selection_and_entered ();
4634 NormalizeDialog dialog (rs.size() > 1);
4636 if (dialog.run () == RESPONSE_CANCEL) {
4640 set_canvas_cursor (_cursors->wait);
4643 /* XXX: should really only count audio regions here */
4644 int const regions = rs.size ();
4646 /* Make a list of the selected audio regions' maximum amplitudes, and also
4647 obtain the maximum amplitude of them all.
4649 list<double> max_amps;
4651 for (RegionSelection::const_iterator i = rs.begin(); i != rs.end(); ++i) {
4652 AudioRegionView const * arv = dynamic_cast<AudioRegionView const *> (*i);
4654 dialog.descend (1.0 / regions);
4655 double const a = arv->audio_region()->maximum_amplitude (&dialog);
4658 /* the user cancelled the operation */
4659 set_canvas_cursor (current_canvas_cursor);
4663 max_amps.push_back (a);
4664 max_amp = max (max_amp, a);
4669 begin_reversible_command (_("normalize"));
4671 list<double>::const_iterator a = max_amps.begin ();
4673 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
4674 AudioRegionView* const arv = dynamic_cast<AudioRegionView*> (*r);
4679 arv->region()->clear_changes ();
4681 double const amp = dialog.normalize_individually() ? *a : max_amp;
4683 arv->audio_region()->normalize (amp, dialog.target ());
4684 _session->add_command (new StatefulDiffCommand (arv->region()));
4689 commit_reversible_command ();
4690 set_canvas_cursor (current_canvas_cursor);
4695 Editor::reset_region_scale_amplitude ()
4701 RegionSelection rs = get_regions_from_selection_and_entered ();
4707 begin_reversible_command ("reset gain");
4709 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
4710 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
4713 arv->region()->clear_changes ();
4714 arv->audio_region()->set_scale_amplitude (1.0f);
4715 _session->add_command (new StatefulDiffCommand (arv->region()));
4718 commit_reversible_command ();
4722 Editor::adjust_region_gain (bool up)
4724 RegionSelection rs = get_regions_from_selection_and_entered ();
4726 if (!_session || rs.empty()) {
4730 begin_reversible_command ("adjust region gain");
4732 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
4733 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
4738 arv->region()->clear_changes ();
4740 double dB = accurate_coefficient_to_dB (arv->audio_region()->scale_amplitude ());
4748 arv->audio_region()->set_scale_amplitude (dB_to_coefficient (dB));
4749 _session->add_command (new StatefulDiffCommand (arv->region()));
4752 commit_reversible_command ();
4757 Editor::reverse_region ()
4763 Reverse rev (*_session);
4764 apply_filter (rev, _("reverse regions"));
4768 Editor::strip_region_silence ()
4774 RegionSelection rs = get_regions_from_selection_and_entered ();
4780 std::list<RegionView*> audio_only;
4782 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
4783 AudioRegionView* const arv = dynamic_cast<AudioRegionView*> (*i);
4785 audio_only.push_back (arv);
4789 StripSilenceDialog d (_session, audio_only);
4790 int const r = d.run ();
4794 if (r == Gtk::RESPONSE_OK) {
4795 ARDOUR::AudioIntervalMap silences;
4796 d.silences (silences);
4797 StripSilence s (*_session, silences, d.fade_length());
4798 apply_filter (s, _("strip silence"), &d);
4803 Editor::apply_midi_note_edit_op_to_region (MidiOperator& op, MidiRegionView& mrv)
4805 Evoral::Sequence<Evoral::MusicalTime>::Notes selected;
4806 mrv.selection_as_notelist (selected, true);
4808 vector<Evoral::Sequence<Evoral::MusicalTime>::Notes> v;
4809 v.push_back (selected);
4811 framepos_t pos_frames = mrv.midi_region()->position() - mrv.midi_region()->start();
4812 double pos_beats = _session->tempo_map().framewalk_to_beats(0, pos_frames);
4814 return op (mrv.midi_region()->model(), pos_beats, v);
4818 Editor::apply_midi_note_edit_op (MidiOperator& op)
4822 RegionSelection rs = get_regions_from_selection_and_entered ();
4828 begin_reversible_command (op.name ());
4830 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
4831 RegionSelection::iterator tmp = r;
4834 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*r);
4837 cmd = apply_midi_note_edit_op_to_region (op, *mrv);
4840 _session->add_command (cmd);
4847 commit_reversible_command ();
4851 Editor::fork_region ()
4853 RegionSelection rs = get_regions_from_selection_and_entered ();
4859 begin_reversible_command (_("Fork Region(s)"));
4861 set_canvas_cursor (_cursors->wait);
4864 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
4865 RegionSelection::iterator tmp = r;
4868 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*>(*r);
4872 boost::shared_ptr<Playlist> playlist = mrv->region()->playlist();
4873 boost::shared_ptr<MidiSource> new_source = _session->create_midi_source_by_stealing_name (mrv->midi_view()->track());
4874 boost::shared_ptr<MidiRegion> newregion = mrv->midi_region()->clone (new_source);
4876 playlist->clear_changes ();
4877 playlist->replace_region (mrv->region(), newregion, mrv->region()->position());
4878 _session->add_command(new StatefulDiffCommand (playlist));
4880 error << string_compose (_("Could not unlink %1"), mrv->region()->name()) << endmsg;
4887 commit_reversible_command ();
4889 set_canvas_cursor (current_canvas_cursor);
4893 Editor::quantize_region ()
4895 int selected_midi_region_cnt = 0;
4901 RegionSelection rs = get_regions_from_selection_and_entered ();
4907 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
4908 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*r);
4910 selected_midi_region_cnt++;
4914 if (selected_midi_region_cnt == 0) {
4918 QuantizeDialog* qd = new QuantizeDialog (*this);
4921 const int r = qd->run ();
4924 if (r == Gtk::RESPONSE_OK) {
4925 Quantize quant (*_session, qd->snap_start(), qd->snap_end(),
4926 qd->start_grid_size(), qd->end_grid_size(),
4927 qd->strength(), qd->swing(), qd->threshold());
4929 apply_midi_note_edit_op (quant);
4934 Editor::insert_patch_change (bool from_context)
4936 RegionSelection rs = get_regions_from_selection_and_entered ();
4942 const framepos_t p = get_preferred_edit_position (false, from_context);
4944 /* XXX: bit of a hack; use the MIDNAM from the first selected region;
4945 there may be more than one, but the PatchChangeDialog can only offer
4946 one set of patch menus.
4948 MidiRegionView* first = dynamic_cast<MidiRegionView*> (rs.front ());
4950 Evoral::PatchChange<Evoral::MusicalTime> empty (0, 0, 0, 0);
4951 PatchChangeDialog d (0, _session, empty, first->instrument_info(), Gtk::Stock::ADD);
4953 if (d.run() == RESPONSE_CANCEL) {
4957 for (RegionSelection::iterator i = rs.begin (); i != rs.end(); ++i) {
4958 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*i);
4960 if (p >= mrv->region()->first_frame() && p <= mrv->region()->last_frame()) {
4961 mrv->add_patch_change (p - mrv->region()->position(), d.patch ());
4968 Editor::apply_filter (Filter& filter, string command, ProgressReporter* progress)
4970 RegionSelection rs = get_regions_from_selection_and_entered ();
4976 begin_reversible_command (command);
4978 set_canvas_cursor (_cursors->wait);
4982 int const N = rs.size ();
4984 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
4985 RegionSelection::iterator tmp = r;
4988 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
4990 boost::shared_ptr<Playlist> playlist = arv->region()->playlist();
4993 progress->descend (1.0 / N);
4996 if (arv->audio_region()->apply (filter, progress) == 0) {
4998 playlist->clear_changes ();
4999 playlist->clear_owned_changes ();
5001 if (filter.results.empty ()) {
5003 /* no regions returned; remove the old one */
5004 playlist->remove_region (arv->region ());
5008 std::vector<boost::shared_ptr<Region> >::iterator res = filter.results.begin ();
5010 /* first region replaces the old one */
5011 playlist->replace_region (arv->region(), *res, (*res)->position());
5015 while (res != filter.results.end()) {
5016 playlist->add_region (*res, (*res)->position());
5022 /* We might have removed regions, which alters other regions' layering_index,
5023 so we need to do a recursive diff here.
5025 vector<Command*> cmds;
5026 playlist->rdiff (cmds);
5027 _session->add_commands (cmds);
5029 _session->add_command(new StatefulDiffCommand (playlist));
5035 progress->ascend ();
5043 commit_reversible_command ();
5046 set_canvas_cursor (current_canvas_cursor);
5050 Editor::external_edit_region ()
5056 Editor::reset_region_gain_envelopes ()
5058 RegionSelection rs = get_regions_from_selection_and_entered ();
5060 if (!_session || rs.empty()) {
5064 _session->begin_reversible_command (_("reset region gain"));
5066 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5067 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
5069 boost::shared_ptr<AutomationList> alist (arv->audio_region()->envelope());
5070 XMLNode& before (alist->get_state());
5072 arv->audio_region()->set_default_envelope ();
5073 _session->add_command (new MementoCommand<AutomationList>(*arv->audio_region()->envelope().get(), &before, &alist->get_state()));
5077 _session->commit_reversible_command ();
5081 Editor::set_region_gain_visibility (RegionView* rv)
5083 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (rv);
5085 arv->update_envelope_visibility();
5090 Editor::set_gain_envelope_visibility ()
5096 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5097 AudioTimeAxisView* v = dynamic_cast<AudioTimeAxisView*>(*i);
5099 v->audio_view()->foreach_regionview (sigc::mem_fun (this, &Editor::set_region_gain_visibility));
5105 Editor::toggle_gain_envelope_active ()
5107 if (_ignore_region_action) {
5111 RegionSelection rs = get_regions_from_selection_and_entered ();
5113 if (!_session || rs.empty()) {
5117 _session->begin_reversible_command (_("region gain envelope active"));
5119 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5120 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
5122 arv->region()->clear_changes ();
5123 arv->audio_region()->set_envelope_active (!arv->audio_region()->envelope_active());
5124 _session->add_command (new StatefulDiffCommand (arv->region()));
5128 _session->commit_reversible_command ();
5132 Editor::toggle_region_lock ()
5134 if (_ignore_region_action) {
5138 RegionSelection rs = get_regions_from_selection_and_entered ();
5140 if (!_session || rs.empty()) {
5144 _session->begin_reversible_command (_("toggle region lock"));
5146 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5147 (*i)->region()->clear_changes ();
5148 (*i)->region()->set_locked (!(*i)->region()->locked());
5149 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5152 _session->commit_reversible_command ();
5156 Editor::toggle_region_video_lock ()
5158 if (_ignore_region_action) {
5162 RegionSelection rs = get_regions_from_selection_and_entered ();
5164 if (!_session || rs.empty()) {
5168 _session->begin_reversible_command (_("Toggle Video Lock"));
5170 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5171 (*i)->region()->clear_changes ();
5172 (*i)->region()->set_video_locked (!(*i)->region()->video_locked());
5173 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5176 _session->commit_reversible_command ();
5180 Editor::toggle_region_lock_style ()
5182 if (_ignore_region_action) {
5186 RegionSelection rs = get_regions_from_selection_and_entered ();
5188 if (!_session || rs.empty()) {
5192 _session->begin_reversible_command (_("region lock style"));
5194 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5195 (*i)->region()->clear_changes ();
5196 PositionLockStyle const ns = (*i)->region()->position_lock_style() == AudioTime ? MusicTime : AudioTime;
5197 (*i)->region()->set_position_lock_style (ns);
5198 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5201 _session->commit_reversible_command ();
5205 Editor::toggle_opaque_region ()
5207 if (_ignore_region_action) {
5211 RegionSelection rs = get_regions_from_selection_and_entered ();
5213 if (!_session || rs.empty()) {
5217 _session->begin_reversible_command (_("change region opacity"));
5219 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5220 (*i)->region()->clear_changes ();
5221 (*i)->region()->set_opaque (!(*i)->region()->opaque());
5222 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5225 _session->commit_reversible_command ();
5229 Editor::toggle_record_enable ()
5231 bool new_state = false;
5233 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5234 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5237 if (!rtav->is_track())
5241 new_state = !rtav->track()->record_enabled();
5245 rtav->track()->set_record_enabled (new_state, this);
5250 Editor::toggle_solo ()
5252 bool new_state = false;
5254 boost::shared_ptr<RouteList> rl (new RouteList);
5256 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5257 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5264 new_state = !rtav->route()->soloed ();
5268 rl->push_back (rtav->route());
5271 _session->set_solo (rl, new_state, Session::rt_cleanup, true);
5275 Editor::toggle_mute ()
5277 bool new_state = false;
5279 boost::shared_ptr<RouteList> rl (new RouteList);
5281 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5282 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5289 new_state = !rtav->route()->muted();
5293 rl->push_back (rtav->route());
5296 _session->set_mute (rl, new_state, Session::rt_cleanup, true);
5300 Editor::toggle_solo_isolate ()
5306 Editor::fade_range ()
5308 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
5310 begin_reversible_command (_("fade range"));
5312 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
5313 (*i)->fade_range (selection->time);
5316 commit_reversible_command ();
5321 Editor::set_fade_length (bool in)
5323 RegionSelection rs = get_regions_from_selection_and_entered ();
5329 /* we need a region to measure the offset from the start */
5331 RegionView* rv = rs.front ();
5333 framepos_t pos = get_preferred_edit_position();
5337 if (pos > rv->region()->last_frame() || pos < rv->region()->first_frame()) {
5338 /* edit point is outside the relevant region */
5343 if (pos <= rv->region()->position()) {
5347 len = pos - rv->region()->position();
5348 cmd = _("set fade in length");
5350 if (pos >= rv->region()->last_frame()) {
5354 len = rv->region()->last_frame() - pos;
5355 cmd = _("set fade out length");
5358 begin_reversible_command (cmd);
5360 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5361 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5367 boost::shared_ptr<AutomationList> alist;
5369 alist = tmp->audio_region()->fade_in();
5371 alist = tmp->audio_region()->fade_out();
5374 XMLNode &before = alist->get_state();
5377 tmp->audio_region()->set_fade_in_length (len);
5378 tmp->audio_region()->set_fade_in_active (true);
5380 tmp->audio_region()->set_fade_out_length (len);
5381 tmp->audio_region()->set_fade_out_active (true);
5384 XMLNode &after = alist->get_state();
5385 _session->add_command(new MementoCommand<AutomationList>(*alist, &before, &after));
5388 commit_reversible_command ();
5392 Editor::set_fade_in_shape (FadeShape shape)
5394 RegionSelection rs = get_regions_from_selection_and_entered ();
5400 begin_reversible_command (_("set fade in shape"));
5402 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5403 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5409 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_in();
5410 XMLNode &before = alist->get_state();
5412 tmp->audio_region()->set_fade_in_shape (shape);
5414 XMLNode &after = alist->get_state();
5415 _session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
5418 commit_reversible_command ();
5423 Editor::set_fade_out_shape (FadeShape shape)
5425 RegionSelection rs = get_regions_from_selection_and_entered ();
5431 begin_reversible_command (_("set fade out shape"));
5433 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5434 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5440 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_out();
5441 XMLNode &before = alist->get_state();
5443 tmp->audio_region()->set_fade_out_shape (shape);
5445 XMLNode &after = alist->get_state();
5446 _session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
5449 commit_reversible_command ();
5453 Editor::set_fade_in_active (bool yn)
5455 RegionSelection rs = get_regions_from_selection_and_entered ();
5461 begin_reversible_command (_("set fade in active"));
5463 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5464 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5471 boost::shared_ptr<AudioRegion> ar (tmp->audio_region());
5473 ar->clear_changes ();
5474 ar->set_fade_in_active (yn);
5475 _session->add_command (new StatefulDiffCommand (ar));
5478 commit_reversible_command ();
5482 Editor::set_fade_out_active (bool yn)
5484 RegionSelection rs = get_regions_from_selection_and_entered ();
5490 begin_reversible_command (_("set fade out active"));
5492 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5493 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5499 boost::shared_ptr<AudioRegion> ar (tmp->audio_region());
5501 ar->clear_changes ();
5502 ar->set_fade_out_active (yn);
5503 _session->add_command(new StatefulDiffCommand (ar));
5506 commit_reversible_command ();
5510 Editor::toggle_region_fades (int dir)
5512 if (_ignore_region_action) {
5516 boost::shared_ptr<AudioRegion> ar;
5519 RegionSelection rs = get_regions_from_selection_and_entered ();
5525 RegionSelection::iterator i;
5526 for (i = rs.begin(); i != rs.end(); ++i) {
5527 if ((ar = boost::dynamic_pointer_cast<AudioRegion>((*i)->region())) != 0) {
5529 yn = ar->fade_out_active ();
5531 yn = ar->fade_in_active ();
5537 if (i == rs.end()) {
5541 /* XXX should this undo-able? */
5543 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5544 if ((ar = boost::dynamic_pointer_cast<AudioRegion>((*i)->region())) == 0) {
5547 if (dir == 1 || dir == 0) {
5548 ar->set_fade_in_active (!yn);
5551 if (dir == -1 || dir == 0) {
5552 ar->set_fade_out_active (!yn);
5558 /** Update region fade visibility after its configuration has been changed */
5560 Editor::update_region_fade_visibility ()
5562 bool _fade_visibility = _session->config.get_show_region_fades ();
5564 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5565 AudioTimeAxisView* v = dynamic_cast<AudioTimeAxisView*>(*i);
5567 if (_fade_visibility) {
5568 v->audio_view()->show_all_fades ();
5570 v->audio_view()->hide_all_fades ();
5577 Editor::set_edit_point ()
5582 if (!mouse_frame (where, ignored)) {
5588 if (selection->markers.empty()) {
5590 mouse_add_new_marker (where);
5595 Location* loc = find_location_from_marker (selection->markers.front(), ignored);
5598 loc->move_to (where);
5604 Editor::set_playhead_cursor ()
5606 if (entered_marker) {
5607 _session->request_locate (entered_marker->position(), _session->transport_rolling());
5612 if (!mouse_frame (where, ignored)) {
5619 _session->request_locate (where, _session->transport_rolling());
5623 if ( Config->get_follow_edits() )
5624 cancel_time_selection();
5628 Editor::split_region ()
5630 if ( !selection->time.empty()) {
5631 separate_regions_between (selection->time);
5635 RegionSelection rs = get_regions_from_selection_and_edit_point ();
5637 framepos_t where = get_preferred_edit_position ();
5643 split_regions_at (where, rs);
5646 struct EditorOrderRouteSorter {
5647 bool operator() (boost::shared_ptr<Route> a, boost::shared_ptr<Route> b) {
5648 return a->order_key () < b->order_key ();
5653 Editor::select_next_route()
5655 if (selection->tracks.empty()) {
5656 selection->set (track_views.front());
5660 TimeAxisView* current = selection->tracks.front();
5664 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5665 if (*i == current) {
5667 if (i != track_views.end()) {
5670 current = (*(track_views.begin()));
5671 //selection->set (*(track_views.begin()));
5676 rui = dynamic_cast<RouteUI *>(current);
5677 } while ( current->hidden() || (rui != NULL && !rui->route()->active()));
5679 selection->set(current);
5681 ensure_time_axis_view_is_visible (*current, false);
5685 Editor::select_prev_route()
5687 if (selection->tracks.empty()) {
5688 selection->set (track_views.front());
5692 TimeAxisView* current = selection->tracks.front();
5696 for (TrackViewList::reverse_iterator i = track_views.rbegin(); i != track_views.rend(); ++i) {
5697 if (*i == current) {
5699 if (i != track_views.rend()) {
5702 current = *(track_views.rbegin());
5707 rui = dynamic_cast<RouteUI *>(current);
5708 } while ( current->hidden() || (rui != NULL && !rui->route()->active()));
5710 selection->set (current);
5712 ensure_time_axis_view_is_visible (*current, false);
5716 Editor::set_loop_from_selection (bool play)
5718 if (_session == 0 || selection->time.empty()) {
5722 framepos_t start = selection->time[clicked_selection].start;
5723 framepos_t end = selection->time[clicked_selection].end;
5725 set_loop_range (start, end, _("set loop range from selection"));
5728 _session->request_locate (start, true);
5729 _session->request_play_loop (true);
5734 Editor::set_loop_from_edit_range (bool play)
5736 if (_session == 0) {
5743 if (!get_edit_op_range (start, end)) {
5747 set_loop_range (start, end, _("set loop range from edit range"));
5750 _session->request_locate (start, true);
5751 _session->request_play_loop (true);
5756 Editor::set_loop_from_region (bool play)
5758 framepos_t start = max_framepos;
5761 RegionSelection rs = get_regions_from_selection_and_entered ();
5767 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5768 if ((*i)->region()->position() < start) {
5769 start = (*i)->region()->position();
5771 if ((*i)->region()->last_frame() + 1 > end) {
5772 end = (*i)->region()->last_frame() + 1;
5776 set_loop_range (start, end, _("set loop range from region"));
5779 _session->request_locate (start, true);
5780 _session->request_play_loop (true);
5785 Editor::set_punch_from_selection ()
5787 if (_session == 0 || selection->time.empty()) {
5791 framepos_t start = selection->time[clicked_selection].start;
5792 framepos_t end = selection->time[clicked_selection].end;
5794 set_punch_range (start, end, _("set punch range from selection"));
5798 Editor::set_punch_from_edit_range ()
5800 if (_session == 0) {
5807 if (!get_edit_op_range (start, end)) {
5811 set_punch_range (start, end, _("set punch range from edit range"));
5815 Editor::set_punch_from_region ()
5817 framepos_t start = max_framepos;
5820 RegionSelection rs = get_regions_from_selection_and_entered ();
5826 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5827 if ((*i)->region()->position() < start) {
5828 start = (*i)->region()->position();
5830 if ((*i)->region()->last_frame() + 1 > end) {
5831 end = (*i)->region()->last_frame() + 1;
5835 set_punch_range (start, end, _("set punch range from region"));
5839 Editor::pitch_shift_region ()
5841 RegionSelection rs = get_regions_from_selection_and_entered ();
5843 RegionSelection audio_rs;
5844 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5845 if (dynamic_cast<AudioRegionView*> (*i)) {
5846 audio_rs.push_back (*i);
5850 if (audio_rs.empty()) {
5854 pitch_shift (audio_rs, 1.2);
5858 Editor::transpose_region ()
5860 RegionSelection rs = get_regions_from_selection_and_entered ();
5862 list<MidiRegionView*> midi_region_views;
5863 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5864 MidiRegionView* mrv = dynamic_cast<MidiRegionView*> (*i);
5866 midi_region_views.push_back (mrv);
5871 int const r = d.run ();
5872 if (r != RESPONSE_ACCEPT) {
5876 for (list<MidiRegionView*>::iterator i = midi_region_views.begin(); i != midi_region_views.end(); ++i) {
5877 (*i)->midi_region()->transpose (d.semitones ());
5882 Editor::set_tempo_from_region ()
5884 RegionSelection rs = get_regions_from_selection_and_entered ();
5886 if (!_session || rs.empty()) {
5890 RegionView* rv = rs.front();
5892 define_one_bar (rv->region()->position(), rv->region()->last_frame() + 1);
5896 Editor::use_range_as_bar ()
5898 framepos_t start, end;
5899 if (get_edit_op_range (start, end)) {
5900 define_one_bar (start, end);
5905 Editor::define_one_bar (framepos_t start, framepos_t end)
5907 framepos_t length = end - start;
5909 const Meter& m (_session->tempo_map().meter_at (start));
5911 /* length = 1 bar */
5913 /* now we want frames per beat.
5914 we have frames per bar, and beats per bar, so ...
5917 /* XXXX METER MATH */
5919 double frames_per_beat = length / m.divisions_per_bar();
5921 /* beats per minute = */
5923 double beats_per_minute = (_session->frame_rate() * 60.0) / frames_per_beat;
5925 /* now decide whether to:
5927 (a) set global tempo
5928 (b) add a new tempo marker
5932 const TempoSection& t (_session->tempo_map().tempo_section_at (start));
5934 bool do_global = false;
5936 if ((_session->tempo_map().n_tempos() == 1) && (_session->tempo_map().n_meters() == 1)) {
5938 /* only 1 tempo & 1 meter: ask if the user wants to set the tempo
5939 at the start, or create a new marker
5942 vector<string> options;
5943 options.push_back (_("Cancel"));
5944 options.push_back (_("Add new marker"));
5945 options.push_back (_("Set global tempo"));
5948 _("Define one bar"),
5949 _("Do you want to set the global tempo or add a new tempo marker?"),
5953 c.set_default_response (2);
5969 /* more than 1 tempo and/or meter section already, go ahead do the "usual":
5970 if the marker is at the region starter, change it, otherwise add
5975 begin_reversible_command (_("set tempo from region"));
5976 XMLNode& before (_session->tempo_map().get_state());
5979 _session->tempo_map().change_initial_tempo (beats_per_minute, t.note_type());
5980 } else if (t.frame() == start) {
5981 _session->tempo_map().change_existing_tempo_at (start, beats_per_minute, t.note_type());
5983 Timecode::BBT_Time bbt;
5984 _session->tempo_map().bbt_time (start, bbt);
5985 _session->tempo_map().add_tempo (Tempo (beats_per_minute, t.note_type()), bbt);
5988 XMLNode& after (_session->tempo_map().get_state());
5990 _session->add_command (new MementoCommand<TempoMap>(_session->tempo_map(), &before, &after));
5991 commit_reversible_command ();
5995 Editor::split_region_at_transients ()
5997 AnalysisFeatureList positions;
5999 RegionSelection rs = get_regions_from_selection_and_entered ();
6001 if (!_session || rs.empty()) {
6005 _session->begin_reversible_command (_("split regions"));
6007 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ) {
6009 RegionSelection::iterator tmp;
6014 boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion> ((*i)->region());
6016 if (ar && (ar->get_transients (positions) == 0)) {
6017 split_region_at_points ((*i)->region(), positions, true);
6024 _session->commit_reversible_command ();
6029 Editor::split_region_at_points (boost::shared_ptr<Region> r, AnalysisFeatureList& positions, bool can_ferret, bool select_new)
6031 bool use_rhythmic_rodent = false;
6033 boost::shared_ptr<Playlist> pl = r->playlist();
6035 list<boost::shared_ptr<Region> > new_regions;
6041 if (positions.empty()) {
6046 if (positions.size() > 20 && can_ferret) {
6047 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);
6048 MessageDialog msg (msgstr,
6051 Gtk::BUTTONS_OK_CANCEL);
6054 msg.add_button (_("Call for the Ferret!"), RESPONSE_APPLY);
6055 msg.set_secondary_text (_("Press OK to continue with this split operation\nor ask the Ferret dialog to tune the analysis"));
6057 msg.set_secondary_text (_("Press OK to continue with this split operation"));
6060 msg.set_title (_("Excessive split?"));
6063 int response = msg.run();
6069 case RESPONSE_APPLY:
6070 use_rhythmic_rodent = true;
6077 if (use_rhythmic_rodent) {
6078 show_rhythm_ferret ();
6082 AnalysisFeatureList::const_iterator x;
6084 pl->clear_changes ();
6085 pl->clear_owned_changes ();
6087 x = positions.begin();
6089 if (x == positions.end()) {
6094 pl->remove_region (r);
6098 while (x != positions.end()) {
6100 /* deal with positons that are out of scope of present region bounds */
6101 if (*x <= 0 || *x > r->length()) {
6106 /* file start = original start + how far we from the initial position ?
6109 framepos_t file_start = r->start() + pos;
6111 /* length = next position - current position
6114 framepos_t len = (*x) - pos;
6116 /* XXX we do we really want to allow even single-sample regions?
6117 shouldn't we have some kind of lower limit on region size?
6126 if (RegionFactory::region_name (new_name, r->name())) {
6130 /* do NOT announce new regions 1 by one, just wait till they are all done */
6134 plist.add (ARDOUR::Properties::start, file_start);
6135 plist.add (ARDOUR::Properties::length, len);
6136 plist.add (ARDOUR::Properties::name, new_name);
6137 plist.add (ARDOUR::Properties::layer, 0);
6139 boost::shared_ptr<Region> nr = RegionFactory::create (r->sources(), plist, false);
6140 /* because we set annouce to false, manually add the new region to the
6143 RegionFactory::map_add (nr);
6145 pl->add_region (nr, r->position() + pos);
6148 new_regions.push_front(nr);
6157 RegionFactory::region_name (new_name, r->name());
6159 /* Add the final region */
6162 plist.add (ARDOUR::Properties::start, r->start() + pos);
6163 plist.add (ARDOUR::Properties::length, r->last_frame() - (r->position() + pos) + 1);
6164 plist.add (ARDOUR::Properties::name, new_name);
6165 plist.add (ARDOUR::Properties::layer, 0);
6167 boost::shared_ptr<Region> nr = RegionFactory::create (r->sources(), plist, false);
6168 /* because we set annouce to false, manually add the new region to the
6171 RegionFactory::map_add (nr);
6172 pl->add_region (nr, r->position() + pos);
6175 new_regions.push_front(nr);
6180 /* We might have removed regions, which alters other regions' layering_index,
6181 so we need to do a recursive diff here.
6183 vector<Command*> cmds;
6185 _session->add_commands (cmds);
6187 _session->add_command (new StatefulDiffCommand (pl));
6191 for (list<boost::shared_ptr<Region> >::iterator i = new_regions.begin(); i != new_regions.end(); ++i){
6192 set_selected_regionview_from_region_list ((*i), Selection::Add);
6198 Editor::place_transient()
6204 RegionSelection rs = get_regions_from_selection_and_edit_point ();
6210 framepos_t where = get_preferred_edit_position();
6212 _session->begin_reversible_command (_("place transient"));
6214 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6215 framepos_t position = (*r)->region()->position();
6216 (*r)->region()->add_transient(where - position);
6219 _session->commit_reversible_command ();
6223 Editor::remove_transient(ArdourCanvas::Item* item)
6229 ArdourCanvas::Line* _line = reinterpret_cast<ArdourCanvas::Line*> (item);
6232 AudioRegionView* _arv = reinterpret_cast<AudioRegionView*> (item->get_data ("regionview"));
6233 _arv->remove_transient (*(float*) _line->get_data ("position"));
6237 Editor::snap_regions_to_grid ()
6239 list <boost::shared_ptr<Playlist > > used_playlists;
6241 RegionSelection rs = get_regions_from_selection_and_entered ();
6243 if (!_session || rs.empty()) {
6247 _session->begin_reversible_command (_("snap regions to grid"));
6249 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6251 boost::shared_ptr<Playlist> pl = (*r)->region()->playlist();
6253 if (!pl->frozen()) {
6254 /* we haven't seen this playlist before */
6256 /* remember used playlists so we can thaw them later */
6257 used_playlists.push_back(pl);
6261 framepos_t start_frame = (*r)->region()->first_frame ();
6262 snap_to (start_frame);
6263 (*r)->region()->set_position (start_frame);
6266 while (used_playlists.size() > 0) {
6267 list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
6269 used_playlists.pop_front();
6272 _session->commit_reversible_command ();
6276 Editor::close_region_gaps ()
6278 list <boost::shared_ptr<Playlist > > used_playlists;
6280 RegionSelection rs = get_regions_from_selection_and_entered ();
6282 if (!_session || rs.empty()) {
6286 Dialog dialog (_("Close Region Gaps"));
6289 table.set_spacings (12);
6290 table.set_border_width (12);
6291 Label* l = manage (left_aligned_label (_("Crossfade length")));
6292 table.attach (*l, 0, 1, 0, 1);
6294 SpinButton spin_crossfade (1, 0);
6295 spin_crossfade.set_range (0, 15);
6296 spin_crossfade.set_increments (1, 1);
6297 spin_crossfade.set_value (5);
6298 table.attach (spin_crossfade, 1, 2, 0, 1);
6300 table.attach (*manage (new Label (_("ms"))), 2, 3, 0, 1);
6302 l = manage (left_aligned_label (_("Pull-back length")));
6303 table.attach (*l, 0, 1, 1, 2);
6305 SpinButton spin_pullback (1, 0);
6306 spin_pullback.set_range (0, 100);
6307 spin_pullback.set_increments (1, 1);
6308 spin_pullback.set_value(30);
6309 table.attach (spin_pullback, 1, 2, 1, 2);
6311 table.attach (*manage (new Label (_("ms"))), 2, 3, 1, 2);
6313 dialog.get_vbox()->pack_start (table);
6314 dialog.add_button (Stock::CANCEL, RESPONSE_CANCEL);
6315 dialog.add_button (_("Ok"), RESPONSE_ACCEPT);
6318 if (dialog.run () == RESPONSE_CANCEL) {
6322 framepos_t crossfade_len = spin_crossfade.get_value();
6323 framepos_t pull_back_frames = spin_pullback.get_value();
6325 crossfade_len = lrintf (crossfade_len * _session->frame_rate()/1000);
6326 pull_back_frames = lrintf (pull_back_frames * _session->frame_rate()/1000);
6328 /* Iterate over the region list and make adjacent regions overlap by crossfade_len_ms */
6330 _session->begin_reversible_command (_("close region gaps"));
6333 boost::shared_ptr<Region> last_region;
6335 rs.sort_by_position_and_track();
6337 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6339 boost::shared_ptr<Playlist> pl = (*r)->region()->playlist();
6341 if (!pl->frozen()) {
6342 /* we haven't seen this playlist before */
6344 /* remember used playlists so we can thaw them later */
6345 used_playlists.push_back(pl);
6349 framepos_t position = (*r)->region()->position();
6351 if (idx == 0 || position < last_region->position()){
6352 last_region = (*r)->region();
6357 (*r)->region()->trim_front( (position - pull_back_frames));
6358 last_region->trim_end( (position - pull_back_frames + crossfade_len));
6360 last_region = (*r)->region();
6365 while (used_playlists.size() > 0) {
6366 list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
6368 used_playlists.pop_front();
6371 _session->commit_reversible_command ();
6375 Editor::tab_to_transient (bool forward)
6377 AnalysisFeatureList positions;
6379 RegionSelection rs = get_regions_from_selection_and_entered ();
6385 framepos_t pos = _session->audible_frame ();
6387 if (!selection->tracks.empty()) {
6389 /* don't waste time searching for transients in duplicate playlists.
6392 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
6394 for (TrackViewList::iterator t = ts.begin(); t != ts.end(); ++t) {
6396 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*t);
6399 boost::shared_ptr<Track> tr = rtv->track();
6401 boost::shared_ptr<Playlist> pl = tr->playlist ();
6403 framepos_t result = pl->find_next_transient (pos, forward ? 1 : -1);
6406 positions.push_back (result);
6419 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6420 (*r)->region()->get_transients (positions);
6424 TransientDetector::cleanup_transients (positions, _session->frame_rate(), 3.0);
6427 AnalysisFeatureList::iterator x;
6429 for (x = positions.begin(); x != positions.end(); ++x) {
6435 if (x != positions.end ()) {
6436 _session->request_locate (*x);
6440 AnalysisFeatureList::reverse_iterator x;
6442 for (x = positions.rbegin(); x != positions.rend(); ++x) {
6448 if (x != positions.rend ()) {
6449 _session->request_locate (*x);
6455 Editor::playhead_forward_to_grid ()
6461 framepos_t pos = playhead_cursor->current_frame ();
6462 if (pos < max_framepos - 1) {
6464 snap_to_internal (pos, 1, false);
6465 _session->request_locate (pos);
6471 Editor::playhead_backward_to_grid ()
6477 framepos_t pos = playhead_cursor->current_frame ();
6480 snap_to_internal (pos, -1, false);
6481 _session->request_locate (pos);
6486 Editor::set_track_height (Height h)
6488 TrackSelection& ts (selection->tracks);
6490 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
6491 (*x)->set_height_enum (h);
6496 Editor::toggle_tracks_active ()
6498 TrackSelection& ts (selection->tracks);
6500 bool target = false;
6506 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
6507 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*x);
6511 target = !rtv->_route->active();
6514 rtv->_route->set_active (target, this);
6520 Editor::remove_tracks ()
6522 TrackSelection& ts (selection->tracks);
6528 vector<string> choices;
6532 const char* trackstr;
6534 vector<boost::shared_ptr<Route> > routes;
6535 bool special_bus = false;
6537 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
6538 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*x);
6542 if (rtv->is_track()) {
6547 routes.push_back (rtv->_route);
6549 if (rtv->route()->is_master() || rtv->route()->is_monitor()) {
6554 if (special_bus && !Config->get_allow_special_bus_removal()) {
6555 MessageDialog msg (_("That would be bad news ...."),
6559 msg.set_secondary_text (string_compose (_(
6560 "Removing the master or monitor bus is such a bad idea\n\
6561 that %1 is not going to allow it.\n\
6563 If you really want to do this sort of thing\n\
6564 edit your ardour.rc file to set the\n\
6565 \"allow-special-bus-removal\" option to be \"yes\""), PROGRAM_NAME));
6572 if (ntracks + nbusses == 0) {
6577 trackstr = _("tracks");
6579 trackstr = _("track");
6583 busstr = _("busses");
6590 prompt = string_compose (_("Do you really want to remove %1 %2 and %3 %4?\n"
6591 "(You may also lose the playlists associated with the %2)\n\n"
6592 "This action cannot be undone, and the session file will be overwritten!"),
6593 ntracks, trackstr, nbusses, busstr);
6595 prompt = string_compose (_("Do you really want to remove %1 %2?\n"
6596 "(You may also lose the playlists associated with the %2)\n\n"
6597 "This action cannot be undone, and the session file will be overwritten!"),
6600 } else if (nbusses) {
6601 prompt = string_compose (_("Do you really want to remove %1 %2?\n\n"
6602 "This action cannot be undon, and the session file will be overwritten"),
6606 choices.push_back (_("No, do nothing."));
6607 if (ntracks + nbusses > 1) {
6608 choices.push_back (_("Yes, remove them."));
6610 choices.push_back (_("Yes, remove it."));
6615 title = string_compose (_("Remove %1"), trackstr);
6617 title = string_compose (_("Remove %1"), busstr);
6620 Choice prompter (title, prompt, choices);
6622 if (prompter.run () != 1) {
6627 Session::StateProtector sp (_session);
6628 DisplaySuspender ds;
6629 for (vector<boost::shared_ptr<Route> >::iterator x = routes.begin(); x != routes.end(); ++x) {
6630 _session->remove_route (*x);
6636 Editor::do_insert_time ()
6638 if (selection->tracks.empty()) {
6642 InsertTimeDialog d (*this);
6643 int response = d.run ();
6645 if (response != RESPONSE_OK) {
6649 if (d.distance() == 0) {
6653 InsertTimeOption opt = d.intersected_region_action ();
6656 get_preferred_edit_position(),
6662 d.move_glued_markers(),
6663 d.move_locked_markers(),
6669 Editor::insert_time (
6670 framepos_t pos, framecnt_t frames, InsertTimeOption opt,
6671 bool all_playlists, bool ignore_music_glue, bool markers_too, bool glued_markers_too, bool locked_markers_too, bool tempo_too
6674 bool commit = false;
6676 if (Config->get_edit_mode() == Lock) {
6680 begin_reversible_command (_("insert time"));
6682 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
6684 for (TrackViewList::iterator x = ts.begin(); x != ts.end(); ++x) {
6688 /* don't operate on any playlist more than once, which could
6689 * happen if "all playlists" is enabled, but there is more
6690 * than 1 track using playlists "from" a given track.
6693 set<boost::shared_ptr<Playlist> > pl;
6695 if (all_playlists) {
6696 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*x);
6698 vector<boost::shared_ptr<Playlist> > all = _session->playlists->playlists_for_track (rtav->track ());
6699 for (vector<boost::shared_ptr<Playlist> >::iterator p = all.begin(); p != all.end(); ++p) {
6704 if ((*x)->playlist ()) {
6705 pl.insert ((*x)->playlist ());
6709 for (set<boost::shared_ptr<Playlist> >::iterator i = pl.begin(); i != pl.end(); ++i) {
6711 (*i)->clear_changes ();
6712 (*i)->clear_owned_changes ();
6714 if (opt == SplitIntersected) {
6718 (*i)->shift (pos, frames, (opt == MoveIntersected), ignore_music_glue);
6720 vector<Command*> cmds;
6722 _session->add_commands (cmds);
6724 _session->add_command (new StatefulDiffCommand (*i));
6729 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*x);
6731 rtav->route ()->shift (pos, frames);
6739 XMLNode& before (_session->locations()->get_state());
6740 Locations::LocationList copy (_session->locations()->list());
6742 for (Locations::LocationList::iterator i = copy.begin(); i != copy.end(); ++i) {
6744 Locations::LocationList::const_iterator tmp;
6746 bool const was_locked = (*i)->locked ();
6747 if (locked_markers_too) {
6751 if ((*i)->position_lock_style() == AudioTime || glued_markers_too) {
6753 if ((*i)->start() >= pos) {
6754 (*i)->set_start ((*i)->start() + frames);
6755 if (!(*i)->is_mark()) {
6756 (*i)->set_end ((*i)->end() + frames);
6769 XMLNode& after (_session->locations()->get_state());
6770 _session->add_command (new MementoCommand<Locations>(*_session->locations(), &before, &after));
6775 _session->tempo_map().insert_time (pos, frames);
6779 commit_reversible_command ();
6784 Editor::fit_selected_tracks ()
6786 if (!selection->tracks.empty()) {
6787 fit_tracks (selection->tracks);
6791 /* no selected tracks - use tracks with selected regions */
6793 if (!selection->regions.empty()) {
6794 for (RegionSelection::iterator r = selection->regions.begin(); r != selection->regions.end(); ++r) {
6795 tvl.push_back (&(*r)->get_time_axis_view ());
6801 } else if (internal_editing()) {
6802 /* no selected tracks, or regions, but in internal edit mode, so follow the mouse and use
6805 if (entered_track) {
6806 tvl.push_back (entered_track);
6815 Editor::fit_tracks (TrackViewList & tracks)
6817 if (tracks.empty()) {
6821 uint32_t child_heights = 0;
6822 int visible_tracks = 0;
6824 for (TrackSelection::iterator t = tracks.begin(); t != tracks.end(); ++t) {
6826 if (!(*t)->marked_for_display()) {
6830 child_heights += (*t)->effective_height() - (*t)->current_height();
6834 /* compute the per-track height from:
6836 total canvas visible height -
6837 height that will be taken by visible children of selected
6838 tracks - height of the ruler/hscroll area
6840 uint32_t h = (uint32_t) floor ((trackviews_height() - child_heights) / visible_tracks);
6841 double first_y_pos = DBL_MAX;
6843 if (h < TimeAxisView::preset_height (HeightSmall)) {
6844 MessageDialog msg (*this, _("There are too many tracks to fit in the current window"));
6845 /* too small to be displayed */
6849 undo_visual_stack.push_back (current_visual_state (true));
6850 no_save_visual = true;
6852 /* build a list of all tracks, including children */
6855 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
6857 TimeAxisView::Children c = (*i)->get_child_list ();
6858 for (TimeAxisView::Children::iterator j = c.begin(); j != c.end(); ++j) {
6859 all.push_back (j->get());
6863 bool prev_was_selected = false;
6864 bool is_selected = tracks.contains (all.front());
6865 bool next_is_selected;
6867 for (TrackViewList::iterator t = all.begin(); t != all.end(); ++t) {
6869 TrackViewList::iterator next;
6874 if (next != all.end()) {
6875 next_is_selected = tracks.contains (*next);
6877 next_is_selected = false;
6880 if ((*t)->marked_for_display ()) {
6882 (*t)->set_height (h);
6883 first_y_pos = std::min ((*t)->y_position (), first_y_pos);
6885 if (prev_was_selected && next_is_selected) {
6886 hide_track_in_display (*t);
6891 prev_was_selected = is_selected;
6892 is_selected = next_is_selected;
6896 set the controls_layout height now, because waiting for its size
6897 request signal handler will cause the vertical adjustment setting to fail
6900 controls_layout.property_height () = _full_canvas_height;
6901 vertical_adjustment.set_value (first_y_pos);
6903 redo_visual_stack.push_back (current_visual_state (true));
6905 visible_tracks_selector.set_text (_("Sel"));
6909 Editor::save_visual_state (uint32_t n)
6911 while (visual_states.size() <= n) {
6912 visual_states.push_back (0);
6915 if (visual_states[n] != 0) {
6916 delete visual_states[n];
6919 visual_states[n] = current_visual_state (true);
6924 Editor::goto_visual_state (uint32_t n)
6926 if (visual_states.size() <= n) {
6930 if (visual_states[n] == 0) {
6934 use_visual_state (*visual_states[n]);
6938 Editor::start_visual_state_op (uint32_t n)
6940 save_visual_state (n);
6942 PopUp* pup = new PopUp (WIN_POS_MOUSE, 1000, true);
6944 snprintf (buf, sizeof (buf), _("Saved view %u"), n+1);
6945 pup->set_text (buf);
6950 Editor::cancel_visual_state_op (uint32_t n)
6952 goto_visual_state (n);
6956 Editor::toggle_region_mute ()
6958 if (_ignore_region_action) {
6962 RegionSelection rs = get_regions_from_selection_and_entered ();
6968 if (rs.size() > 1) {
6969 begin_reversible_command (_("mute regions"));
6971 begin_reversible_command (_("mute region"));
6974 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
6976 (*i)->region()->playlist()->clear_changes ();
6977 (*i)->region()->set_muted (!(*i)->region()->muted ());
6978 _session->add_command (new StatefulDiffCommand ((*i)->region()->playlist()));
6982 commit_reversible_command ();
6986 Editor::combine_regions ()
6988 /* foreach track with selected regions, take all selected regions
6989 and join them into a new region containing the subregions (as a
6993 typedef set<RouteTimeAxisView*> RTVS;
6996 if (selection->regions.empty()) {
7000 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
7001 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(&(*i)->get_time_axis_view());
7004 tracks.insert (rtv);
7008 begin_reversible_command (_("combine regions"));
7010 vector<RegionView*> new_selection;
7012 for (RTVS::iterator i = tracks.begin(); i != tracks.end(); ++i) {
7015 if ((rv = (*i)->combine_regions ()) != 0) {
7016 new_selection.push_back (rv);
7020 selection->clear_regions ();
7021 for (vector<RegionView*>::iterator i = new_selection.begin(); i != new_selection.end(); ++i) {
7022 selection->add (*i);
7025 commit_reversible_command ();
7029 Editor::uncombine_regions ()
7031 typedef set<RouteTimeAxisView*> RTVS;
7034 if (selection->regions.empty()) {
7038 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
7039 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(&(*i)->get_time_axis_view());
7042 tracks.insert (rtv);
7046 begin_reversible_command (_("uncombine regions"));
7048 for (RTVS::iterator i = tracks.begin(); i != tracks.end(); ++i) {
7049 (*i)->uncombine_regions ();
7052 commit_reversible_command ();
7056 Editor::toggle_midi_input_active (bool flip_others)
7059 boost::shared_ptr<RouteList> rl (new RouteList);
7061 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
7062 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
7068 boost::shared_ptr<MidiTrack> mt = rtav->midi_track();
7071 rl->push_back (rtav->route());
7072 onoff = !mt->input_active();
7076 _session->set_exclusive_input_active (rl, onoff, flip_others);
7083 lock_dialog = new Gtk::Dialog (string_compose (_("%1: Locked"), PROGRAM_NAME), true);
7085 Gtk::Image* padlock = manage (new Gtk::Image (ARDOUR_UI_UTILS::get_icon ("padlock_closed")));
7086 lock_dialog->get_vbox()->pack_start (*padlock);
7088 ArdourButton* b = manage (new ArdourButton);
7089 b->set_name ("lock button");
7090 b->set_text (_("Click to unlock"));
7091 b->signal_clicked.connect (sigc::mem_fun (*this, &Editor::unlock));
7092 lock_dialog->get_vbox()->pack_start (*b);
7094 lock_dialog->get_vbox()->show_all ();
7095 lock_dialog->set_size_request (200, 200);
7099 /* The global menu bar continues to be accessible to applications
7100 with modal dialogs, which means that we need to desensitize
7101 all items in the menu bar. Since those items are really just
7102 proxies for actions, that means disabling all actions.
7104 ActionManager::disable_all_actions ();
7106 lock_dialog->present ();
7112 lock_dialog->hide ();
7115 ActionManager::pop_action_state ();
7118 if (ARDOUR_UI::config()->get_lock_gui_after_seconds()) {
7119 start_lock_event_timing ();
7124 Editor::bring_in_callback (Gtk::Label* label, uint32_t n, uint32_t total, string name)
7126 Gtkmm2ext::UI::instance()->call_slot (invalidator (*this), boost::bind (&Editor::update_bring_in_message, this, label, n, total, name));
7130 Editor::update_bring_in_message (Gtk::Label* label, uint32_t n, uint32_t total, string name)
7132 label->set_text (string_compose ("Copying %1, %2 of %3", name, n, total));
7133 Gtkmm2ext::UI::instance()->flush_pending ();
7137 Editor::bring_all_sources_into_session ()
7144 ArdourDialog w (_("Moving embedded files into session folder"));
7145 w.get_vbox()->pack_start (msg);
7148 /* flush all pending GUI events because we're about to start copying
7152 Gtkmm2ext::UI::instance()->flush_pending ();
7156 _session->bring_all_sources_into_session (boost::bind (&Editor::bring_in_callback, this, &msg, _1, _2, _3));