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 ((start == 0 && end == 0) || end < start) {
1774 calc_extra_zoom_edges(start, end);
1776 temporal_zoom_by_frame (start, end);
1781 Editor::temporal_zoom_by_frame (framepos_t start, framepos_t end)
1783 if (!_session) return;
1785 if ((start == 0 && end == 0) || end < start) {
1789 framepos_t range = end - start;
1791 double const new_fpp = (double) range / (double) _visible_canvas_width;
1793 framepos_t new_page = (framepos_t) floor (_visible_canvas_width * new_fpp);
1794 framepos_t middle = (framepos_t) floor ((double) start + ((double) range / 2.0f));
1795 framepos_t new_leftmost = (framepos_t) floor ((double) middle - ((double) new_page / 2.0f));
1797 if (new_leftmost > middle) {
1801 if (new_leftmost < 0) {
1805 reposition_and_zoom (new_leftmost, new_fpp);
1809 Editor::temporal_zoom_to_frame (bool coarser, framepos_t frame)
1815 framecnt_t range_before = frame - leftmost_frame;
1819 if (samples_per_pixel <= 1) {
1822 new_spp = samples_per_pixel + (samples_per_pixel/2);
1824 range_before += range_before/2;
1826 if (samples_per_pixel >= 1) {
1827 new_spp = samples_per_pixel - (samples_per_pixel/2);
1829 /* could bail out here since we cannot zoom any finer,
1830 but leave that to the equality test below
1832 new_spp = samples_per_pixel;
1835 range_before -= range_before/2;
1838 if (new_spp == samples_per_pixel) {
1842 /* zoom focus is automatically taken as @param frame when this
1846 framepos_t new_leftmost = frame - (framepos_t)range_before;
1848 if (new_leftmost > frame) {
1852 if (new_leftmost < 0) {
1856 reposition_and_zoom (new_leftmost, new_spp);
1861 Editor::choose_new_marker_name(string &name) {
1863 if (!Config->get_name_new_markers()) {
1864 /* don't prompt user for a new name */
1868 ArdourPrompter dialog (true);
1870 dialog.set_prompt (_("New Name:"));
1872 dialog.set_title (_("New Location Marker"));
1874 dialog.set_name ("MarkNameWindow");
1875 dialog.set_size_request (250, -1);
1876 dialog.set_position (Gtk::WIN_POS_MOUSE);
1878 dialog.add_button (Stock::OK, RESPONSE_ACCEPT);
1879 dialog.set_initial_text (name);
1883 switch (dialog.run ()) {
1884 case RESPONSE_ACCEPT:
1890 dialog.get_result(name);
1897 Editor::add_location_from_selection ()
1901 if (selection->time.empty()) {
1905 if (_session == 0 || clicked_axisview == 0) {
1909 framepos_t start = selection->time[clicked_selection].start;
1910 framepos_t end = selection->time[clicked_selection].end;
1912 _session->locations()->next_available_name(rangename,"selection");
1913 Location *location = new Location (*_session, start, end, rangename, Location::IsRangeMarker);
1915 _session->begin_reversible_command (_("add marker"));
1916 XMLNode &before = _session->locations()->get_state();
1917 _session->locations()->add (location, true);
1918 XMLNode &after = _session->locations()->get_state();
1919 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
1920 _session->commit_reversible_command ();
1924 Editor::add_location_mark (framepos_t where)
1928 select_new_marker = true;
1930 _session->locations()->next_available_name(markername,"mark");
1931 if (!choose_new_marker_name(markername)) {
1934 Location *location = new Location (*_session, where, where, markername, Location::IsMark);
1935 _session->begin_reversible_command (_("add marker"));
1936 XMLNode &before = _session->locations()->get_state();
1937 _session->locations()->add (location, true);
1938 XMLNode &after = _session->locations()->get_state();
1939 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
1940 _session->commit_reversible_command ();
1944 Editor::add_location_from_playhead_cursor ()
1946 add_location_mark (_session->audible_frame());
1950 Editor::remove_location_at_playhead_cursor ()
1955 _session->begin_reversible_command (_("remove marker"));
1956 XMLNode &before = _session->locations()->get_state();
1957 bool removed = false;
1959 //find location(s) at this time
1960 Locations::LocationList locs;
1961 _session->locations()->find_all_between (_session->audible_frame(), _session->audible_frame()+1, locs, Location::Flags(0));
1962 for (Locations::LocationList::iterator i = locs.begin(); i != locs.end(); ++i) {
1963 if ((*i)->is_mark()) {
1964 _session->locations()->remove (*i);
1971 XMLNode &after = _session->locations()->get_state();
1972 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
1973 _session->commit_reversible_command ();
1978 /** Add a range marker around each selected region */
1980 Editor::add_locations_from_region ()
1982 RegionSelection rs = get_regions_from_selection_and_entered ();
1988 _session->begin_reversible_command (selection->regions.size () > 1 ? _("add markers") : _("add marker"));
1989 XMLNode &before = _session->locations()->get_state();
1991 for (RegionSelection::iterator i = rs.begin (); i != rs.end (); ++i) {
1993 boost::shared_ptr<Region> region = (*i)->region ();
1995 Location *location = new Location (*_session, region->position(), region->last_frame(), region->name(), Location::IsRangeMarker);
1997 _session->locations()->add (location, true);
2000 XMLNode &after = _session->locations()->get_state();
2001 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2002 _session->commit_reversible_command ();
2005 /** Add a single range marker around all selected regions */
2007 Editor::add_location_from_region ()
2009 RegionSelection rs = get_regions_from_selection_and_entered ();
2015 _session->begin_reversible_command (_("add marker"));
2016 XMLNode &before = _session->locations()->get_state();
2020 if (rs.size() > 1) {
2021 _session->locations()->next_available_name(markername, "regions");
2023 RegionView* rv = *(rs.begin());
2024 boost::shared_ptr<Region> region = rv->region();
2025 markername = region->name();
2028 if (!choose_new_marker_name(markername)) {
2032 // single range spanning all selected
2033 Location *location = new Location (*_session, selection->regions.start(), selection->regions.end_frame(), markername, Location::IsRangeMarker);
2034 _session->locations()->add (location, true);
2036 XMLNode &after = _session->locations()->get_state();
2037 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2038 _session->commit_reversible_command ();
2044 Editor::jump_forward_to_mark ()
2050 framepos_t pos = _session->locations()->first_mark_after (playhead_cursor->current_frame());
2056 _session->request_locate (pos, _session->transport_rolling());
2060 Editor::jump_backward_to_mark ()
2066 framepos_t pos = _session->locations()->first_mark_before (playhead_cursor->current_frame());
2072 _session->request_locate (pos, _session->transport_rolling());
2078 framepos_t const pos = _session->audible_frame ();
2081 _session->locations()->next_available_name (markername, "mark");
2083 if (!choose_new_marker_name (markername)) {
2087 _session->locations()->add (new Location (*_session, pos, 0, markername, Location::IsMark), true);
2091 Editor::clear_markers ()
2094 _session->begin_reversible_command (_("clear markers"));
2095 XMLNode &before = _session->locations()->get_state();
2096 _session->locations()->clear_markers ();
2097 XMLNode &after = _session->locations()->get_state();
2098 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2099 _session->commit_reversible_command ();
2104 Editor::clear_ranges ()
2107 _session->begin_reversible_command (_("clear ranges"));
2108 XMLNode &before = _session->locations()->get_state();
2110 Location * looploc = _session->locations()->auto_loop_location();
2111 Location * punchloc = _session->locations()->auto_punch_location();
2112 Location * sessionloc = _session->locations()->session_range_location();
2114 _session->locations()->clear_ranges ();
2116 if (looploc) _session->locations()->add (looploc);
2117 if (punchloc) _session->locations()->add (punchloc);
2118 if (sessionloc) _session->locations()->add (sessionloc);
2120 XMLNode &after = _session->locations()->get_state();
2121 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2122 _session->commit_reversible_command ();
2127 Editor::clear_locations ()
2129 _session->begin_reversible_command (_("clear locations"));
2130 XMLNode &before = _session->locations()->get_state();
2131 _session->locations()->clear ();
2132 XMLNode &after = _session->locations()->get_state();
2133 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2134 _session->commit_reversible_command ();
2135 _session->locations()->clear ();
2139 Editor::unhide_markers ()
2141 for (LocationMarkerMap::iterator i = location_markers.begin(); i != location_markers.end(); ++i) {
2142 Location *l = (*i).first;
2143 if (l->is_hidden() && l->is_mark()) {
2144 l->set_hidden(false, this);
2150 Editor::unhide_ranges ()
2152 for (LocationMarkerMap::iterator i = location_markers.begin(); i != location_markers.end(); ++i) {
2153 Location *l = (*i).first;
2154 if (l->is_hidden() && l->is_range_marker()) {
2155 l->set_hidden(false, this);
2160 /* INSERT/REPLACE */
2163 Editor::insert_region_list_selection (float times)
2165 RouteTimeAxisView *tv = 0;
2166 boost::shared_ptr<Playlist> playlist;
2168 if (clicked_routeview != 0) {
2169 tv = clicked_routeview;
2170 } else if (!selection->tracks.empty()) {
2171 if ((tv = dynamic_cast<RouteTimeAxisView*>(selection->tracks.front())) == 0) {
2174 } else if (entered_track != 0) {
2175 if ((tv = dynamic_cast<RouteTimeAxisView*>(entered_track)) == 0) {
2182 if ((playlist = tv->playlist()) == 0) {
2186 boost::shared_ptr<Region> region = _regions->get_single_selection ();
2191 begin_reversible_command (_("insert region"));
2192 playlist->clear_changes ();
2193 playlist->add_region ((RegionFactory::create (region, true)), get_preferred_edit_position(), times);
2194 if (Config->get_edit_mode() == Ripple)
2195 playlist->ripple (get_preferred_edit_position(), region->length() * times, boost::shared_ptr<Region>());
2197 _session->add_command(new StatefulDiffCommand (playlist));
2198 commit_reversible_command ();
2201 /* BUILT-IN EFFECTS */
2204 Editor::reverse_selection ()
2209 /* GAIN ENVELOPE EDITING */
2212 Editor::edit_envelope ()
2219 Editor::transition_to_rolling (bool fwd)
2225 if (_session->config.get_external_sync()) {
2226 switch (Config->get_sync_source()) {
2230 /* transport controlled by the master */
2235 if (_session->is_auditioning()) {
2236 _session->cancel_audition ();
2240 _session->request_transport_speed (fwd ? 1.0f : -1.0f);
2244 Editor::play_from_start ()
2246 _session->request_locate (_session->current_start_frame(), true);
2250 Editor::play_from_edit_point ()
2252 _session->request_locate (get_preferred_edit_position(), true);
2256 Editor::play_from_edit_point_and_return ()
2258 framepos_t start_frame;
2259 framepos_t return_frame;
2261 start_frame = get_preferred_edit_position (true);
2263 if (_session->transport_rolling()) {
2264 _session->request_locate (start_frame, false);
2268 /* don't reset the return frame if its already set */
2270 if ((return_frame = _session->requested_return_frame()) < 0) {
2271 return_frame = _session->audible_frame();
2274 if (start_frame >= 0) {
2275 _session->request_roll_at_and_return (start_frame, return_frame);
2280 Editor::play_selection ()
2282 if (selection->time.empty()) {
2286 _session->request_play_range (&selection->time, true);
2290 Editor::get_preroll ()
2292 return 1.0 /*Config->get_edit_preroll_seconds()*/ * _session->frame_rate();
2297 Editor::maybe_locate_with_edit_preroll ( framepos_t location )
2299 if ( _session->transport_rolling() || !Config->get_follow_edits() || _ignore_follow_edits )
2302 location -= get_preroll();
2304 //don't try to locate before the beginning of time
2308 //if follow_playhead is on, keep the playhead on the screen
2309 if ( _follow_playhead )
2310 if ( location < leftmost_frame )
2311 location = leftmost_frame;
2313 _session->request_locate( location );
2317 Editor::play_with_preroll ()
2319 if (selection->time.empty()) {
2322 framepos_t preroll = get_preroll();
2324 framepos_t start = 0;
2325 if (selection->time[clicked_selection].start > preroll)
2326 start = selection->time[clicked_selection].start - preroll;
2328 framepos_t end = selection->time[clicked_selection].end + preroll;
2330 AudioRange ar (start, end, 0);
2331 list<AudioRange> lar;
2334 _session->request_play_range (&lar, true);
2339 Editor::play_location (Location& location)
2341 if (location.start() <= location.end()) {
2345 _session->request_bounded_roll (location.start(), location.end());
2349 Editor::loop_location (Location& location)
2351 if (location.start() <= location.end()) {
2357 if ((tll = transport_loop_location()) != 0) {
2358 tll->set (location.start(), location.end());
2360 // enable looping, reposition and start rolling
2361 _session->request_play_loop (true);
2362 _session->request_locate (tll->start(), true);
2367 Editor::do_layer_operation (LayerOperation op)
2369 if (selection->regions.empty ()) {
2373 bool const multiple = selection->regions.size() > 1;
2377 begin_reversible_command (_("raise regions"));
2379 begin_reversible_command (_("raise region"));
2385 begin_reversible_command (_("raise regions to top"));
2387 begin_reversible_command (_("raise region to top"));
2393 begin_reversible_command (_("lower regions"));
2395 begin_reversible_command (_("lower region"));
2401 begin_reversible_command (_("lower regions to bottom"));
2403 begin_reversible_command (_("lower region"));
2408 set<boost::shared_ptr<Playlist> > playlists = selection->regions.playlists ();
2409 for (set<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
2410 (*i)->clear_owned_changes ();
2413 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
2414 boost::shared_ptr<Region> r = (*i)->region ();
2426 r->lower_to_bottom ();
2430 for (set<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
2431 vector<Command*> cmds;
2433 _session->add_commands (cmds);
2436 commit_reversible_command ();
2440 Editor::raise_region ()
2442 do_layer_operation (Raise);
2446 Editor::raise_region_to_top ()
2448 do_layer_operation (RaiseToTop);
2452 Editor::lower_region ()
2454 do_layer_operation (Lower);
2458 Editor::lower_region_to_bottom ()
2460 do_layer_operation (LowerToBottom);
2463 /** Show the region editor for the selected regions */
2465 Editor::show_region_properties ()
2467 selection->foreach_regionview (&RegionView::show_region_editor);
2470 /** Show the midi list editor for the selected MIDI regions */
2472 Editor::show_midi_list_editor ()
2474 selection->foreach_midi_regionview (&MidiRegionView::show_list_editor);
2478 Editor::rename_region ()
2480 RegionSelection rs = get_regions_from_selection_and_entered ();
2486 ArdourDialog d (*this, _("Rename Region"), true, false);
2488 Label label (_("New name:"));
2491 hbox.set_spacing (6);
2492 hbox.pack_start (label, false, false);
2493 hbox.pack_start (entry, true, true);
2495 d.get_vbox()->set_border_width (12);
2496 d.get_vbox()->pack_start (hbox, false, false);
2498 d.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
2499 d.add_button(Gtk::Stock::OK, Gtk::RESPONSE_OK);
2501 d.set_size_request (300, -1);
2503 entry.set_text (rs.front()->region()->name());
2504 entry.select_region (0, -1);
2506 entry.signal_activate().connect (sigc::bind (sigc::mem_fun (d, &Dialog::response), RESPONSE_OK));
2512 int const ret = d.run();
2516 if (ret != RESPONSE_OK) {
2520 std::string str = entry.get_text();
2521 strip_whitespace_edges (str);
2523 rs.front()->region()->set_name (str);
2524 _regions->redisplay ();
2529 Editor::audition_playlist_region_via_route (boost::shared_ptr<Region> region, Route& route)
2531 if (_session->is_auditioning()) {
2532 _session->cancel_audition ();
2535 // note: some potential for creativity here, because region doesn't
2536 // have to belong to the playlist that Route is handling
2538 // bool was_soloed = route.soloed();
2540 route.set_solo (true, this);
2542 _session->request_bounded_roll (region->position(), region->position() + region->length());
2544 /* XXX how to unset the solo state ? */
2547 /** Start an audition of the first selected region */
2549 Editor::play_edit_range ()
2551 framepos_t start, end;
2553 if (get_edit_op_range (start, end)) {
2554 _session->request_bounded_roll (start, end);
2559 Editor::play_selected_region ()
2561 framepos_t start = max_framepos;
2564 RegionSelection rs = get_regions_from_selection_and_entered ();
2570 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
2571 if ((*i)->region()->position() < start) {
2572 start = (*i)->region()->position();
2574 if ((*i)->region()->last_frame() + 1 > end) {
2575 end = (*i)->region()->last_frame() + 1;
2579 _session->request_bounded_roll (start, end);
2583 Editor::audition_playlist_region_standalone (boost::shared_ptr<Region> region)
2585 _session->audition_region (region);
2589 Editor::region_from_selection ()
2591 if (clicked_axisview == 0) {
2595 if (selection->time.empty()) {
2599 framepos_t start = selection->time[clicked_selection].start;
2600 framepos_t end = selection->time[clicked_selection].end;
2602 TrackViewList tracks = get_tracks_for_range_action ();
2604 framepos_t selection_cnt = end - start + 1;
2606 for (TrackSelection::iterator i = tracks.begin(); i != tracks.end(); ++i) {
2607 boost::shared_ptr<Region> current;
2608 boost::shared_ptr<Playlist> pl;
2609 framepos_t internal_start;
2612 if ((pl = (*i)->playlist()) == 0) {
2616 if ((current = pl->top_region_at (start)) == 0) {
2620 internal_start = start - current->position();
2621 RegionFactory::region_name (new_name, current->name(), true);
2625 plist.add (ARDOUR::Properties::start, current->start() + internal_start);
2626 plist.add (ARDOUR::Properties::length, selection_cnt);
2627 plist.add (ARDOUR::Properties::name, new_name);
2628 plist.add (ARDOUR::Properties::layer, 0);
2630 boost::shared_ptr<Region> region (RegionFactory::create (current, plist));
2635 Editor::create_region_from_selection (vector<boost::shared_ptr<Region> >& new_regions)
2637 if (selection->time.empty() || selection->tracks.empty()) {
2641 framepos_t start = selection->time[clicked_selection].start;
2642 framepos_t end = selection->time[clicked_selection].end;
2644 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
2645 sort_track_selection (ts);
2647 for (TrackSelection::iterator i = ts.begin(); i != ts.end(); ++i) {
2648 boost::shared_ptr<Region> current;
2649 boost::shared_ptr<Playlist> playlist;
2650 framepos_t internal_start;
2653 if ((playlist = (*i)->playlist()) == 0) {
2657 if ((current = playlist->top_region_at(start)) == 0) {
2661 internal_start = start - current->position();
2662 RegionFactory::region_name (new_name, current->name(), true);
2666 plist.add (ARDOUR::Properties::start, current->start() + internal_start);
2667 plist.add (ARDOUR::Properties::length, end - start + 1);
2668 plist.add (ARDOUR::Properties::name, new_name);
2670 new_regions.push_back (RegionFactory::create (current, plist));
2675 Editor::split_multichannel_region ()
2677 RegionSelection rs = get_regions_from_selection_and_entered ();
2683 vector< boost::shared_ptr<Region> > v;
2685 for (list<RegionView*>::iterator x = rs.begin(); x != rs.end(); ++x) {
2686 (*x)->region()->separate_by_channel (*_session, v);
2691 Editor::new_region_from_selection ()
2693 region_from_selection ();
2694 cancel_selection ();
2698 add_if_covered (RegionView* rv, const AudioRange* ar, RegionSelection* rs)
2700 switch (rv->region()->coverage (ar->start, ar->end - 1)) {
2701 case Evoral::OverlapNone:
2709 * - selected tracks, or if there are none...
2710 * - tracks containing selected regions, or if there are none...
2715 Editor::get_tracks_for_range_action () const
2719 if (selection->tracks.empty()) {
2721 /* use tracks with selected regions */
2723 RegionSelection rs = selection->regions;
2725 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
2726 TimeAxisView* tv = &(*i)->get_time_axis_view();
2728 if (!t.contains (tv)) {
2734 /* no regions and no tracks: use all tracks */
2740 t = selection->tracks;
2743 return t.filter_to_unique_playlists();
2747 Editor::separate_regions_between (const TimeSelection& ts)
2749 bool in_command = false;
2750 boost::shared_ptr<Playlist> playlist;
2751 RegionSelection new_selection;
2753 TrackViewList tmptracks = get_tracks_for_range_action ();
2754 sort_track_selection (tmptracks);
2756 for (TrackSelection::iterator i = tmptracks.begin(); i != tmptracks.end(); ++i) {
2758 RouteTimeAxisView* rtv;
2760 if ((rtv = dynamic_cast<RouteTimeAxisView*> ((*i))) != 0) {
2762 if (rtv->is_track()) {
2764 /* no edits to destructive tracks */
2766 if (rtv->track()->destructive()) {
2770 if ((playlist = rtv->playlist()) != 0) {
2772 playlist->clear_changes ();
2774 /* XXX need to consider musical time selections here at some point */
2776 double speed = rtv->track()->speed();
2779 for (list<AudioRange>::const_iterator t = ts.begin(); t != ts.end(); ++t) {
2781 sigc::connection c = rtv->view()->RegionViewAdded.connect (
2782 sigc::mem_fun(*this, &Editor::collect_new_region_view));
2784 latest_regionviews.clear ();
2786 playlist->partition ((framepos_t)((*t).start * speed),
2787 (framepos_t)((*t).end * speed), false);
2791 if (!latest_regionviews.empty()) {
2793 rtv->view()->foreach_regionview (sigc::bind (
2794 sigc::ptr_fun (add_if_covered),
2795 &(*t), &new_selection));
2798 begin_reversible_command (_("separate"));
2802 /* pick up changes to existing regions */
2804 vector<Command*> cmds;
2805 playlist->rdiff (cmds);
2806 _session->add_commands (cmds);
2808 /* pick up changes to the playlist itself (adds/removes)
2811 _session->add_command(new StatefulDiffCommand (playlist));
2820 // selection->set (new_selection);
2822 commit_reversible_command ();
2826 struct PlaylistState {
2827 boost::shared_ptr<Playlist> playlist;
2831 /** Take tracks from get_tracks_for_range_action and cut any regions
2832 * on those tracks so that the tracks are empty over the time
2836 Editor::separate_region_from_selection ()
2838 /* preferentially use *all* ranges in the time selection if we're in range mode
2839 to allow discontiguous operation, since get_edit_op_range() currently
2840 returns a single range.
2843 if (!selection->time.empty()) {
2845 separate_regions_between (selection->time);
2852 if (get_edit_op_range (start, end)) {
2854 AudioRange ar (start, end, 1);
2858 separate_regions_between (ts);
2864 Editor::separate_region_from_punch ()
2866 Location* loc = _session->locations()->auto_punch_location();
2868 separate_regions_using_location (*loc);
2873 Editor::separate_region_from_loop ()
2875 Location* loc = _session->locations()->auto_loop_location();
2877 separate_regions_using_location (*loc);
2882 Editor::separate_regions_using_location (Location& loc)
2884 if (loc.is_mark()) {
2888 AudioRange ar (loc.start(), loc.end(), 1);
2893 separate_regions_between (ts);
2896 /** Separate regions under the selected region */
2898 Editor::separate_under_selected_regions ()
2900 vector<PlaylistState> playlists;
2904 rs = get_regions_from_selection_and_entered();
2906 if (!_session || rs.empty()) {
2910 begin_reversible_command (_("separate region under"));
2912 list<boost::shared_ptr<Region> > regions_to_remove;
2914 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
2915 // we can't just remove the region(s) in this loop because
2916 // this removes them from the RegionSelection, and they thus
2917 // disappear from underneath the iterator, and the ++i above
2918 // SEGVs in a puzzling fashion.
2920 // so, first iterate over the regions to be removed from rs and
2921 // add them to the regions_to_remove list, and then
2922 // iterate over the list to actually remove them.
2924 regions_to_remove.push_back ((*i)->region());
2927 for (list<boost::shared_ptr<Region> >::iterator rl = regions_to_remove.begin(); rl != regions_to_remove.end(); ++rl) {
2929 boost::shared_ptr<Playlist> playlist = (*rl)->playlist();
2932 // is this check necessary?
2936 vector<PlaylistState>::iterator i;
2938 //only take state if this is a new playlist.
2939 for (i = playlists.begin(); i != playlists.end(); ++i) {
2940 if ((*i).playlist == playlist) {
2945 if (i == playlists.end()) {
2947 PlaylistState before;
2948 before.playlist = playlist;
2949 before.before = &playlist->get_state();
2951 playlist->freeze ();
2952 playlists.push_back(before);
2955 //Partition on the region bounds
2956 playlist->partition ((*rl)->first_frame() - 1, (*rl)->last_frame() + 1, true);
2958 //Re-add region that was just removed due to the partition operation
2959 playlist->add_region( (*rl), (*rl)->first_frame() );
2962 vector<PlaylistState>::iterator pl;
2964 for (pl = playlists.begin(); pl != playlists.end(); ++pl) {
2965 (*pl).playlist->thaw ();
2966 _session->add_command(new MementoCommand<Playlist>(*(*pl).playlist, (*pl).before, &(*pl).playlist->get_state()));
2969 commit_reversible_command ();
2973 Editor::crop_region_to_selection ()
2975 if (!selection->time.empty()) {
2977 crop_region_to (selection->time.start(), selection->time.end_frame());
2984 if (get_edit_op_range (start, end)) {
2985 crop_region_to (start, end);
2992 Editor::crop_region_to (framepos_t start, framepos_t end)
2994 vector<boost::shared_ptr<Playlist> > playlists;
2995 boost::shared_ptr<Playlist> playlist;
2998 if (selection->tracks.empty()) {
2999 ts = track_views.filter_to_unique_playlists();
3001 ts = selection->tracks.filter_to_unique_playlists ();
3004 sort_track_selection (ts);
3006 for (TrackSelection::iterator i = ts.begin(); i != ts.end(); ++i) {
3008 RouteTimeAxisView* rtv;
3010 if ((rtv = dynamic_cast<RouteTimeAxisView*> ((*i))) != 0) {
3012 boost::shared_ptr<Track> t = rtv->track();
3014 if (t != 0 && ! t->destructive()) {
3016 if ((playlist = rtv->playlist()) != 0) {
3017 playlists.push_back (playlist);
3023 if (playlists.empty()) {
3027 framepos_t the_start;
3031 begin_reversible_command (_("trim to selection"));
3033 for (vector<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
3035 boost::shared_ptr<Region> region;
3039 if ((region = (*i)->top_region_at(the_start)) == 0) {
3043 /* now adjust lengths to that we do the right thing
3044 if the selection extends beyond the region
3047 the_start = max (the_start, (framepos_t) region->position());
3048 if (max_framepos - the_start < region->length()) {
3049 the_end = the_start + region->length() - 1;
3051 the_end = max_framepos;
3053 the_end = min (end, the_end);
3054 cnt = the_end - the_start + 1;
3056 region->clear_changes ();
3057 region->trim_to (the_start, cnt);
3058 _session->add_command (new StatefulDiffCommand (region));
3061 commit_reversible_command ();
3065 Editor::region_fill_track ()
3067 RegionSelection rs = get_regions_from_selection_and_entered ();
3069 if (!_session || rs.empty()) {
3073 framepos_t const end = _session->current_end_frame ();
3075 begin_reversible_command (Operations::region_fill);
3077 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3079 boost::shared_ptr<Region> region ((*i)->region());
3081 boost::shared_ptr<Playlist> pl = region->playlist();
3083 if (end <= region->last_frame()) {
3087 double times = (double) (end - region->last_frame()) / (double) region->length();
3093 pl->clear_changes ();
3094 pl->add_region (RegionFactory::create (region, true), region->last_frame(), times);
3095 _session->add_command (new StatefulDiffCommand (pl));
3098 commit_reversible_command ();
3102 Editor::region_fill_selection ()
3104 if (clicked_routeview == 0 || !clicked_routeview->is_audio_track()) {
3108 if (selection->time.empty()) {
3112 boost::shared_ptr<Region> region = _regions->get_single_selection ();
3117 framepos_t start = selection->time[clicked_selection].start;
3118 framepos_t end = selection->time[clicked_selection].end;
3120 boost::shared_ptr<Playlist> playlist;
3122 if (selection->tracks.empty()) {
3126 framepos_t selection_length = end - start;
3127 float times = (float)selection_length / region->length();
3129 begin_reversible_command (Operations::fill_selection);
3131 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
3133 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
3135 if ((playlist = (*i)->playlist()) == 0) {
3139 playlist->clear_changes ();
3140 playlist->add_region (RegionFactory::create (region, true), start, times);
3141 _session->add_command (new StatefulDiffCommand (playlist));
3144 commit_reversible_command ();
3148 Editor::set_region_sync_position ()
3150 set_sync_point (get_preferred_edit_position (), get_regions_from_selection_and_edit_point ());
3154 Editor::set_sync_point (framepos_t where, const RegionSelection& rs)
3156 bool in_command = false;
3158 for (RegionSelection::const_iterator r = rs.begin(); r != rs.end(); ++r) {
3160 if (!(*r)->region()->covers (where)) {
3164 boost::shared_ptr<Region> region ((*r)->region());
3167 begin_reversible_command (_("set sync point"));
3171 region->clear_changes ();
3172 region->set_sync_position (where);
3173 _session->add_command(new StatefulDiffCommand (region));
3177 commit_reversible_command ();
3181 /** Remove the sync positions of the selection */
3183 Editor::remove_region_sync ()
3185 RegionSelection rs = get_regions_from_selection_and_entered ();
3191 begin_reversible_command (_("remove region sync"));
3193 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3195 (*i)->region()->clear_changes ();
3196 (*i)->region()->clear_sync_position ();
3197 _session->add_command(new StatefulDiffCommand ((*i)->region()));
3200 commit_reversible_command ();
3204 Editor::naturalize_region ()
3206 RegionSelection rs = get_regions_from_selection_and_entered ();
3212 if (rs.size() > 1) {
3213 begin_reversible_command (_("move regions to original position"));
3215 begin_reversible_command (_("move region to original position"));
3218 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3219 (*i)->region()->clear_changes ();
3220 (*i)->region()->move_to_natural_position ();
3221 _session->add_command (new StatefulDiffCommand ((*i)->region()));
3224 commit_reversible_command ();
3228 Editor::align_regions (RegionPoint what)
3230 RegionSelection const rs = get_regions_from_selection_and_edit_point ();
3236 begin_reversible_command (_("align selection"));
3238 framepos_t const position = get_preferred_edit_position ();
3240 for (RegionSelection::const_iterator i = rs.begin(); i != rs.end(); ++i) {
3241 align_region_internal ((*i)->region(), what, position);
3244 commit_reversible_command ();
3247 struct RegionSortByTime {
3248 bool operator() (const RegionView* a, const RegionView* b) {
3249 return a->region()->position() < b->region()->position();
3254 Editor::align_regions_relative (RegionPoint point)
3256 RegionSelection const rs = get_regions_from_selection_and_edit_point ();
3262 framepos_t const position = get_preferred_edit_position ();
3264 framepos_t distance = 0;
3268 list<RegionView*> sorted;
3269 rs.by_position (sorted);
3271 boost::shared_ptr<Region> r ((*sorted.begin())->region());
3276 if (position > r->position()) {
3277 distance = position - r->position();
3279 distance = r->position() - position;
3285 if (position > r->last_frame()) {
3286 distance = position - r->last_frame();
3287 pos = r->position() + distance;
3289 distance = r->last_frame() - position;
3290 pos = r->position() - distance;
3296 pos = r->adjust_to_sync (position);
3297 if (pos > r->position()) {
3298 distance = pos - r->position();
3300 distance = r->position() - pos;
3306 if (pos == r->position()) {
3310 begin_reversible_command (_("align selection (relative)"));
3312 /* move first one specially */
3314 r->clear_changes ();
3315 r->set_position (pos);
3316 _session->add_command(new StatefulDiffCommand (r));
3318 /* move rest by the same amount */
3322 for (list<RegionView*>::iterator i = sorted.begin(); i != sorted.end(); ++i) {
3324 boost::shared_ptr<Region> region ((*i)->region());
3326 region->clear_changes ();
3329 region->set_position (region->position() + distance);
3331 region->set_position (region->position() - distance);
3334 _session->add_command(new StatefulDiffCommand (region));
3338 commit_reversible_command ();
3342 Editor::align_region (boost::shared_ptr<Region> region, RegionPoint point, framepos_t position)
3344 begin_reversible_command (_("align region"));
3345 align_region_internal (region, point, position);
3346 commit_reversible_command ();
3350 Editor::align_region_internal (boost::shared_ptr<Region> region, RegionPoint point, framepos_t position)
3352 region->clear_changes ();
3356 region->set_position (region->adjust_to_sync (position));
3360 if (position > region->length()) {
3361 region->set_position (position - region->length());
3366 region->set_position (position);
3370 _session->add_command(new StatefulDiffCommand (region));
3374 Editor::trim_region_front ()
3380 Editor::trim_region_back ()
3382 trim_region (false);
3386 Editor::trim_region (bool front)
3388 framepos_t where = get_preferred_edit_position();
3389 RegionSelection rs = get_regions_from_selection_and_edit_point ();
3395 begin_reversible_command (front ? _("trim front") : _("trim back"));
3397 for (list<RegionView*>::const_iterator i = rs.by_layer().begin(); i != rs.by_layer().end(); ++i) {
3398 if (!(*i)->region()->locked()) {
3400 (*i)->region()->clear_changes ();
3403 (*i)->region()->trim_front (where);
3404 maybe_locate_with_edit_preroll ( where );
3406 (*i)->region()->trim_end (where);
3407 maybe_locate_with_edit_preroll ( where );
3410 _session->add_command (new StatefulDiffCommand ((*i)->region()));
3414 commit_reversible_command ();
3417 /** Trim the end of the selected regions to the position of the edit cursor */
3419 Editor::trim_region_to_loop ()
3421 Location* loc = _session->locations()->auto_loop_location();
3425 trim_region_to_location (*loc, _("trim to loop"));
3429 Editor::trim_region_to_punch ()
3431 Location* loc = _session->locations()->auto_punch_location();
3435 trim_region_to_location (*loc, _("trim to punch"));
3439 Editor::trim_region_to_location (const Location& loc, const char* str)
3441 RegionSelection rs = get_regions_from_selection_and_entered ();
3443 begin_reversible_command (str);
3445 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
3446 RegionView* rv = (*x);
3448 /* require region to span proposed trim */
3449 switch (rv->region()->coverage (loc.start(), loc.end())) {
3450 case Evoral::OverlapInternal:
3456 RouteTimeAxisView* tav = dynamic_cast<RouteTimeAxisView*> (&rv->get_time_axis_view());
3465 if (tav->track() != 0) {
3466 speed = tav->track()->speed();
3469 start = session_frame_to_track_frame (loc.start(), speed);
3470 end = session_frame_to_track_frame (loc.end(), speed);
3472 rv->region()->clear_changes ();
3473 rv->region()->trim_to (start, (end - start));
3474 _session->add_command(new StatefulDiffCommand (rv->region()));
3477 commit_reversible_command ();
3481 Editor::trim_region_to_previous_region_end ()
3483 return trim_to_region(false);
3487 Editor::trim_region_to_next_region_start ()
3489 return trim_to_region(true);
3493 Editor::trim_to_region(bool forward)
3495 RegionSelection rs = get_regions_from_selection_and_entered ();
3497 begin_reversible_command (_("trim to region"));
3499 boost::shared_ptr<Region> next_region;
3501 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
3503 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*x);
3509 AudioTimeAxisView* atav = dynamic_cast<AudioTimeAxisView*> (&arv->get_time_axis_view());
3517 if (atav->track() != 0) {
3518 speed = atav->track()->speed();
3522 boost::shared_ptr<Region> region = arv->region();
3523 boost::shared_ptr<Playlist> playlist (region->playlist());
3525 region->clear_changes ();
3529 next_region = playlist->find_next_region (region->first_frame(), Start, 1);
3535 region->trim_end((framepos_t) ( (next_region->first_frame() - 1) * speed));
3536 arv->region_changed (PropertyChange (ARDOUR::Properties::length));
3540 next_region = playlist->find_next_region (region->first_frame(), Start, 0);
3546 region->trim_front((framepos_t) ((next_region->last_frame() + 1) * speed));
3548 arv->region_changed (ARDOUR::bounds_change);
3551 _session->add_command(new StatefulDiffCommand (region));
3554 commit_reversible_command ();
3558 Editor::unfreeze_route ()
3560 if (clicked_routeview == 0 || !clicked_routeview->is_track()) {
3564 clicked_routeview->track()->unfreeze ();
3568 Editor::_freeze_thread (void* arg)
3570 return static_cast<Editor*>(arg)->freeze_thread ();
3574 Editor::freeze_thread ()
3576 /* create event pool because we may need to talk to the session */
3577 SessionEvent::create_per_thread_pool ("freeze events", 64);
3578 /* create per-thread buffers for process() tree to use */
3579 clicked_routeview->audio_track()->freeze_me (*current_interthread_info);
3580 current_interthread_info->done = true;
3585 Editor::freeze_route ()
3591 /* stop transport before we start. this is important */
3593 _session->request_transport_speed (0.0);
3595 /* wait for just a little while, because the above call is asynchronous */
3597 Glib::usleep (250000);
3599 if (clicked_routeview == 0 || !clicked_routeview->is_audio_track()) {
3603 if (!clicked_routeview->track()->bounceable (clicked_routeview->track()->main_outs(), true)) {
3605 _("This track/bus cannot be frozen because the signal adds or loses channels before reaching the outputs.\n"
3606 "This is typically caused by plugins that generate stereo output from mono input or vice versa.")
3608 d.set_title (_("Cannot freeze"));
3613 if (clicked_routeview->track()->has_external_redirects()) {
3614 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"
3615 "Freezing will only process the signal as far as the first send/insert/return."),
3616 clicked_routeview->track()->name()), true, MESSAGE_INFO, BUTTONS_NONE, true);
3618 d.add_button (_("Freeze anyway"), Gtk::RESPONSE_OK);
3619 d.add_button (_("Don't freeze"), Gtk::RESPONSE_CANCEL);
3620 d.set_title (_("Freeze Limits"));
3622 int response = d.run ();
3625 case Gtk::RESPONSE_CANCEL:
3632 InterThreadInfo itt;
3633 current_interthread_info = &itt;
3635 InterthreadProgressWindow ipw (current_interthread_info, _("Freeze"), _("Cancel Freeze"));
3637 pthread_create_and_store (X_("freezer"), &itt.thread, _freeze_thread, this);
3639 set_canvas_cursor (_cursors->wait);
3641 while (!itt.done && !itt.cancel) {
3642 gtk_main_iteration ();
3645 current_interthread_info = 0;
3646 set_canvas_cursor (current_canvas_cursor);
3650 Editor::bounce_range_selection (bool replace, bool enable_processing)
3652 if (selection->time.empty()) {
3656 TrackSelection views = selection->tracks;
3658 for (TrackViewList::iterator i = views.begin(); i != views.end(); ++i) {
3660 if (enable_processing) {
3662 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*i);
3664 if (rtv && rtv->track() && replace && enable_processing && !rtv->track()->bounceable (rtv->track()->main_outs(), false)) {
3666 _("You can't perform this operation because the processing of the signal "
3667 "will cause one or more of the tracks to end up with a region with more channels than this track has inputs.\n\n"
3668 "You can do this without processing, which is a different operation.")
3670 d.set_title (_("Cannot bounce"));
3677 framepos_t start = selection->time[clicked_selection].start;
3678 framepos_t end = selection->time[clicked_selection].end;
3679 framepos_t cnt = end - start + 1;
3681 begin_reversible_command (_("bounce range"));
3683 for (TrackViewList::iterator i = views.begin(); i != views.end(); ++i) {
3685 RouteTimeAxisView* rtv;
3687 if ((rtv = dynamic_cast<RouteTimeAxisView*> (*i)) == 0) {
3691 boost::shared_ptr<Playlist> playlist;
3693 if ((playlist = rtv->playlist()) == 0) {
3697 InterThreadInfo itt;
3699 playlist->clear_changes ();
3700 playlist->clear_owned_changes ();
3702 boost::shared_ptr<Region> r;
3704 if (enable_processing) {
3705 r = rtv->track()->bounce_range (start, start+cnt, itt, rtv->track()->main_outs(), false);
3707 r = rtv->track()->bounce_range (start, start+cnt, itt, boost::shared_ptr<Processor>(), false);
3715 list<AudioRange> ranges;
3716 ranges.push_back (AudioRange (start, start+cnt, 0));
3717 playlist->cut (ranges); // discard result
3718 playlist->add_region (r, start);
3721 vector<Command*> cmds;
3722 playlist->rdiff (cmds);
3723 _session->add_commands (cmds);
3725 _session->add_command (new StatefulDiffCommand (playlist));
3728 commit_reversible_command ();
3731 /** Delete selected regions, automation points or a time range */
3735 //special case: if the user is pointing in the editor/mixer strip, they may be trying to delete a plugin.
3736 //we need this because the editor-mixer strip is in the editor window, so it doesn't get the bindings from the mix window
3737 //TODO: perhaps someday we need to accomodate the other bindings such as mute, solo, etc.
3738 if ( current_mixer_strip && current_mixer_strip->is_selected() )
3739 current_mixer_strip->delete_processors ();
3744 /** Cut selected regions, automation points or a time range */
3751 /** Copy selected regions, automation points or a time range */
3759 /** @return true if a Cut, Copy or Clear is possible */
3761 Editor::can_cut_copy () const
3763 if (!selection->time.empty() || !selection->regions.empty() || !selection->points.empty())
3770 /** Cut, copy or clear selected regions, automation points or a time range.
3771 * @param op Operation (Delete, Cut, Copy or Clear)
3774 Editor::cut_copy (CutCopyOp op)
3776 /* only cancel selection if cut/copy is successful.*/
3782 opname = _("delete");
3791 opname = _("clear");
3795 /* if we're deleting something, and the mouse is still pressed,
3796 the thing we started a drag for will be gone when we release
3797 the mouse button(s). avoid this. see part 2 at the end of
3801 if (op == Delete || op == Cut || op == Clear) {
3802 if (_drags->active ()) {
3807 if ( op != Delete ) //"Delete" doesn't change copy/paste buf
3808 cut_buffer->clear ();
3810 if (entered_marker) {
3812 /* cut/delete op while pointing at a marker */
3815 Location* loc = find_location_from_marker (entered_marker, ignored);
3817 if (_session && loc) {
3818 Glib::signal_idle().connect (sigc::bind (sigc::mem_fun(*this, &Editor::really_remove_marker), loc));
3825 if (internal_editing()) {
3827 switch (effective_mouse_mode()) {
3830 begin_reversible_command (opname + ' ' + X_("MIDI"));
3832 commit_reversible_command ();
3841 bool did_edit = false;
3843 if (!selection->points.empty()) {
3844 begin_reversible_command (opname + _(" points"));
3846 cut_copy_points (op);
3847 if (op == Cut || op == Delete) {
3848 selection->clear_points ();
3850 } else if (!selection->regions.empty() || !selection->points.empty()) {
3854 if (selection->regions.empty()) {
3855 thing_name = _("points");
3856 } else if (selection->points.empty()) {
3857 thing_name = _("regions");
3859 thing_name = _("objects");
3862 begin_reversible_command (opname + ' ' + thing_name);
3865 if (!selection->regions.empty()) {
3866 cut_copy_regions (op, selection->regions);
3868 if (op == Cut || op == Delete) {
3869 selection->clear_regions ();
3873 if (!selection->points.empty()) {
3874 cut_copy_points (op);
3876 if (op == Cut || op == Delete) {
3877 selection->clear_points ();
3880 } else if (selection->time.empty()) {
3881 framepos_t start, end;
3882 /* no time selection, see if we can get an edit range
3885 if (get_edit_op_range (start, end)) {
3886 selection->set (start, end);
3888 } else if (!selection->time.empty()) {
3889 begin_reversible_command (opname + _(" range"));
3892 cut_copy_ranges (op);
3894 if (op == Cut || op == Delete) {
3895 selection->clear_time ();
3900 commit_reversible_command ();
3903 if (op == Delete || op == Cut || op == Clear) {
3908 struct AutomationRecord {
3909 AutomationRecord () : state (0) {}
3910 AutomationRecord (XMLNode* s) : state (s) {}
3912 XMLNode* state; ///< state before any operation
3913 boost::shared_ptr<Evoral::ControlList> copy; ///< copied events for the cut buffer
3916 /** Cut, copy or clear selected automation points.
3917 * @param op Operation (Cut, Copy or Clear)
3920 Editor::cut_copy_points (CutCopyOp op)
3922 if (selection->points.empty ()) {
3926 /* XXX: not ideal, as there may be more than one track involved in the point selection */
3927 _last_cut_copy_source_track = &selection->points.front()->line().trackview;
3929 /* Keep a record of the AutomationLists that we end up using in this operation */
3930 typedef std::map<boost::shared_ptr<AutomationList>, AutomationRecord> Lists;
3933 /* Go through all selected points, making an AutomationRecord for each distinct AutomationList */
3934 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
3935 boost::shared_ptr<AutomationList> al = (*i)->line().the_list();
3936 if (lists.find (al) == lists.end ()) {
3937 /* We haven't seen this list yet, so make a record for it. This includes
3938 taking a copy of its current state, in case this is needed for undo later.
3940 lists[al] = AutomationRecord (&al->get_state ());
3944 if (op == Cut || op == Copy) {
3945 /* This operation will involve putting things in the cut buffer, so create an empty
3946 ControlList for each of our source lists to put the cut buffer data in.
3948 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
3949 i->second.copy = i->first->create (i->first->parameter ());
3952 /* Add all selected points to the relevant copy ControlLists */
3953 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
3954 boost::shared_ptr<AutomationList> al = (*i)->line().the_list();
3955 AutomationList::const_iterator j = (*i)->model ();
3956 lists[al].copy->add ((*j)->when, (*j)->value);
3959 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
3960 /* Correct this copy list so that it starts at time 0 */
3961 double const start = i->second.copy->front()->when;
3962 for (AutomationList::iterator j = i->second.copy->begin(); j != i->second.copy->end(); ++j) {
3963 (*j)->when -= start;
3966 /* And add it to the cut buffer */
3967 cut_buffer->add (i->second.copy);
3971 if (op == Delete || op == Cut) {
3972 /* This operation needs to remove things from the main AutomationList, so do that now */
3974 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
3975 i->first->freeze ();
3978 /* Remove each selected point from its AutomationList */
3979 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
3980 boost::shared_ptr<AutomationList> al = (*i)->line().the_list();
3981 al->erase ((*i)->model ());
3984 /* Thaw the lists and add undo records for them */
3985 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
3986 boost::shared_ptr<AutomationList> al = i->first;
3988 _session->add_command (new MementoCommand<AutomationList> (*al.get(), i->second.state, &(al->get_state ())));
3993 /** Cut, copy or clear selected automation points.
3994 * @param op Operation (Cut, Copy or Clear)
3997 Editor::cut_copy_midi (CutCopyOp op)
3999 for (MidiRegionSelection::iterator i = selection->midi_regions.begin(); i != selection->midi_regions.end(); ++i) {
4000 MidiRegionView* mrv = *i;
4001 mrv->cut_copy_clear (op);
4007 struct lt_playlist {
4008 bool operator () (const PlaylistState& a, const PlaylistState& b) {
4009 return a.playlist < b.playlist;
4013 struct PlaylistMapping {
4015 boost::shared_ptr<Playlist> pl;
4017 PlaylistMapping (TimeAxisView* tvp) : tv (tvp) {}
4020 /** Remove `clicked_regionview' */
4022 Editor::remove_clicked_region ()
4024 if (clicked_routeview == 0 || clicked_regionview == 0) {
4028 boost::shared_ptr<Playlist> playlist = clicked_routeview->playlist();
4030 playlist->clear_changes ();
4031 playlist->clear_owned_changes ();
4032 playlist->remove_region (clicked_regionview->region());
4033 if (Config->get_edit_mode() == Ripple)
4034 playlist->ripple (clicked_regionview->region()->position(), -clicked_regionview->region()->length(), boost::shared_ptr<Region>());
4036 /* We might have removed regions, which alters other regions' layering_index,
4037 so we need to do a recursive diff here.
4039 vector<Command*> cmds;
4040 playlist->rdiff (cmds);
4041 _session->add_commands (cmds);
4043 _session->add_command(new StatefulDiffCommand (playlist));
4044 commit_reversible_command ();
4048 /** Remove the selected regions */
4050 Editor::remove_selected_regions ()
4052 RegionSelection rs = get_regions_from_selection_and_entered ();
4054 if (!_session || rs.empty()) {
4058 begin_reversible_command (_("remove region"));
4060 list<boost::shared_ptr<Region> > regions_to_remove;
4062 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
4063 // we can't just remove the region(s) in this loop because
4064 // this removes them from the RegionSelection, and they thus
4065 // disappear from underneath the iterator, and the ++i above
4066 // SEGVs in a puzzling fashion.
4068 // so, first iterate over the regions to be removed from rs and
4069 // add them to the regions_to_remove list, and then
4070 // iterate over the list to actually remove them.
4072 regions_to_remove.push_back ((*i)->region());
4075 vector<boost::shared_ptr<Playlist> > playlists;
4077 for (list<boost::shared_ptr<Region> >::iterator rl = regions_to_remove.begin(); rl != regions_to_remove.end(); ++rl) {
4079 boost::shared_ptr<Playlist> playlist = (*rl)->playlist();
4082 // is this check necessary?
4086 /* get_regions_from_selection_and_entered() guarantees that
4087 the playlists involved are unique, so there is no need
4091 playlists.push_back (playlist);
4093 playlist->clear_changes ();
4094 playlist->clear_owned_changes ();
4095 playlist->freeze ();
4096 playlist->remove_region (*rl);
4097 if (Config->get_edit_mode() == Ripple)
4098 playlist->ripple ((*rl)->position(), -(*rl)->length(), boost::shared_ptr<Region>());
4102 vector<boost::shared_ptr<Playlist> >::iterator pl;
4104 for (pl = playlists.begin(); pl != playlists.end(); ++pl) {
4107 /* We might have removed regions, which alters other regions' layering_index,
4108 so we need to do a recursive diff here.
4110 vector<Command*> cmds;
4111 (*pl)->rdiff (cmds);
4112 _session->add_commands (cmds);
4114 _session->add_command(new StatefulDiffCommand (*pl));
4117 commit_reversible_command ();
4120 /** Cut, copy or clear selected regions.
4121 * @param op Operation (Cut, Copy or Clear)
4124 Editor::cut_copy_regions (CutCopyOp op, RegionSelection& rs)
4126 /* we can't use a std::map here because the ordering is important, and we can't trivially sort
4127 a map when we want ordered access to both elements. i think.
4130 vector<PlaylistMapping> pmap;
4132 framepos_t first_position = max_framepos;
4134 typedef set<boost::shared_ptr<Playlist> > FreezeList;
4135 FreezeList freezelist;
4137 /* get ordering correct before we cut/copy */
4139 rs.sort_by_position_and_track ();
4141 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
4143 first_position = min ((framepos_t) (*x)->region()->position(), first_position);
4145 if (op == Cut || op == Clear || op == Delete) {
4146 boost::shared_ptr<Playlist> pl = (*x)->region()->playlist();
4149 FreezeList::iterator fl;
4151 // only take state if this is a new playlist.
4152 for (fl = freezelist.begin(); fl != freezelist.end(); ++fl) {
4158 if (fl == freezelist.end()) {
4159 pl->clear_changes();
4160 pl->clear_owned_changes ();
4162 freezelist.insert (pl);
4167 TimeAxisView* tv = &(*x)->get_time_axis_view();
4168 vector<PlaylistMapping>::iterator z;
4170 for (z = pmap.begin(); z != pmap.end(); ++z) {
4171 if ((*z).tv == tv) {
4176 if (z == pmap.end()) {
4177 pmap.push_back (PlaylistMapping (tv));
4181 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ) {
4183 boost::shared_ptr<Playlist> pl = (*x)->region()->playlist();
4186 /* region not yet associated with a playlist (e.g. unfinished
4193 TimeAxisView& tv = (*x)->get_time_axis_view();
4194 boost::shared_ptr<Playlist> npl;
4195 RegionSelection::iterator tmp;
4202 vector<PlaylistMapping>::iterator z;
4204 for (z = pmap.begin(); z != pmap.end(); ++z) {
4205 if ((*z).tv == &tv) {
4210 assert (z != pmap.end());
4213 npl = PlaylistFactory::create (pl->data_type(), *_session, "cutlist", true);
4221 boost::shared_ptr<Region> r = (*x)->region();
4222 boost::shared_ptr<Region> _xx;
4228 pl->remove_region (r);
4229 if (Config->get_edit_mode() == Ripple)
4230 pl->ripple (r->position(), -r->length(), boost::shared_ptr<Region>());
4234 _xx = RegionFactory::create (r);
4235 npl->add_region (_xx, r->position() - first_position);
4236 pl->remove_region (r);
4237 if (Config->get_edit_mode() == Ripple)
4238 pl->ripple (r->position(), -r->length(), boost::shared_ptr<Region>());
4242 /* copy region before adding, so we're not putting same object into two different playlists */
4243 npl->add_region (RegionFactory::create (r), r->position() - first_position);
4247 pl->remove_region (r);
4248 if (Config->get_edit_mode() == Ripple)
4249 pl->ripple (r->position(), -r->length(), boost::shared_ptr<Region>());
4258 list<boost::shared_ptr<Playlist> > foo;
4260 /* the pmap is in the same order as the tracks in which selected regions occured */
4262 for (vector<PlaylistMapping>::iterator i = pmap.begin(); i != pmap.end(); ++i) {
4265 foo.push_back ((*i).pl);
4270 cut_buffer->set (foo);
4274 _last_cut_copy_source_track = 0;
4276 _last_cut_copy_source_track = pmap.front().tv;
4280 for (FreezeList::iterator pl = freezelist.begin(); pl != freezelist.end(); ++pl) {
4283 /* We might have removed regions, which alters other regions' layering_index,
4284 so we need to do a recursive diff here.
4286 vector<Command*> cmds;
4287 (*pl)->rdiff (cmds);
4288 _session->add_commands (cmds);
4290 _session->add_command (new StatefulDiffCommand (*pl));
4295 Editor::cut_copy_ranges (CutCopyOp op)
4297 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4299 /* Sort the track selection now, so that it if is used, the playlists
4300 selected by the calls below to cut_copy_clear are in the order that
4301 their tracks appear in the editor. This makes things like paste
4302 of ranges work properly.
4305 sort_track_selection (ts);
4308 if (!entered_track) {
4311 ts.push_back (entered_track);
4314 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4315 (*i)->cut_copy_clear (*selection, op);
4320 Editor::paste (float times, bool from_context)
4322 DEBUG_TRACE (DEBUG::CutNPaste, "paste to preferred edit pos\n");
4324 paste_internal (get_preferred_edit_position (false, from_context), times);
4328 Editor::mouse_paste ()
4333 if (!mouse_frame (where, ignored)) {
4338 paste_internal (where, 1);
4342 Editor::paste_internal (framepos_t position, float times)
4344 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("apparent paste position is %1\n", position));
4346 if (internal_editing()) {
4347 if (cut_buffer->midi_notes.empty()) {
4351 if (cut_buffer->empty()) {
4356 if (position == max_framepos) {
4357 position = get_preferred_edit_position();
4358 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("preferred edit position is %1\n", position));
4362 TrackViewList::iterator i;
4365 /* get everything in the correct order */
4367 if (_edit_point == Editing::EditAtMouse && entered_track) {
4368 /* With the mouse edit point, paste onto the track under the mouse */
4369 ts.push_back (entered_track);
4370 } else if (!selection->tracks.empty()) {
4371 /* Otherwise, if there are some selected tracks, paste to them */
4372 ts = selection->tracks.filter_to_unique_playlists ();
4373 sort_track_selection (ts);
4374 } else if (_last_cut_copy_source_track) {
4375 /* Otherwise paste to the track that the cut/copy came from;
4376 see discussion in mantis #3333.
4378 ts.push_back (_last_cut_copy_source_track);
4381 if (internal_editing ()) {
4383 /* undo/redo is handled by individual tracks/regions */
4385 for (nth = 0, i = ts.begin(); i != ts.end(); ++i, ++nth) {
4388 RegionSelection::iterator r;
4389 MidiNoteSelection::iterator cb;
4391 get_regions_at (rs, position, ts);
4393 for (cb = cut_buffer->midi_notes.begin(), r = rs.begin();
4394 cb != cut_buffer->midi_notes.end() && r != rs.end(); ++r) {
4395 MidiRegionView* mrv = dynamic_cast<MidiRegionView*> (*r);
4397 mrv->paste (position, times, **cb);
4405 /* we do redo (do you do voodoo?) */
4407 begin_reversible_command (Operations::paste);
4409 for (nth = 0, i = ts.begin(); i != ts.end(); ++i, ++nth) {
4410 (*i)->paste (position, times, *cut_buffer, nth);
4413 commit_reversible_command ();
4418 Editor::duplicate_some_regions (RegionSelection& regions, float times)
4420 boost::shared_ptr<Playlist> playlist;
4421 RegionSelection sel = regions; // clear (below) may clear the argument list if its the current region selection
4422 RegionSelection foo;
4424 framepos_t const start_frame = regions.start ();
4425 framepos_t const end_frame = regions.end_frame ();
4427 begin_reversible_command (Operations::duplicate_region);
4429 selection->clear_regions ();
4431 for (RegionSelection::iterator i = sel.begin(); i != sel.end(); ++i) {
4433 boost::shared_ptr<Region> r ((*i)->region());
4435 TimeAxisView& tv = (*i)->get_time_axis_view();
4436 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (&tv);
4437 latest_regionviews.clear ();
4438 sigc::connection c = rtv->view()->RegionViewAdded.connect (sigc::mem_fun(*this, &Editor::collect_new_region_view));
4440 playlist = (*i)->region()->playlist();
4441 playlist->clear_changes ();
4442 playlist->duplicate (r, end_frame + (r->first_frame() - start_frame), times);
4443 _session->add_command(new StatefulDiffCommand (playlist));
4447 foo.insert (foo.end(), latest_regionviews.begin(), latest_regionviews.end());
4450 commit_reversible_command ();
4453 selection->set (foo);
4458 Editor::duplicate_selection (float times)
4460 if (selection->time.empty() || selection->tracks.empty()) {
4464 boost::shared_ptr<Playlist> playlist;
4465 vector<boost::shared_ptr<Region> > new_regions;
4466 vector<boost::shared_ptr<Region> >::iterator ri;
4468 create_region_from_selection (new_regions);
4470 if (new_regions.empty()) {
4474 begin_reversible_command (_("duplicate selection"));
4476 ri = new_regions.begin();
4478 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4480 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4481 if ((playlist = (*i)->playlist()) == 0) {
4484 playlist->clear_changes ();
4485 playlist->duplicate (*ri, selection->time[clicked_selection].end, times);
4486 _session->add_command (new StatefulDiffCommand (playlist));
4489 if (ri == new_regions.end()) {
4494 commit_reversible_command ();
4497 /** Reset all selected points to the relevant default value */
4499 Editor::reset_point_selection ()
4501 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
4502 ARDOUR::AutomationList::iterator j = (*i)->model ();
4503 (*j)->value = (*i)->line().the_list()->default_value ();
4508 Editor::center_playhead ()
4510 float const page = _visible_canvas_width * samples_per_pixel;
4511 center_screen_internal (playhead_cursor->current_frame (), page);
4515 Editor::center_edit_point ()
4517 float const page = _visible_canvas_width * samples_per_pixel;
4518 center_screen_internal (get_preferred_edit_position(), page);
4521 /** Caller must begin and commit a reversible command */
4523 Editor::clear_playlist (boost::shared_ptr<Playlist> playlist)
4525 playlist->clear_changes ();
4527 _session->add_command (new StatefulDiffCommand (playlist));
4531 Editor::nudge_track (bool use_edit, bool forwards)
4533 boost::shared_ptr<Playlist> playlist;
4534 framepos_t distance;
4535 framepos_t next_distance;
4539 start = get_preferred_edit_position();
4544 if ((distance = get_nudge_distance (start, next_distance)) == 0) {
4548 if (selection->tracks.empty()) {
4552 begin_reversible_command (_("nudge track"));
4554 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4556 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4558 if ((playlist = (*i)->playlist()) == 0) {
4562 playlist->clear_changes ();
4563 playlist->clear_owned_changes ();
4565 playlist->nudge_after (start, distance, forwards);
4567 vector<Command*> cmds;
4569 playlist->rdiff (cmds);
4570 _session->add_commands (cmds);
4572 _session->add_command (new StatefulDiffCommand (playlist));
4575 commit_reversible_command ();
4579 Editor::remove_last_capture ()
4581 vector<string> choices;
4588 if (Config->get_verify_remove_last_capture()) {
4589 prompt = _("Do you really want to destroy the last capture?"
4590 "\n(This is destructive and cannot be undone)");
4592 choices.push_back (_("No, do nothing."));
4593 choices.push_back (_("Yes, destroy it."));
4595 Gtkmm2ext::Choice prompter (_("Destroy last capture"), prompt, choices);
4597 if (prompter.run () == 1) {
4598 _session->remove_last_capture ();
4599 _regions->redisplay ();
4603 _session->remove_last_capture();
4604 _regions->redisplay ();
4609 Editor::normalize_region ()
4615 RegionSelection rs = get_regions_from_selection_and_entered ();
4621 NormalizeDialog dialog (rs.size() > 1);
4623 if (dialog.run () == RESPONSE_CANCEL) {
4627 set_canvas_cursor (_cursors->wait);
4630 /* XXX: should really only count audio regions here */
4631 int const regions = rs.size ();
4633 /* Make a list of the selected audio regions' maximum amplitudes, and also
4634 obtain the maximum amplitude of them all.
4636 list<double> max_amps;
4638 for (RegionSelection::const_iterator i = rs.begin(); i != rs.end(); ++i) {
4639 AudioRegionView const * arv = dynamic_cast<AudioRegionView const *> (*i);
4641 dialog.descend (1.0 / regions);
4642 double const a = arv->audio_region()->maximum_amplitude (&dialog);
4645 /* the user cancelled the operation */
4646 set_canvas_cursor (current_canvas_cursor);
4650 max_amps.push_back (a);
4651 max_amp = max (max_amp, a);
4656 begin_reversible_command (_("normalize"));
4658 list<double>::const_iterator a = max_amps.begin ();
4660 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
4661 AudioRegionView* const arv = dynamic_cast<AudioRegionView*> (*r);
4666 arv->region()->clear_changes ();
4668 double const amp = dialog.normalize_individually() ? *a : max_amp;
4670 arv->audio_region()->normalize (amp, dialog.target ());
4671 _session->add_command (new StatefulDiffCommand (arv->region()));
4676 commit_reversible_command ();
4677 set_canvas_cursor (current_canvas_cursor);
4682 Editor::reset_region_scale_amplitude ()
4688 RegionSelection rs = get_regions_from_selection_and_entered ();
4694 begin_reversible_command ("reset gain");
4696 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
4697 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
4700 arv->region()->clear_changes ();
4701 arv->audio_region()->set_scale_amplitude (1.0f);
4702 _session->add_command (new StatefulDiffCommand (arv->region()));
4705 commit_reversible_command ();
4709 Editor::adjust_region_gain (bool up)
4711 RegionSelection rs = get_regions_from_selection_and_entered ();
4713 if (!_session || rs.empty()) {
4717 begin_reversible_command ("adjust region gain");
4719 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
4720 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
4725 arv->region()->clear_changes ();
4727 double dB = accurate_coefficient_to_dB (arv->audio_region()->scale_amplitude ());
4735 arv->audio_region()->set_scale_amplitude (dB_to_coefficient (dB));
4736 _session->add_command (new StatefulDiffCommand (arv->region()));
4739 commit_reversible_command ();
4744 Editor::reverse_region ()
4750 Reverse rev (*_session);
4751 apply_filter (rev, _("reverse regions"));
4755 Editor::strip_region_silence ()
4761 RegionSelection rs = get_regions_from_selection_and_entered ();
4767 std::list<RegionView*> audio_only;
4769 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
4770 AudioRegionView* const arv = dynamic_cast<AudioRegionView*> (*i);
4772 audio_only.push_back (arv);
4776 StripSilenceDialog d (_session, audio_only);
4777 int const r = d.run ();
4781 if (r == Gtk::RESPONSE_OK) {
4782 ARDOUR::AudioIntervalMap silences;
4783 d.silences (silences);
4784 StripSilence s (*_session, silences, d.fade_length());
4785 apply_filter (s, _("strip silence"), &d);
4790 Editor::apply_midi_note_edit_op_to_region (MidiOperator& op, MidiRegionView& mrv)
4792 Evoral::Sequence<Evoral::MusicalTime>::Notes selected;
4793 mrv.selection_as_notelist (selected, true);
4795 vector<Evoral::Sequence<Evoral::MusicalTime>::Notes> v;
4796 v.push_back (selected);
4798 framepos_t pos_frames = mrv.midi_region()->position() - mrv.midi_region()->start();
4799 double pos_beats = _session->tempo_map().framewalk_to_beats(0, pos_frames);
4801 return op (mrv.midi_region()->model(), pos_beats, v);
4805 Editor::apply_midi_note_edit_op (MidiOperator& op)
4809 RegionSelection rs = get_regions_from_selection_and_entered ();
4815 begin_reversible_command (op.name ());
4817 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
4818 RegionSelection::iterator tmp = r;
4821 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*r);
4824 cmd = apply_midi_note_edit_op_to_region (op, *mrv);
4827 _session->add_command (cmd);
4834 commit_reversible_command ();
4838 Editor::fork_region ()
4840 RegionSelection rs = get_regions_from_selection_and_entered ();
4846 begin_reversible_command (_("Fork Region(s)"));
4848 set_canvas_cursor (_cursors->wait);
4851 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
4852 RegionSelection::iterator tmp = r;
4855 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*>(*r);
4859 boost::shared_ptr<Playlist> playlist = mrv->region()->playlist();
4860 boost::shared_ptr<MidiSource> new_source = _session->create_midi_source_by_stealing_name (mrv->midi_view()->track());
4861 boost::shared_ptr<MidiRegion> newregion = mrv->midi_region()->clone (new_source);
4863 playlist->clear_changes ();
4864 playlist->replace_region (mrv->region(), newregion, mrv->region()->position());
4865 _session->add_command(new StatefulDiffCommand (playlist));
4867 error << string_compose (_("Could not unlink %1"), mrv->region()->name()) << endmsg;
4874 commit_reversible_command ();
4876 set_canvas_cursor (current_canvas_cursor);
4880 Editor::quantize_region ()
4882 int selected_midi_region_cnt = 0;
4888 RegionSelection rs = get_regions_from_selection_and_entered ();
4894 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
4895 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*r);
4897 selected_midi_region_cnt++;
4901 if (selected_midi_region_cnt == 0) {
4905 QuantizeDialog* qd = new QuantizeDialog (*this);
4908 const int r = qd->run ();
4911 if (r == Gtk::RESPONSE_OK) {
4912 Quantize quant (*_session, qd->snap_start(), qd->snap_end(),
4913 qd->start_grid_size(), qd->end_grid_size(),
4914 qd->strength(), qd->swing(), qd->threshold());
4916 apply_midi_note_edit_op (quant);
4921 Editor::insert_patch_change (bool from_context)
4923 RegionSelection rs = get_regions_from_selection_and_entered ();
4929 const framepos_t p = get_preferred_edit_position (false, from_context);
4931 /* XXX: bit of a hack; use the MIDNAM from the first selected region;
4932 there may be more than one, but the PatchChangeDialog can only offer
4933 one set of patch menus.
4935 MidiRegionView* first = dynamic_cast<MidiRegionView*> (rs.front ());
4937 Evoral::PatchChange<Evoral::MusicalTime> empty (0, 0, 0, 0);
4938 PatchChangeDialog d (0, _session, empty, first->instrument_info(), Gtk::Stock::ADD);
4940 if (d.run() == RESPONSE_CANCEL) {
4944 for (RegionSelection::iterator i = rs.begin (); i != rs.end(); ++i) {
4945 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*i);
4947 if (p >= mrv->region()->first_frame() && p <= mrv->region()->last_frame()) {
4948 mrv->add_patch_change (p - mrv->region()->position(), d.patch ());
4955 Editor::apply_filter (Filter& filter, string command, ProgressReporter* progress)
4957 RegionSelection rs = get_regions_from_selection_and_entered ();
4963 begin_reversible_command (command);
4965 set_canvas_cursor (_cursors->wait);
4969 int const N = rs.size ();
4971 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
4972 RegionSelection::iterator tmp = r;
4975 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
4977 boost::shared_ptr<Playlist> playlist = arv->region()->playlist();
4980 progress->descend (1.0 / N);
4983 if (arv->audio_region()->apply (filter, progress) == 0) {
4985 playlist->clear_changes ();
4986 playlist->clear_owned_changes ();
4988 if (filter.results.empty ()) {
4990 /* no regions returned; remove the old one */
4991 playlist->remove_region (arv->region ());
4995 std::vector<boost::shared_ptr<Region> >::iterator res = filter.results.begin ();
4997 /* first region replaces the old one */
4998 playlist->replace_region (arv->region(), *res, (*res)->position());
5002 while (res != filter.results.end()) {
5003 playlist->add_region (*res, (*res)->position());
5009 /* We might have removed regions, which alters other regions' layering_index,
5010 so we need to do a recursive diff here.
5012 vector<Command*> cmds;
5013 playlist->rdiff (cmds);
5014 _session->add_commands (cmds);
5016 _session->add_command(new StatefulDiffCommand (playlist));
5022 progress->ascend ();
5030 commit_reversible_command ();
5033 set_canvas_cursor (current_canvas_cursor);
5037 Editor::external_edit_region ()
5043 Editor::reset_region_gain_envelopes ()
5045 RegionSelection rs = get_regions_from_selection_and_entered ();
5047 if (!_session || rs.empty()) {
5051 _session->begin_reversible_command (_("reset region gain"));
5053 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5054 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
5056 boost::shared_ptr<AutomationList> alist (arv->audio_region()->envelope());
5057 XMLNode& before (alist->get_state());
5059 arv->audio_region()->set_default_envelope ();
5060 _session->add_command (new MementoCommand<AutomationList>(*arv->audio_region()->envelope().get(), &before, &alist->get_state()));
5064 _session->commit_reversible_command ();
5068 Editor::set_region_gain_visibility (RegionView* rv)
5070 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (rv);
5072 arv->update_envelope_visibility();
5077 Editor::set_gain_envelope_visibility ()
5083 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5084 AudioTimeAxisView* v = dynamic_cast<AudioTimeAxisView*>(*i);
5086 v->audio_view()->foreach_regionview (sigc::mem_fun (this, &Editor::set_region_gain_visibility));
5092 Editor::toggle_gain_envelope_active ()
5094 if (_ignore_region_action) {
5098 RegionSelection rs = get_regions_from_selection_and_entered ();
5100 if (!_session || rs.empty()) {
5104 _session->begin_reversible_command (_("region gain envelope active"));
5106 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5107 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
5109 arv->region()->clear_changes ();
5110 arv->audio_region()->set_envelope_active (!arv->audio_region()->envelope_active());
5111 _session->add_command (new StatefulDiffCommand (arv->region()));
5115 _session->commit_reversible_command ();
5119 Editor::toggle_region_lock ()
5121 if (_ignore_region_action) {
5125 RegionSelection rs = get_regions_from_selection_and_entered ();
5127 if (!_session || rs.empty()) {
5131 _session->begin_reversible_command (_("toggle region lock"));
5133 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5134 (*i)->region()->clear_changes ();
5135 (*i)->region()->set_locked (!(*i)->region()->locked());
5136 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5139 _session->commit_reversible_command ();
5143 Editor::toggle_region_video_lock ()
5145 if (_ignore_region_action) {
5149 RegionSelection rs = get_regions_from_selection_and_entered ();
5151 if (!_session || rs.empty()) {
5155 _session->begin_reversible_command (_("Toggle Video Lock"));
5157 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5158 (*i)->region()->clear_changes ();
5159 (*i)->region()->set_video_locked (!(*i)->region()->video_locked());
5160 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5163 _session->commit_reversible_command ();
5167 Editor::toggle_region_lock_style ()
5169 if (_ignore_region_action) {
5173 RegionSelection rs = get_regions_from_selection_and_entered ();
5175 if (!_session || rs.empty()) {
5179 _session->begin_reversible_command (_("region lock style"));
5181 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5182 (*i)->region()->clear_changes ();
5183 PositionLockStyle const ns = (*i)->region()->position_lock_style() == AudioTime ? MusicTime : AudioTime;
5184 (*i)->region()->set_position_lock_style (ns);
5185 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5188 _session->commit_reversible_command ();
5192 Editor::toggle_opaque_region ()
5194 if (_ignore_region_action) {
5198 RegionSelection rs = get_regions_from_selection_and_entered ();
5200 if (!_session || rs.empty()) {
5204 _session->begin_reversible_command (_("change region opacity"));
5206 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5207 (*i)->region()->clear_changes ();
5208 (*i)->region()->set_opaque (!(*i)->region()->opaque());
5209 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5212 _session->commit_reversible_command ();
5216 Editor::toggle_record_enable ()
5218 bool new_state = false;
5220 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5221 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5224 if (!rtav->is_track())
5228 new_state = !rtav->track()->record_enabled();
5232 rtav->track()->set_record_enabled (new_state, this);
5237 Editor::toggle_solo ()
5239 bool new_state = false;
5241 boost::shared_ptr<RouteList> rl (new RouteList);
5243 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5244 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5251 new_state = !rtav->route()->soloed ();
5255 rl->push_back (rtav->route());
5258 _session->set_solo (rl, new_state, Session::rt_cleanup, true);
5262 Editor::toggle_mute ()
5264 bool new_state = false;
5266 boost::shared_ptr<RouteList> rl (new RouteList);
5268 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5269 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5276 new_state = !rtav->route()->muted();
5280 rl->push_back (rtav->route());
5283 _session->set_mute (rl, new_state, Session::rt_cleanup, true);
5287 Editor::toggle_solo_isolate ()
5293 Editor::fade_range ()
5295 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
5297 begin_reversible_command (_("fade range"));
5299 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
5300 (*i)->fade_range (selection->time);
5303 commit_reversible_command ();
5308 Editor::set_fade_length (bool in)
5310 RegionSelection rs = get_regions_from_selection_and_entered ();
5316 /* we need a region to measure the offset from the start */
5318 RegionView* rv = rs.front ();
5320 framepos_t pos = get_preferred_edit_position();
5324 if (pos > rv->region()->last_frame() || pos < rv->region()->first_frame()) {
5325 /* edit point is outside the relevant region */
5330 if (pos <= rv->region()->position()) {
5334 len = pos - rv->region()->position();
5335 cmd = _("set fade in length");
5337 if (pos >= rv->region()->last_frame()) {
5341 len = rv->region()->last_frame() - pos;
5342 cmd = _("set fade out length");
5345 begin_reversible_command (cmd);
5347 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5348 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5354 boost::shared_ptr<AutomationList> alist;
5356 alist = tmp->audio_region()->fade_in();
5358 alist = tmp->audio_region()->fade_out();
5361 XMLNode &before = alist->get_state();
5364 tmp->audio_region()->set_fade_in_length (len);
5365 tmp->audio_region()->set_fade_in_active (true);
5367 tmp->audio_region()->set_fade_out_length (len);
5368 tmp->audio_region()->set_fade_out_active (true);
5371 XMLNode &after = alist->get_state();
5372 _session->add_command(new MementoCommand<AutomationList>(*alist, &before, &after));
5375 commit_reversible_command ();
5379 Editor::set_fade_in_shape (FadeShape shape)
5381 RegionSelection rs = get_regions_from_selection_and_entered ();
5387 begin_reversible_command (_("set fade in shape"));
5389 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5390 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5396 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_in();
5397 XMLNode &before = alist->get_state();
5399 tmp->audio_region()->set_fade_in_shape (shape);
5401 XMLNode &after = alist->get_state();
5402 _session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
5405 commit_reversible_command ();
5410 Editor::set_fade_out_shape (FadeShape shape)
5412 RegionSelection rs = get_regions_from_selection_and_entered ();
5418 begin_reversible_command (_("set fade out shape"));
5420 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5421 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5427 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_out();
5428 XMLNode &before = alist->get_state();
5430 tmp->audio_region()->set_fade_out_shape (shape);
5432 XMLNode &after = alist->get_state();
5433 _session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
5436 commit_reversible_command ();
5440 Editor::set_fade_in_active (bool yn)
5442 RegionSelection rs = get_regions_from_selection_and_entered ();
5448 begin_reversible_command (_("set fade in active"));
5450 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5451 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5458 boost::shared_ptr<AudioRegion> ar (tmp->audio_region());
5460 ar->clear_changes ();
5461 ar->set_fade_in_active (yn);
5462 _session->add_command (new StatefulDiffCommand (ar));
5465 commit_reversible_command ();
5469 Editor::set_fade_out_active (bool yn)
5471 RegionSelection rs = get_regions_from_selection_and_entered ();
5477 begin_reversible_command (_("set fade out active"));
5479 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5480 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5486 boost::shared_ptr<AudioRegion> ar (tmp->audio_region());
5488 ar->clear_changes ();
5489 ar->set_fade_out_active (yn);
5490 _session->add_command(new StatefulDiffCommand (ar));
5493 commit_reversible_command ();
5497 Editor::toggle_region_fades (int dir)
5499 if (_ignore_region_action) {
5503 boost::shared_ptr<AudioRegion> ar;
5506 RegionSelection rs = get_regions_from_selection_and_entered ();
5512 RegionSelection::iterator i;
5513 for (i = rs.begin(); i != rs.end(); ++i) {
5514 if ((ar = boost::dynamic_pointer_cast<AudioRegion>((*i)->region())) != 0) {
5516 yn = ar->fade_out_active ();
5518 yn = ar->fade_in_active ();
5524 if (i == rs.end()) {
5528 /* XXX should this undo-able? */
5530 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5531 if ((ar = boost::dynamic_pointer_cast<AudioRegion>((*i)->region())) == 0) {
5534 if (dir == 1 || dir == 0) {
5535 ar->set_fade_in_active (!yn);
5538 if (dir == -1 || dir == 0) {
5539 ar->set_fade_out_active (!yn);
5545 /** Update region fade visibility after its configuration has been changed */
5547 Editor::update_region_fade_visibility ()
5549 bool _fade_visibility = _session->config.get_show_region_fades ();
5551 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5552 AudioTimeAxisView* v = dynamic_cast<AudioTimeAxisView*>(*i);
5554 if (_fade_visibility) {
5555 v->audio_view()->show_all_fades ();
5557 v->audio_view()->hide_all_fades ();
5564 Editor::set_edit_point ()
5569 if (!mouse_frame (where, ignored)) {
5575 if (selection->markers.empty()) {
5577 mouse_add_new_marker (where);
5582 Location* loc = find_location_from_marker (selection->markers.front(), ignored);
5585 loc->move_to (where);
5591 Editor::set_playhead_cursor ()
5593 if (entered_marker) {
5594 _session->request_locate (entered_marker->position(), _session->transport_rolling());
5599 if (!mouse_frame (where, ignored)) {
5606 _session->request_locate (where, _session->transport_rolling());
5610 if ( Config->get_follow_edits() )
5611 cancel_time_selection();
5615 Editor::split_region ()
5617 if ( !selection->time.empty()) {
5618 separate_regions_between (selection->time);
5622 RegionSelection rs = get_regions_from_selection_and_edit_point ();
5624 framepos_t where = get_preferred_edit_position ();
5630 split_regions_at (where, rs);
5633 struct EditorOrderRouteSorter {
5634 bool operator() (boost::shared_ptr<Route> a, boost::shared_ptr<Route> b) {
5635 return a->order_key () < b->order_key ();
5640 Editor::select_next_route()
5642 if (selection->tracks.empty()) {
5643 selection->set (track_views.front());
5647 TimeAxisView* current = selection->tracks.front();
5651 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5652 if (*i == current) {
5654 if (i != track_views.end()) {
5657 current = (*(track_views.begin()));
5658 //selection->set (*(track_views.begin()));
5663 rui = dynamic_cast<RouteUI *>(current);
5664 } while ( current->hidden() || (rui != NULL && !rui->route()->active()));
5666 selection->set(current);
5668 ensure_time_axis_view_is_visible (*current, false);
5672 Editor::select_prev_route()
5674 if (selection->tracks.empty()) {
5675 selection->set (track_views.front());
5679 TimeAxisView* current = selection->tracks.front();
5683 for (TrackViewList::reverse_iterator i = track_views.rbegin(); i != track_views.rend(); ++i) {
5684 if (*i == current) {
5686 if (i != track_views.rend()) {
5689 current = *(track_views.rbegin());
5694 rui = dynamic_cast<RouteUI *>(current);
5695 } while ( current->hidden() || (rui != NULL && !rui->route()->active()));
5697 selection->set (current);
5699 ensure_time_axis_view_is_visible (*current, false);
5703 Editor::set_loop_from_selection (bool play)
5705 if (_session == 0 || selection->time.empty()) {
5709 framepos_t start = selection->time[clicked_selection].start;
5710 framepos_t end = selection->time[clicked_selection].end;
5712 set_loop_range (start, end, _("set loop range from selection"));
5715 _session->request_play_loop (true);
5716 _session->request_locate (start, true);
5721 Editor::set_loop_from_edit_range (bool play)
5723 if (_session == 0) {
5730 if (!get_edit_op_range (start, end)) {
5734 set_loop_range (start, end, _("set loop range from edit range"));
5737 _session->request_play_loop (true);
5738 _session->request_locate (start, true);
5743 Editor::set_loop_from_region (bool play)
5745 framepos_t start = max_framepos;
5748 RegionSelection rs = get_regions_from_selection_and_entered ();
5754 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5755 if ((*i)->region()->position() < start) {
5756 start = (*i)->region()->position();
5758 if ((*i)->region()->last_frame() + 1 > end) {
5759 end = (*i)->region()->last_frame() + 1;
5763 set_loop_range (start, end, _("set loop range from region"));
5766 _session->request_play_loop (true);
5767 _session->request_locate (start, true);
5772 Editor::set_punch_from_selection ()
5774 if (_session == 0 || selection->time.empty()) {
5778 framepos_t start = selection->time[clicked_selection].start;
5779 framepos_t end = selection->time[clicked_selection].end;
5781 set_punch_range (start, end, _("set punch range from selection"));
5785 Editor::set_punch_from_edit_range ()
5787 if (_session == 0) {
5794 if (!get_edit_op_range (start, end)) {
5798 set_punch_range (start, end, _("set punch range from edit range"));
5802 Editor::set_punch_from_region ()
5804 framepos_t start = max_framepos;
5807 RegionSelection rs = get_regions_from_selection_and_entered ();
5813 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5814 if ((*i)->region()->position() < start) {
5815 start = (*i)->region()->position();
5817 if ((*i)->region()->last_frame() + 1 > end) {
5818 end = (*i)->region()->last_frame() + 1;
5822 set_punch_range (start, end, _("set punch range from region"));
5826 Editor::pitch_shift_region ()
5828 RegionSelection rs = get_regions_from_selection_and_entered ();
5830 RegionSelection audio_rs;
5831 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5832 if (dynamic_cast<AudioRegionView*> (*i)) {
5833 audio_rs.push_back (*i);
5837 if (audio_rs.empty()) {
5841 pitch_shift (audio_rs, 1.2);
5845 Editor::transpose_region ()
5847 RegionSelection rs = get_regions_from_selection_and_entered ();
5849 list<MidiRegionView*> midi_region_views;
5850 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5851 MidiRegionView* mrv = dynamic_cast<MidiRegionView*> (*i);
5853 midi_region_views.push_back (mrv);
5858 int const r = d.run ();
5859 if (r != RESPONSE_ACCEPT) {
5863 for (list<MidiRegionView*>::iterator i = midi_region_views.begin(); i != midi_region_views.end(); ++i) {
5864 (*i)->midi_region()->transpose (d.semitones ());
5869 Editor::set_tempo_from_region ()
5871 RegionSelection rs = get_regions_from_selection_and_entered ();
5873 if (!_session || rs.empty()) {
5877 RegionView* rv = rs.front();
5879 define_one_bar (rv->region()->position(), rv->region()->last_frame() + 1);
5883 Editor::use_range_as_bar ()
5885 framepos_t start, end;
5886 if (get_edit_op_range (start, end)) {
5887 define_one_bar (start, end);
5892 Editor::define_one_bar (framepos_t start, framepos_t end)
5894 framepos_t length = end - start;
5896 const Meter& m (_session->tempo_map().meter_at (start));
5898 /* length = 1 bar */
5900 /* now we want frames per beat.
5901 we have frames per bar, and beats per bar, so ...
5904 /* XXXX METER MATH */
5906 double frames_per_beat = length / m.divisions_per_bar();
5908 /* beats per minute = */
5910 double beats_per_minute = (_session->frame_rate() * 60.0) / frames_per_beat;
5912 /* now decide whether to:
5914 (a) set global tempo
5915 (b) add a new tempo marker
5919 const TempoSection& t (_session->tempo_map().tempo_section_at (start));
5921 bool do_global = false;
5923 if ((_session->tempo_map().n_tempos() == 1) && (_session->tempo_map().n_meters() == 1)) {
5925 /* only 1 tempo & 1 meter: ask if the user wants to set the tempo
5926 at the start, or create a new marker
5929 vector<string> options;
5930 options.push_back (_("Cancel"));
5931 options.push_back (_("Add new marker"));
5932 options.push_back (_("Set global tempo"));
5935 _("Define one bar"),
5936 _("Do you want to set the global tempo or add a new tempo marker?"),
5940 c.set_default_response (2);
5956 /* more than 1 tempo and/or meter section already, go ahead do the "usual":
5957 if the marker is at the region starter, change it, otherwise add
5962 begin_reversible_command (_("set tempo from region"));
5963 XMLNode& before (_session->tempo_map().get_state());
5966 _session->tempo_map().change_initial_tempo (beats_per_minute, t.note_type());
5967 } else if (t.frame() == start) {
5968 _session->tempo_map().change_existing_tempo_at (start, beats_per_minute, t.note_type());
5970 Timecode::BBT_Time bbt;
5971 _session->tempo_map().bbt_time (start, bbt);
5972 _session->tempo_map().add_tempo (Tempo (beats_per_minute, t.note_type()), bbt);
5975 XMLNode& after (_session->tempo_map().get_state());
5977 _session->add_command (new MementoCommand<TempoMap>(_session->tempo_map(), &before, &after));
5978 commit_reversible_command ();
5982 Editor::split_region_at_transients ()
5984 AnalysisFeatureList positions;
5986 RegionSelection rs = get_regions_from_selection_and_entered ();
5988 if (!_session || rs.empty()) {
5992 _session->begin_reversible_command (_("split regions"));
5994 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ) {
5996 RegionSelection::iterator tmp;
6001 boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion> ((*i)->region());
6003 if (ar && (ar->get_transients (positions) == 0)) {
6004 split_region_at_points ((*i)->region(), positions, true);
6011 _session->commit_reversible_command ();
6016 Editor::split_region_at_points (boost::shared_ptr<Region> r, AnalysisFeatureList& positions, bool can_ferret, bool select_new)
6018 bool use_rhythmic_rodent = false;
6020 boost::shared_ptr<Playlist> pl = r->playlist();
6022 list<boost::shared_ptr<Region> > new_regions;
6028 if (positions.empty()) {
6033 if (positions.size() > 20 && can_ferret) {
6034 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);
6035 MessageDialog msg (msgstr,
6038 Gtk::BUTTONS_OK_CANCEL);
6041 msg.add_button (_("Call for the Ferret!"), RESPONSE_APPLY);
6042 msg.set_secondary_text (_("Press OK to continue with this split operation\nor ask the Ferret dialog to tune the analysis"));
6044 msg.set_secondary_text (_("Press OK to continue with this split operation"));
6047 msg.set_title (_("Excessive split?"));
6050 int response = msg.run();
6056 case RESPONSE_APPLY:
6057 use_rhythmic_rodent = true;
6064 if (use_rhythmic_rodent) {
6065 show_rhythm_ferret ();
6069 AnalysisFeatureList::const_iterator x;
6071 pl->clear_changes ();
6072 pl->clear_owned_changes ();
6074 x = positions.begin();
6076 if (x == positions.end()) {
6081 pl->remove_region (r);
6085 while (x != positions.end()) {
6087 /* deal with positons that are out of scope of present region bounds */
6088 if (*x <= 0 || *x > r->length()) {
6093 /* file start = original start + how far we from the initial position ?
6096 framepos_t file_start = r->start() + pos;
6098 /* length = next position - current position
6101 framepos_t len = (*x) - pos;
6103 /* XXX we do we really want to allow even single-sample regions?
6104 shouldn't we have some kind of lower limit on region size?
6113 if (RegionFactory::region_name (new_name, r->name())) {
6117 /* do NOT announce new regions 1 by one, just wait till they are all done */
6121 plist.add (ARDOUR::Properties::start, file_start);
6122 plist.add (ARDOUR::Properties::length, len);
6123 plist.add (ARDOUR::Properties::name, new_name);
6124 plist.add (ARDOUR::Properties::layer, 0);
6126 boost::shared_ptr<Region> nr = RegionFactory::create (r->sources(), plist, false);
6127 /* because we set annouce to false, manually add the new region to the
6130 RegionFactory::map_add (nr);
6132 pl->add_region (nr, r->position() + pos);
6135 new_regions.push_front(nr);
6144 RegionFactory::region_name (new_name, r->name());
6146 /* Add the final region */
6149 plist.add (ARDOUR::Properties::start, r->start() + pos);
6150 plist.add (ARDOUR::Properties::length, r->last_frame() - (r->position() + pos) + 1);
6151 plist.add (ARDOUR::Properties::name, new_name);
6152 plist.add (ARDOUR::Properties::layer, 0);
6154 boost::shared_ptr<Region> nr = RegionFactory::create (r->sources(), plist, false);
6155 /* because we set annouce to false, manually add the new region to the
6158 RegionFactory::map_add (nr);
6159 pl->add_region (nr, r->position() + pos);
6162 new_regions.push_front(nr);
6167 /* We might have removed regions, which alters other regions' layering_index,
6168 so we need to do a recursive diff here.
6170 vector<Command*> cmds;
6172 _session->add_commands (cmds);
6174 _session->add_command (new StatefulDiffCommand (pl));
6178 for (list<boost::shared_ptr<Region> >::iterator i = new_regions.begin(); i != new_regions.end(); ++i){
6179 set_selected_regionview_from_region_list ((*i), Selection::Add);
6185 Editor::place_transient()
6191 RegionSelection rs = get_regions_from_selection_and_edit_point ();
6197 framepos_t where = get_preferred_edit_position();
6199 _session->begin_reversible_command (_("place transient"));
6201 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6202 framepos_t position = (*r)->region()->position();
6203 (*r)->region()->add_transient(where - position);
6206 _session->commit_reversible_command ();
6210 Editor::remove_transient(ArdourCanvas::Item* item)
6216 ArdourCanvas::Line* _line = reinterpret_cast<ArdourCanvas::Line*> (item);
6219 AudioRegionView* _arv = reinterpret_cast<AudioRegionView*> (item->get_data ("regionview"));
6220 _arv->remove_transient (*(float*) _line->get_data ("position"));
6224 Editor::snap_regions_to_grid ()
6226 list <boost::shared_ptr<Playlist > > used_playlists;
6228 RegionSelection rs = get_regions_from_selection_and_entered ();
6230 if (!_session || rs.empty()) {
6234 _session->begin_reversible_command (_("snap regions to grid"));
6236 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6238 boost::shared_ptr<Playlist> pl = (*r)->region()->playlist();
6240 if (!pl->frozen()) {
6241 /* we haven't seen this playlist before */
6243 /* remember used playlists so we can thaw them later */
6244 used_playlists.push_back(pl);
6248 framepos_t start_frame = (*r)->region()->first_frame ();
6249 snap_to (start_frame);
6250 (*r)->region()->set_position (start_frame);
6253 while (used_playlists.size() > 0) {
6254 list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
6256 used_playlists.pop_front();
6259 _session->commit_reversible_command ();
6263 Editor::close_region_gaps ()
6265 list <boost::shared_ptr<Playlist > > used_playlists;
6267 RegionSelection rs = get_regions_from_selection_and_entered ();
6269 if (!_session || rs.empty()) {
6273 Dialog dialog (_("Close Region Gaps"));
6276 table.set_spacings (12);
6277 table.set_border_width (12);
6278 Label* l = manage (left_aligned_label (_("Crossfade length")));
6279 table.attach (*l, 0, 1, 0, 1);
6281 SpinButton spin_crossfade (1, 0);
6282 spin_crossfade.set_range (0, 15);
6283 spin_crossfade.set_increments (1, 1);
6284 spin_crossfade.set_value (5);
6285 table.attach (spin_crossfade, 1, 2, 0, 1);
6287 table.attach (*manage (new Label (_("ms"))), 2, 3, 0, 1);
6289 l = manage (left_aligned_label (_("Pull-back length")));
6290 table.attach (*l, 0, 1, 1, 2);
6292 SpinButton spin_pullback (1, 0);
6293 spin_pullback.set_range (0, 100);
6294 spin_pullback.set_increments (1, 1);
6295 spin_pullback.set_value(30);
6296 table.attach (spin_pullback, 1, 2, 1, 2);
6298 table.attach (*manage (new Label (_("ms"))), 2, 3, 1, 2);
6300 dialog.get_vbox()->pack_start (table);
6301 dialog.add_button (Stock::CANCEL, RESPONSE_CANCEL);
6302 dialog.add_button (_("Ok"), RESPONSE_ACCEPT);
6305 if (dialog.run () == RESPONSE_CANCEL) {
6309 framepos_t crossfade_len = spin_crossfade.get_value();
6310 framepos_t pull_back_frames = spin_pullback.get_value();
6312 crossfade_len = lrintf (crossfade_len * _session->frame_rate()/1000);
6313 pull_back_frames = lrintf (pull_back_frames * _session->frame_rate()/1000);
6315 /* Iterate over the region list and make adjacent regions overlap by crossfade_len_ms */
6317 _session->begin_reversible_command (_("close region gaps"));
6320 boost::shared_ptr<Region> last_region;
6322 rs.sort_by_position_and_track();
6324 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6326 boost::shared_ptr<Playlist> pl = (*r)->region()->playlist();
6328 if (!pl->frozen()) {
6329 /* we haven't seen this playlist before */
6331 /* remember used playlists so we can thaw them later */
6332 used_playlists.push_back(pl);
6336 framepos_t position = (*r)->region()->position();
6338 if (idx == 0 || position < last_region->position()){
6339 last_region = (*r)->region();
6344 (*r)->region()->trim_front( (position - pull_back_frames));
6345 last_region->trim_end( (position - pull_back_frames + crossfade_len));
6347 last_region = (*r)->region();
6352 while (used_playlists.size() > 0) {
6353 list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
6355 used_playlists.pop_front();
6358 _session->commit_reversible_command ();
6362 Editor::tab_to_transient (bool forward)
6364 AnalysisFeatureList positions;
6366 RegionSelection rs = get_regions_from_selection_and_entered ();
6372 framepos_t pos = _session->audible_frame ();
6374 if (!selection->tracks.empty()) {
6376 /* don't waste time searching for transients in duplicate playlists.
6379 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
6381 for (TrackViewList::iterator t = ts.begin(); t != ts.end(); ++t) {
6383 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*t);
6386 boost::shared_ptr<Track> tr = rtv->track();
6388 boost::shared_ptr<Playlist> pl = tr->playlist ();
6390 framepos_t result = pl->find_next_transient (pos, forward ? 1 : -1);
6393 positions.push_back (result);
6406 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6407 (*r)->region()->get_transients (positions);
6411 TransientDetector::cleanup_transients (positions, _session->frame_rate(), 3.0);
6414 AnalysisFeatureList::iterator x;
6416 for (x = positions.begin(); x != positions.end(); ++x) {
6422 if (x != positions.end ()) {
6423 _session->request_locate (*x);
6427 AnalysisFeatureList::reverse_iterator x;
6429 for (x = positions.rbegin(); x != positions.rend(); ++x) {
6435 if (x != positions.rend ()) {
6436 _session->request_locate (*x);
6442 Editor::playhead_forward_to_grid ()
6448 framepos_t pos = playhead_cursor->current_frame ();
6449 if (pos < max_framepos - 1) {
6451 snap_to_internal (pos, 1, false);
6452 _session->request_locate (pos);
6458 Editor::playhead_backward_to_grid ()
6464 framepos_t pos = playhead_cursor->current_frame ();
6467 snap_to_internal (pos, -1, false);
6468 _session->request_locate (pos);
6473 Editor::set_track_height (Height h)
6475 TrackSelection& ts (selection->tracks);
6477 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
6478 (*x)->set_height_enum (h);
6483 Editor::toggle_tracks_active ()
6485 TrackSelection& ts (selection->tracks);
6487 bool target = false;
6493 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
6494 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*x);
6498 target = !rtv->_route->active();
6501 rtv->_route->set_active (target, this);
6507 Editor::remove_tracks ()
6509 TrackSelection& ts (selection->tracks);
6515 vector<string> choices;
6519 const char* trackstr;
6521 vector<boost::shared_ptr<Route> > routes;
6522 bool special_bus = false;
6524 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
6525 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*x);
6529 if (rtv->is_track()) {
6534 routes.push_back (rtv->_route);
6536 if (rtv->route()->is_master() || rtv->route()->is_monitor()) {
6541 if (special_bus && !Config->get_allow_special_bus_removal()) {
6542 MessageDialog msg (_("That would be bad news ...."),
6546 msg.set_secondary_text (string_compose (_(
6547 "Removing the master or monitor bus is such a bad idea\n\
6548 that %1 is not going to allow it.\n\
6550 If you really want to do this sort of thing\n\
6551 edit your ardour.rc file to set the\n\
6552 \"allow-special-bus-removal\" option to be \"yes\""), PROGRAM_NAME));
6559 if (ntracks + nbusses == 0) {
6564 trackstr = _("tracks");
6566 trackstr = _("track");
6570 busstr = _("busses");
6577 prompt = string_compose (_("Do you really want to remove %1 %2 and %3 %4?\n"
6578 "(You may also lose the playlists associated with the %2)\n\n"
6579 "This action cannot be undone, and the session file will be overwritten!"),
6580 ntracks, trackstr, nbusses, busstr);
6582 prompt = string_compose (_("Do you really want to remove %1 %2?\n"
6583 "(You may also lose the playlists associated with the %2)\n\n"
6584 "This action cannot be undone, and the session file will be overwritten!"),
6587 } else if (nbusses) {
6588 prompt = string_compose (_("Do you really want to remove %1 %2?\n\n"
6589 "This action cannot be undon, and the session file will be overwritten"),
6593 choices.push_back (_("No, do nothing."));
6594 if (ntracks + nbusses > 1) {
6595 choices.push_back (_("Yes, remove them."));
6597 choices.push_back (_("Yes, remove it."));
6602 title = string_compose (_("Remove %1"), trackstr);
6604 title = string_compose (_("Remove %1"), busstr);
6607 Choice prompter (title, prompt, choices);
6609 if (prompter.run () != 1) {
6614 Session::StateProtector sp (_session);
6615 for (vector<boost::shared_ptr<Route> >::iterator x = routes.begin(); x != routes.end(); ++x) {
6616 _session->remove_route (*x);
6622 Editor::do_insert_time ()
6624 if (selection->tracks.empty()) {
6628 InsertTimeDialog d (*this);
6629 int response = d.run ();
6631 if (response != RESPONSE_OK) {
6635 if (d.distance() == 0) {
6639 InsertTimeOption opt = d.intersected_region_action ();
6642 get_preferred_edit_position(),
6648 d.move_glued_markers(),
6649 d.move_locked_markers(),
6655 Editor::insert_time (
6656 framepos_t pos, framecnt_t frames, InsertTimeOption opt,
6657 bool all_playlists, bool ignore_music_glue, bool markers_too, bool glued_markers_too, bool locked_markers_too, bool tempo_too
6660 bool commit = false;
6662 if (Config->get_edit_mode() == Lock) {
6666 begin_reversible_command (_("insert time"));
6668 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
6670 for (TrackViewList::iterator x = ts.begin(); x != ts.end(); ++x) {
6674 /* don't operate on any playlist more than once, which could
6675 * happen if "all playlists" is enabled, but there is more
6676 * than 1 track using playlists "from" a given track.
6679 set<boost::shared_ptr<Playlist> > pl;
6681 if (all_playlists) {
6682 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*x);
6684 vector<boost::shared_ptr<Playlist> > all = _session->playlists->playlists_for_track (rtav->track ());
6685 for (vector<boost::shared_ptr<Playlist> >::iterator p = all.begin(); p != all.end(); ++p) {
6690 if ((*x)->playlist ()) {
6691 pl.insert ((*x)->playlist ());
6695 for (set<boost::shared_ptr<Playlist> >::iterator i = pl.begin(); i != pl.end(); ++i) {
6697 (*i)->clear_changes ();
6698 (*i)->clear_owned_changes ();
6700 if (opt == SplitIntersected) {
6704 (*i)->shift (pos, frames, (opt == MoveIntersected), ignore_music_glue);
6706 vector<Command*> cmds;
6708 _session->add_commands (cmds);
6710 _session->add_command (new StatefulDiffCommand (*i));
6715 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*x);
6717 rtav->route ()->shift (pos, frames);
6725 XMLNode& before (_session->locations()->get_state());
6726 Locations::LocationList copy (_session->locations()->list());
6728 for (Locations::LocationList::iterator i = copy.begin(); i != copy.end(); ++i) {
6730 Locations::LocationList::const_iterator tmp;
6732 bool const was_locked = (*i)->locked ();
6733 if (locked_markers_too) {
6737 if ((*i)->position_lock_style() == AudioTime || glued_markers_too) {
6739 if ((*i)->start() >= pos) {
6740 (*i)->set_start ((*i)->start() + frames);
6741 if (!(*i)->is_mark()) {
6742 (*i)->set_end ((*i)->end() + frames);
6755 XMLNode& after (_session->locations()->get_state());
6756 _session->add_command (new MementoCommand<Locations>(*_session->locations(), &before, &after));
6761 _session->tempo_map().insert_time (pos, frames);
6765 commit_reversible_command ();
6770 Editor::fit_selected_tracks ()
6772 if (!selection->tracks.empty()) {
6773 fit_tracks (selection->tracks);
6777 /* no selected tracks - use tracks with selected regions */
6779 if (!selection->regions.empty()) {
6780 for (RegionSelection::iterator r = selection->regions.begin(); r != selection->regions.end(); ++r) {
6781 tvl.push_back (&(*r)->get_time_axis_view ());
6787 } else if (internal_editing()) {
6788 /* no selected tracks, or regions, but in internal edit mode, so follow the mouse and use
6791 if (entered_track) {
6792 tvl.push_back (entered_track);
6801 Editor::fit_tracks (TrackViewList & tracks)
6803 if (tracks.empty()) {
6807 uint32_t child_heights = 0;
6808 int visible_tracks = 0;
6810 for (TrackSelection::iterator t = tracks.begin(); t != tracks.end(); ++t) {
6812 if (!(*t)->marked_for_display()) {
6816 child_heights += (*t)->effective_height() - (*t)->current_height();
6820 /* compute the per-track height from:
6822 total canvas visible height -
6823 height that will be taken by visible children of selected
6824 tracks - height of the ruler/hscroll area
6826 uint32_t h = (uint32_t) floor ((trackviews_height() - child_heights) / visible_tracks);
6827 double first_y_pos = DBL_MAX;
6829 if (h < TimeAxisView::preset_height (HeightSmall)) {
6830 MessageDialog msg (*this, _("There are too many tracks to fit in the current window"));
6831 /* too small to be displayed */
6835 undo_visual_stack.push_back (current_visual_state (true));
6836 no_save_visual = true;
6838 /* build a list of all tracks, including children */
6841 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
6843 TimeAxisView::Children c = (*i)->get_child_list ();
6844 for (TimeAxisView::Children::iterator j = c.begin(); j != c.end(); ++j) {
6845 all.push_back (j->get());
6849 bool prev_was_selected = false;
6850 bool is_selected = tracks.contains (all.front());
6851 bool next_is_selected;
6853 for (TrackViewList::iterator t = all.begin(); t != all.end(); ++t) {
6855 TrackViewList::iterator next;
6860 if (next != all.end()) {
6861 next_is_selected = tracks.contains (*next);
6863 next_is_selected = false;
6866 if ((*t)->marked_for_display ()) {
6868 (*t)->set_height (h);
6869 first_y_pos = std::min ((*t)->y_position (), first_y_pos);
6871 if (prev_was_selected && next_is_selected) {
6872 hide_track_in_display (*t);
6877 prev_was_selected = is_selected;
6878 is_selected = next_is_selected;
6882 set the controls_layout height now, because waiting for its size
6883 request signal handler will cause the vertical adjustment setting to fail
6886 controls_layout.property_height () = _full_canvas_height;
6887 vertical_adjustment.set_value (first_y_pos);
6889 redo_visual_stack.push_back (current_visual_state (true));
6891 visible_tracks_selector.set_text (_("Sel"));
6895 Editor::save_visual_state (uint32_t n)
6897 while (visual_states.size() <= n) {
6898 visual_states.push_back (0);
6901 if (visual_states[n] != 0) {
6902 delete visual_states[n];
6905 visual_states[n] = current_visual_state (true);
6910 Editor::goto_visual_state (uint32_t n)
6912 if (visual_states.size() <= n) {
6916 if (visual_states[n] == 0) {
6920 use_visual_state (*visual_states[n]);
6924 Editor::start_visual_state_op (uint32_t n)
6926 save_visual_state (n);
6928 PopUp* pup = new PopUp (WIN_POS_MOUSE, 1000, true);
6930 snprintf (buf, sizeof (buf), _("Saved view %u"), n+1);
6931 pup->set_text (buf);
6936 Editor::cancel_visual_state_op (uint32_t n)
6938 goto_visual_state (n);
6942 Editor::toggle_region_mute ()
6944 if (_ignore_region_action) {
6948 RegionSelection rs = get_regions_from_selection_and_entered ();
6954 if (rs.size() > 1) {
6955 begin_reversible_command (_("mute regions"));
6957 begin_reversible_command (_("mute region"));
6960 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
6962 (*i)->region()->playlist()->clear_changes ();
6963 (*i)->region()->set_muted (!(*i)->region()->muted ());
6964 _session->add_command (new StatefulDiffCommand ((*i)->region()->playlist()));
6968 commit_reversible_command ();
6972 Editor::combine_regions ()
6974 /* foreach track with selected regions, take all selected regions
6975 and join them into a new region containing the subregions (as a
6979 typedef set<RouteTimeAxisView*> RTVS;
6982 if (selection->regions.empty()) {
6986 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
6987 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(&(*i)->get_time_axis_view());
6990 tracks.insert (rtv);
6994 begin_reversible_command (_("combine regions"));
6996 vector<RegionView*> new_selection;
6998 for (RTVS::iterator i = tracks.begin(); i != tracks.end(); ++i) {
7001 if ((rv = (*i)->combine_regions ()) != 0) {
7002 new_selection.push_back (rv);
7006 selection->clear_regions ();
7007 for (vector<RegionView*>::iterator i = new_selection.begin(); i != new_selection.end(); ++i) {
7008 selection->add (*i);
7011 commit_reversible_command ();
7015 Editor::uncombine_regions ()
7017 typedef set<RouteTimeAxisView*> RTVS;
7020 if (selection->regions.empty()) {
7024 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
7025 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(&(*i)->get_time_axis_view());
7028 tracks.insert (rtv);
7032 begin_reversible_command (_("uncombine regions"));
7034 for (RTVS::iterator i = tracks.begin(); i != tracks.end(); ++i) {
7035 (*i)->uncombine_regions ();
7038 commit_reversible_command ();
7042 Editor::toggle_midi_input_active (bool flip_others)
7045 boost::shared_ptr<RouteList> rl (new RouteList);
7047 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
7048 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
7054 boost::shared_ptr<MidiTrack> mt = rtav->midi_track();
7057 rl->push_back (rtav->route());
7058 onoff = !mt->input_active();
7062 _session->set_exclusive_input_active (rl, onoff, flip_others);
7069 lock_dialog = new Gtk::Dialog (string_compose (_("%1: Locked"), PROGRAM_NAME), true);
7071 Gtk::Image* padlock = manage (new Gtk::Image (ARDOUR_UI_UTILS::get_icon ("padlock_closed")));
7072 lock_dialog->get_vbox()->pack_start (*padlock);
7074 ArdourButton* b = manage (new ArdourButton);
7075 b->set_name ("lock button");
7076 b->set_markup (string_compose ("<span size=\"large\" weight=\"bold\">%1</span>", _("Click to unlock")));
7077 b->signal_clicked.connect (sigc::mem_fun (*this, &Editor::unlock));
7078 lock_dialog->get_vbox()->pack_start (*b);
7080 lock_dialog->get_vbox()->show_all ();
7081 lock_dialog->set_size_request (200, 200);
7085 /* The global menu bar continues to be accessible to applications
7086 with modal dialogs, which means that we need to desensitize
7087 all items in the menu bar. Since those items are really just
7088 proxies for actions, that means disabling all actions.
7090 ActionManager::disable_all_actions ();
7092 lock_dialog->present ();
7098 lock_dialog->hide ();
7101 ActionManager::pop_action_state ();
7104 if (ARDOUR_UI::config()->get_lock_gui_after_seconds()) {
7105 start_lock_event_timing ();
7110 Editor::bring_in_callback (Gtk::Label* label, uint32_t n, uint32_t total, string name)
7112 Gtkmm2ext::UI::instance()->call_slot (invalidator (*this), boost::bind (&Editor::update_bring_in_message, this, label, n, total, name));
7116 Editor::update_bring_in_message (Gtk::Label* label, uint32_t n, uint32_t total, string name)
7118 label->set_text (string_compose ("Copying %1, %2 of %3", name, n, total));
7119 Gtkmm2ext::UI::instance()->flush_pending ();
7123 Editor::bring_all_sources_into_session ()
7130 ArdourDialog w (_("Moving embedded files into session folder"));
7131 w.get_vbox()->pack_start (msg);
7134 /* flush all pending GUI events because we're about to start copying
7138 Gtkmm2ext::UI::instance()->flush_pending ();
7142 _session->bring_all_sources_into_session (boost::bind (&Editor::bring_in_callback, this, &msg, _1, _2, _3));