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 bool deleted = false;
3738 if ( current_mixer_strip && current_mixer_strip == MixerStrip::entered_mixer_strip() )
3739 deleted = current_mixer_strip->delete_processors ();
3745 /** Cut selected regions, automation points or a time range */
3752 /** Copy selected regions, automation points or a time range */
3760 /** @return true if a Cut, Copy or Clear is possible */
3762 Editor::can_cut_copy () const
3764 if (!selection->time.empty() || !selection->regions.empty() || !selection->points.empty())
3771 /** Cut, copy or clear selected regions, automation points or a time range.
3772 * @param op Operation (Delete, Cut, Copy or Clear)
3775 Editor::cut_copy (CutCopyOp op)
3777 /* only cancel selection if cut/copy is successful.*/
3783 opname = _("delete");
3792 opname = _("clear");
3796 /* if we're deleting something, and the mouse is still pressed,
3797 the thing we started a drag for will be gone when we release
3798 the mouse button(s). avoid this. see part 2 at the end of
3802 if (op == Delete || op == Cut || op == Clear) {
3803 if (_drags->active ()) {
3808 if ( op != Delete ) //"Delete" doesn't change copy/paste buf
3809 cut_buffer->clear ();
3811 if (entered_marker) {
3813 /* cut/delete op while pointing at a marker */
3816 Location* loc = find_location_from_marker (entered_marker, ignored);
3818 if (_session && loc) {
3819 Glib::signal_idle().connect (sigc::bind (sigc::mem_fun(*this, &Editor::really_remove_marker), loc));
3826 if (internal_editing()) {
3828 switch (effective_mouse_mode()) {
3831 begin_reversible_command (opname + ' ' + X_("MIDI"));
3833 commit_reversible_command ();
3842 bool did_edit = false;
3844 if (!selection->points.empty()) {
3845 begin_reversible_command (opname + _(" points"));
3847 cut_copy_points (op);
3848 if (op == Cut || op == Delete) {
3849 selection->clear_points ();
3851 } else if (!selection->regions.empty() || !selection->points.empty()) {
3855 if (selection->regions.empty()) {
3856 thing_name = _("points");
3857 } else if (selection->points.empty()) {
3858 thing_name = _("regions");
3860 thing_name = _("objects");
3863 begin_reversible_command (opname + ' ' + thing_name);
3866 if (!selection->regions.empty()) {
3867 cut_copy_regions (op, selection->regions);
3869 if (op == Cut || op == Delete) {
3870 selection->clear_regions ();
3874 if (!selection->points.empty()) {
3875 cut_copy_points (op);
3877 if (op == Cut || op == Delete) {
3878 selection->clear_points ();
3881 } else if (selection->time.empty()) {
3882 framepos_t start, end;
3883 /* no time selection, see if we can get an edit range
3886 if (get_edit_op_range (start, end)) {
3887 selection->set (start, end);
3889 } else if (!selection->time.empty()) {
3890 begin_reversible_command (opname + _(" range"));
3893 cut_copy_ranges (op);
3895 if (op == Cut || op == Delete) {
3896 selection->clear_time ();
3901 commit_reversible_command ();
3904 if (op == Delete || op == Cut || op == Clear) {
3909 struct AutomationRecord {
3910 AutomationRecord () : state (0) {}
3911 AutomationRecord (XMLNode* s) : state (s) {}
3913 XMLNode* state; ///< state before any operation
3914 boost::shared_ptr<Evoral::ControlList> copy; ///< copied events for the cut buffer
3917 /** Cut, copy or clear selected automation points.
3918 * @param op Operation (Cut, Copy or Clear)
3921 Editor::cut_copy_points (CutCopyOp op)
3923 if (selection->points.empty ()) {
3927 /* XXX: not ideal, as there may be more than one track involved in the point selection */
3928 _last_cut_copy_source_track = &selection->points.front()->line().trackview;
3930 /* Keep a record of the AutomationLists that we end up using in this operation */
3931 typedef std::map<boost::shared_ptr<AutomationList>, AutomationRecord> Lists;
3934 /* Go through all selected points, making an AutomationRecord for each distinct AutomationList */
3935 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
3936 boost::shared_ptr<AutomationList> al = (*i)->line().the_list();
3937 if (lists.find (al) == lists.end ()) {
3938 /* We haven't seen this list yet, so make a record for it. This includes
3939 taking a copy of its current state, in case this is needed for undo later.
3941 lists[al] = AutomationRecord (&al->get_state ());
3945 if (op == Cut || op == Copy) {
3946 /* This operation will involve putting things in the cut buffer, so create an empty
3947 ControlList for each of our source lists to put the cut buffer data in.
3949 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
3950 i->second.copy = i->first->create (i->first->parameter ());
3953 /* Add all selected points to the relevant copy ControlLists */
3954 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
3955 boost::shared_ptr<AutomationList> al = (*i)->line().the_list();
3956 AutomationList::const_iterator j = (*i)->model ();
3957 lists[al].copy->add ((*j)->when, (*j)->value);
3960 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
3961 /* Correct this copy list so that it starts at time 0 */
3962 double const start = i->second.copy->front()->when;
3963 for (AutomationList::iterator j = i->second.copy->begin(); j != i->second.copy->end(); ++j) {
3964 (*j)->when -= start;
3967 /* And add it to the cut buffer */
3968 cut_buffer->add (i->second.copy);
3972 if (op == Delete || op == Cut) {
3973 /* This operation needs to remove things from the main AutomationList, so do that now */
3975 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
3976 i->first->freeze ();
3979 /* Remove each selected point from its AutomationList */
3980 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
3981 boost::shared_ptr<AutomationList> al = (*i)->line().the_list();
3982 al->erase ((*i)->model ());
3985 /* Thaw the lists and add undo records for them */
3986 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
3987 boost::shared_ptr<AutomationList> al = i->first;
3989 _session->add_command (new MementoCommand<AutomationList> (*al.get(), i->second.state, &(al->get_state ())));
3994 /** Cut, copy or clear selected automation points.
3995 * @param op Operation (Cut, Copy or Clear)
3998 Editor::cut_copy_midi (CutCopyOp op)
4000 for (MidiRegionSelection::iterator i = selection->midi_regions.begin(); i != selection->midi_regions.end(); ++i) {
4001 MidiRegionView* mrv = *i;
4002 mrv->cut_copy_clear (op);
4008 struct lt_playlist {
4009 bool operator () (const PlaylistState& a, const PlaylistState& b) {
4010 return a.playlist < b.playlist;
4014 struct PlaylistMapping {
4016 boost::shared_ptr<Playlist> pl;
4018 PlaylistMapping (TimeAxisView* tvp) : tv (tvp) {}
4021 /** Remove `clicked_regionview' */
4023 Editor::remove_clicked_region ()
4025 if (clicked_routeview == 0 || clicked_regionview == 0) {
4029 boost::shared_ptr<Playlist> playlist = clicked_routeview->playlist();
4031 playlist->clear_changes ();
4032 playlist->clear_owned_changes ();
4033 playlist->remove_region (clicked_regionview->region());
4034 if (Config->get_edit_mode() == Ripple)
4035 playlist->ripple (clicked_regionview->region()->position(), -clicked_regionview->region()->length(), boost::shared_ptr<Region>());
4037 /* We might have removed regions, which alters other regions' layering_index,
4038 so we need to do a recursive diff here.
4040 vector<Command*> cmds;
4041 playlist->rdiff (cmds);
4042 _session->add_commands (cmds);
4044 _session->add_command(new StatefulDiffCommand (playlist));
4045 commit_reversible_command ();
4049 /** Remove the selected regions */
4051 Editor::remove_selected_regions ()
4053 RegionSelection rs = get_regions_from_selection_and_entered ();
4055 if (!_session || rs.empty()) {
4059 begin_reversible_command (_("remove region"));
4061 list<boost::shared_ptr<Region> > regions_to_remove;
4063 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
4064 // we can't just remove the region(s) in this loop because
4065 // this removes them from the RegionSelection, and they thus
4066 // disappear from underneath the iterator, and the ++i above
4067 // SEGVs in a puzzling fashion.
4069 // so, first iterate over the regions to be removed from rs and
4070 // add them to the regions_to_remove list, and then
4071 // iterate over the list to actually remove them.
4073 regions_to_remove.push_back ((*i)->region());
4076 vector<boost::shared_ptr<Playlist> > playlists;
4078 for (list<boost::shared_ptr<Region> >::iterator rl = regions_to_remove.begin(); rl != regions_to_remove.end(); ++rl) {
4080 boost::shared_ptr<Playlist> playlist = (*rl)->playlist();
4083 // is this check necessary?
4087 /* get_regions_from_selection_and_entered() guarantees that
4088 the playlists involved are unique, so there is no need
4092 playlists.push_back (playlist);
4094 playlist->clear_changes ();
4095 playlist->clear_owned_changes ();
4096 playlist->freeze ();
4097 playlist->remove_region (*rl);
4098 if (Config->get_edit_mode() == Ripple)
4099 playlist->ripple ((*rl)->position(), -(*rl)->length(), boost::shared_ptr<Region>());
4103 vector<boost::shared_ptr<Playlist> >::iterator pl;
4105 for (pl = playlists.begin(); pl != playlists.end(); ++pl) {
4108 /* We might have removed regions, which alters other regions' layering_index,
4109 so we need to do a recursive diff here.
4111 vector<Command*> cmds;
4112 (*pl)->rdiff (cmds);
4113 _session->add_commands (cmds);
4115 _session->add_command(new StatefulDiffCommand (*pl));
4118 commit_reversible_command ();
4121 /** Cut, copy or clear selected regions.
4122 * @param op Operation (Cut, Copy or Clear)
4125 Editor::cut_copy_regions (CutCopyOp op, RegionSelection& rs)
4127 /* we can't use a std::map here because the ordering is important, and we can't trivially sort
4128 a map when we want ordered access to both elements. i think.
4131 vector<PlaylistMapping> pmap;
4133 framepos_t first_position = max_framepos;
4135 typedef set<boost::shared_ptr<Playlist> > FreezeList;
4136 FreezeList freezelist;
4138 /* get ordering correct before we cut/copy */
4140 rs.sort_by_position_and_track ();
4142 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
4144 first_position = min ((framepos_t) (*x)->region()->position(), first_position);
4146 if (op == Cut || op == Clear || op == Delete) {
4147 boost::shared_ptr<Playlist> pl = (*x)->region()->playlist();
4150 FreezeList::iterator fl;
4152 // only take state if this is a new playlist.
4153 for (fl = freezelist.begin(); fl != freezelist.end(); ++fl) {
4159 if (fl == freezelist.end()) {
4160 pl->clear_changes();
4161 pl->clear_owned_changes ();
4163 freezelist.insert (pl);
4168 TimeAxisView* tv = &(*x)->get_time_axis_view();
4169 vector<PlaylistMapping>::iterator z;
4171 for (z = pmap.begin(); z != pmap.end(); ++z) {
4172 if ((*z).tv == tv) {
4177 if (z == pmap.end()) {
4178 pmap.push_back (PlaylistMapping (tv));
4182 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ) {
4184 boost::shared_ptr<Playlist> pl = (*x)->region()->playlist();
4187 /* region not yet associated with a playlist (e.g. unfinished
4194 TimeAxisView& tv = (*x)->get_time_axis_view();
4195 boost::shared_ptr<Playlist> npl;
4196 RegionSelection::iterator tmp;
4203 vector<PlaylistMapping>::iterator z;
4205 for (z = pmap.begin(); z != pmap.end(); ++z) {
4206 if ((*z).tv == &tv) {
4211 assert (z != pmap.end());
4214 npl = PlaylistFactory::create (pl->data_type(), *_session, "cutlist", true);
4222 boost::shared_ptr<Region> r = (*x)->region();
4223 boost::shared_ptr<Region> _xx;
4229 pl->remove_region (r);
4230 if (Config->get_edit_mode() == Ripple)
4231 pl->ripple (r->position(), -r->length(), boost::shared_ptr<Region>());
4235 _xx = RegionFactory::create (r);
4236 npl->add_region (_xx, r->position() - first_position);
4237 pl->remove_region (r);
4238 if (Config->get_edit_mode() == Ripple)
4239 pl->ripple (r->position(), -r->length(), boost::shared_ptr<Region>());
4243 /* copy region before adding, so we're not putting same object into two different playlists */
4244 npl->add_region (RegionFactory::create (r), r->position() - first_position);
4248 pl->remove_region (r);
4249 if (Config->get_edit_mode() == Ripple)
4250 pl->ripple (r->position(), -r->length(), boost::shared_ptr<Region>());
4259 list<boost::shared_ptr<Playlist> > foo;
4261 /* the pmap is in the same order as the tracks in which selected regions occured */
4263 for (vector<PlaylistMapping>::iterator i = pmap.begin(); i != pmap.end(); ++i) {
4266 foo.push_back ((*i).pl);
4271 cut_buffer->set (foo);
4275 _last_cut_copy_source_track = 0;
4277 _last_cut_copy_source_track = pmap.front().tv;
4281 for (FreezeList::iterator pl = freezelist.begin(); pl != freezelist.end(); ++pl) {
4284 /* We might have removed regions, which alters other regions' layering_index,
4285 so we need to do a recursive diff here.
4287 vector<Command*> cmds;
4288 (*pl)->rdiff (cmds);
4289 _session->add_commands (cmds);
4291 _session->add_command (new StatefulDiffCommand (*pl));
4296 Editor::cut_copy_ranges (CutCopyOp op)
4298 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4300 /* Sort the track selection now, so that it if is used, the playlists
4301 selected by the calls below to cut_copy_clear are in the order that
4302 their tracks appear in the editor. This makes things like paste
4303 of ranges work properly.
4306 sort_track_selection (ts);
4309 if (!entered_track) {
4312 ts.push_back (entered_track);
4315 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4316 (*i)->cut_copy_clear (*selection, op);
4321 Editor::paste (float times, bool from_context)
4323 DEBUG_TRACE (DEBUG::CutNPaste, "paste to preferred edit pos\n");
4325 paste_internal (get_preferred_edit_position (false, from_context), times);
4329 Editor::mouse_paste ()
4334 if (!mouse_frame (where, ignored)) {
4339 paste_internal (where, 1);
4343 Editor::paste_internal (framepos_t position, float times)
4345 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("apparent paste position is %1\n", position));
4347 if (internal_editing()) {
4348 if (cut_buffer->midi_notes.empty()) {
4352 if (cut_buffer->empty()) {
4357 if (position == max_framepos) {
4358 position = get_preferred_edit_position();
4359 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("preferred edit position is %1\n", position));
4363 TrackViewList::iterator i;
4366 /* get everything in the correct order */
4368 if (_edit_point == Editing::EditAtMouse && entered_track) {
4369 /* With the mouse edit point, paste onto the track under the mouse */
4370 ts.push_back (entered_track);
4371 } else if (!selection->tracks.empty()) {
4372 /* Otherwise, if there are some selected tracks, paste to them */
4373 ts = selection->tracks.filter_to_unique_playlists ();
4374 sort_track_selection (ts);
4375 } else if (_last_cut_copy_source_track) {
4376 /* Otherwise paste to the track that the cut/copy came from;
4377 see discussion in mantis #3333.
4379 ts.push_back (_last_cut_copy_source_track);
4382 if (internal_editing ()) {
4384 /* undo/redo is handled by individual tracks/regions */
4386 for (nth = 0, i = ts.begin(); i != ts.end(); ++i, ++nth) {
4389 RegionSelection::iterator r;
4390 MidiNoteSelection::iterator cb;
4392 get_regions_at (rs, position, ts);
4394 for (cb = cut_buffer->midi_notes.begin(), r = rs.begin();
4395 cb != cut_buffer->midi_notes.end() && r != rs.end(); ++r) {
4396 MidiRegionView* mrv = dynamic_cast<MidiRegionView*> (*r);
4398 mrv->paste (position, times, **cb);
4406 /* we do redo (do you do voodoo?) */
4408 begin_reversible_command (Operations::paste);
4410 for (nth = 0, i = ts.begin(); i != ts.end(); ++i, ++nth) {
4411 (*i)->paste (position, times, *cut_buffer, nth);
4414 commit_reversible_command ();
4419 Editor::duplicate_some_regions (RegionSelection& regions, float times)
4421 boost::shared_ptr<Playlist> playlist;
4422 RegionSelection sel = regions; // clear (below) may clear the argument list if its the current region selection
4423 RegionSelection foo;
4425 framepos_t const start_frame = regions.start ();
4426 framepos_t const end_frame = regions.end_frame ();
4428 begin_reversible_command (Operations::duplicate_region);
4430 selection->clear_regions ();
4432 for (RegionSelection::iterator i = sel.begin(); i != sel.end(); ++i) {
4434 boost::shared_ptr<Region> r ((*i)->region());
4436 TimeAxisView& tv = (*i)->get_time_axis_view();
4437 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (&tv);
4438 latest_regionviews.clear ();
4439 sigc::connection c = rtv->view()->RegionViewAdded.connect (sigc::mem_fun(*this, &Editor::collect_new_region_view));
4441 playlist = (*i)->region()->playlist();
4442 playlist->clear_changes ();
4443 playlist->duplicate (r, end_frame + (r->first_frame() - start_frame), times);
4444 _session->add_command(new StatefulDiffCommand (playlist));
4448 foo.insert (foo.end(), latest_regionviews.begin(), latest_regionviews.end());
4451 commit_reversible_command ();
4454 selection->set (foo);
4459 Editor::duplicate_selection (float times)
4461 if (selection->time.empty() || selection->tracks.empty()) {
4465 boost::shared_ptr<Playlist> playlist;
4466 vector<boost::shared_ptr<Region> > new_regions;
4467 vector<boost::shared_ptr<Region> >::iterator ri;
4469 create_region_from_selection (new_regions);
4471 if (new_regions.empty()) {
4475 begin_reversible_command (_("duplicate selection"));
4477 ri = new_regions.begin();
4479 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4481 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4482 if ((playlist = (*i)->playlist()) == 0) {
4485 playlist->clear_changes ();
4486 playlist->duplicate (*ri, selection->time[clicked_selection].end, times);
4487 _session->add_command (new StatefulDiffCommand (playlist));
4490 if (ri == new_regions.end()) {
4495 commit_reversible_command ();
4498 /** Reset all selected points to the relevant default value */
4500 Editor::reset_point_selection ()
4502 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
4503 ARDOUR::AutomationList::iterator j = (*i)->model ();
4504 (*j)->value = (*i)->line().the_list()->default_value ();
4509 Editor::center_playhead ()
4511 float const page = _visible_canvas_width * samples_per_pixel;
4512 center_screen_internal (playhead_cursor->current_frame (), page);
4516 Editor::center_edit_point ()
4518 float const page = _visible_canvas_width * samples_per_pixel;
4519 center_screen_internal (get_preferred_edit_position(), page);
4522 /** Caller must begin and commit a reversible command */
4524 Editor::clear_playlist (boost::shared_ptr<Playlist> playlist)
4526 playlist->clear_changes ();
4528 _session->add_command (new StatefulDiffCommand (playlist));
4532 Editor::nudge_track (bool use_edit, bool forwards)
4534 boost::shared_ptr<Playlist> playlist;
4535 framepos_t distance;
4536 framepos_t next_distance;
4540 start = get_preferred_edit_position();
4545 if ((distance = get_nudge_distance (start, next_distance)) == 0) {
4549 if (selection->tracks.empty()) {
4553 begin_reversible_command (_("nudge track"));
4555 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4557 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4559 if ((playlist = (*i)->playlist()) == 0) {
4563 playlist->clear_changes ();
4564 playlist->clear_owned_changes ();
4566 playlist->nudge_after (start, distance, forwards);
4568 vector<Command*> cmds;
4570 playlist->rdiff (cmds);
4571 _session->add_commands (cmds);
4573 _session->add_command (new StatefulDiffCommand (playlist));
4576 commit_reversible_command ();
4580 Editor::remove_last_capture ()
4582 vector<string> choices;
4589 if (Config->get_verify_remove_last_capture()) {
4590 prompt = _("Do you really want to destroy the last capture?"
4591 "\n(This is destructive and cannot be undone)");
4593 choices.push_back (_("No, do nothing."));
4594 choices.push_back (_("Yes, destroy it."));
4596 Gtkmm2ext::Choice prompter (_("Destroy last capture"), prompt, choices);
4598 if (prompter.run () == 1) {
4599 _session->remove_last_capture ();
4600 _regions->redisplay ();
4604 _session->remove_last_capture();
4605 _regions->redisplay ();
4610 Editor::normalize_region ()
4616 RegionSelection rs = get_regions_from_selection_and_entered ();
4622 NormalizeDialog dialog (rs.size() > 1);
4624 if (dialog.run () == RESPONSE_CANCEL) {
4628 set_canvas_cursor (_cursors->wait);
4631 /* XXX: should really only count audio regions here */
4632 int const regions = rs.size ();
4634 /* Make a list of the selected audio regions' maximum amplitudes, and also
4635 obtain the maximum amplitude of them all.
4637 list<double> max_amps;
4639 for (RegionSelection::const_iterator i = rs.begin(); i != rs.end(); ++i) {
4640 AudioRegionView const * arv = dynamic_cast<AudioRegionView const *> (*i);
4642 dialog.descend (1.0 / regions);
4643 double const a = arv->audio_region()->maximum_amplitude (&dialog);
4646 /* the user cancelled the operation */
4647 set_canvas_cursor (current_canvas_cursor);
4651 max_amps.push_back (a);
4652 max_amp = max (max_amp, a);
4657 begin_reversible_command (_("normalize"));
4659 list<double>::const_iterator a = max_amps.begin ();
4661 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
4662 AudioRegionView* const arv = dynamic_cast<AudioRegionView*> (*r);
4667 arv->region()->clear_changes ();
4669 double const amp = dialog.normalize_individually() ? *a : max_amp;
4671 arv->audio_region()->normalize (amp, dialog.target ());
4672 _session->add_command (new StatefulDiffCommand (arv->region()));
4677 commit_reversible_command ();
4678 set_canvas_cursor (current_canvas_cursor);
4683 Editor::reset_region_scale_amplitude ()
4689 RegionSelection rs = get_regions_from_selection_and_entered ();
4695 begin_reversible_command ("reset gain");
4697 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
4698 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
4701 arv->region()->clear_changes ();
4702 arv->audio_region()->set_scale_amplitude (1.0f);
4703 _session->add_command (new StatefulDiffCommand (arv->region()));
4706 commit_reversible_command ();
4710 Editor::adjust_region_gain (bool up)
4712 RegionSelection rs = get_regions_from_selection_and_entered ();
4714 if (!_session || rs.empty()) {
4718 begin_reversible_command ("adjust region gain");
4720 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
4721 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
4726 arv->region()->clear_changes ();
4728 double dB = accurate_coefficient_to_dB (arv->audio_region()->scale_amplitude ());
4736 arv->audio_region()->set_scale_amplitude (dB_to_coefficient (dB));
4737 _session->add_command (new StatefulDiffCommand (arv->region()));
4740 commit_reversible_command ();
4745 Editor::reverse_region ()
4751 Reverse rev (*_session);
4752 apply_filter (rev, _("reverse regions"));
4756 Editor::strip_region_silence ()
4762 RegionSelection rs = get_regions_from_selection_and_entered ();
4768 std::list<RegionView*> audio_only;
4770 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
4771 AudioRegionView* const arv = dynamic_cast<AudioRegionView*> (*i);
4773 audio_only.push_back (arv);
4777 StripSilenceDialog d (_session, audio_only);
4778 int const r = d.run ();
4782 if (r == Gtk::RESPONSE_OK) {
4783 ARDOUR::AudioIntervalMap silences;
4784 d.silences (silences);
4785 StripSilence s (*_session, silences, d.fade_length());
4786 apply_filter (s, _("strip silence"), &d);
4791 Editor::apply_midi_note_edit_op_to_region (MidiOperator& op, MidiRegionView& mrv)
4793 Evoral::Sequence<Evoral::MusicalTime>::Notes selected;
4794 mrv.selection_as_notelist (selected, true);
4796 vector<Evoral::Sequence<Evoral::MusicalTime>::Notes> v;
4797 v.push_back (selected);
4799 framepos_t pos_frames = mrv.midi_region()->position() - mrv.midi_region()->start();
4800 double pos_beats = _session->tempo_map().framewalk_to_beats(0, pos_frames);
4802 return op (mrv.midi_region()->model(), pos_beats, v);
4806 Editor::apply_midi_note_edit_op (MidiOperator& op)
4810 RegionSelection rs = get_regions_from_selection_and_entered ();
4816 begin_reversible_command (op.name ());
4818 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
4819 RegionSelection::iterator tmp = r;
4822 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*r);
4825 cmd = apply_midi_note_edit_op_to_region (op, *mrv);
4828 _session->add_command (cmd);
4835 commit_reversible_command ();
4839 Editor::fork_region ()
4841 RegionSelection rs = get_regions_from_selection_and_entered ();
4847 begin_reversible_command (_("Fork Region(s)"));
4849 set_canvas_cursor (_cursors->wait);
4852 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
4853 RegionSelection::iterator tmp = r;
4856 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*>(*r);
4860 boost::shared_ptr<Playlist> playlist = mrv->region()->playlist();
4861 boost::shared_ptr<MidiSource> new_source = _session->create_midi_source_by_stealing_name (mrv->midi_view()->track());
4862 boost::shared_ptr<MidiRegion> newregion = mrv->midi_region()->clone (new_source);
4864 playlist->clear_changes ();
4865 playlist->replace_region (mrv->region(), newregion, mrv->region()->position());
4866 _session->add_command(new StatefulDiffCommand (playlist));
4868 error << string_compose (_("Could not unlink %1"), mrv->region()->name()) << endmsg;
4875 commit_reversible_command ();
4877 set_canvas_cursor (current_canvas_cursor);
4881 Editor::quantize_region ()
4883 int selected_midi_region_cnt = 0;
4889 RegionSelection rs = get_regions_from_selection_and_entered ();
4895 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
4896 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*r);
4898 selected_midi_region_cnt++;
4902 if (selected_midi_region_cnt == 0) {
4906 QuantizeDialog* qd = new QuantizeDialog (*this);
4909 const int r = qd->run ();
4912 if (r == Gtk::RESPONSE_OK) {
4913 Quantize quant (*_session, qd->snap_start(), qd->snap_end(),
4914 qd->start_grid_size(), qd->end_grid_size(),
4915 qd->strength(), qd->swing(), qd->threshold());
4917 apply_midi_note_edit_op (quant);
4922 Editor::insert_patch_change (bool from_context)
4924 RegionSelection rs = get_regions_from_selection_and_entered ();
4930 const framepos_t p = get_preferred_edit_position (false, from_context);
4932 /* XXX: bit of a hack; use the MIDNAM from the first selected region;
4933 there may be more than one, but the PatchChangeDialog can only offer
4934 one set of patch menus.
4936 MidiRegionView* first = dynamic_cast<MidiRegionView*> (rs.front ());
4938 Evoral::PatchChange<Evoral::MusicalTime> empty (0, 0, 0, 0);
4939 PatchChangeDialog d (0, _session, empty, first->instrument_info(), Gtk::Stock::ADD);
4941 if (d.run() == RESPONSE_CANCEL) {
4945 for (RegionSelection::iterator i = rs.begin (); i != rs.end(); ++i) {
4946 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*i);
4948 if (p >= mrv->region()->first_frame() && p <= mrv->region()->last_frame()) {
4949 mrv->add_patch_change (p - mrv->region()->position(), d.patch ());
4956 Editor::apply_filter (Filter& filter, string command, ProgressReporter* progress)
4958 RegionSelection rs = get_regions_from_selection_and_entered ();
4964 begin_reversible_command (command);
4966 set_canvas_cursor (_cursors->wait);
4970 int const N = rs.size ();
4972 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
4973 RegionSelection::iterator tmp = r;
4976 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
4978 boost::shared_ptr<Playlist> playlist = arv->region()->playlist();
4981 progress->descend (1.0 / N);
4984 if (arv->audio_region()->apply (filter, progress) == 0) {
4986 playlist->clear_changes ();
4987 playlist->clear_owned_changes ();
4989 if (filter.results.empty ()) {
4991 /* no regions returned; remove the old one */
4992 playlist->remove_region (arv->region ());
4996 std::vector<boost::shared_ptr<Region> >::iterator res = filter.results.begin ();
4998 /* first region replaces the old one */
4999 playlist->replace_region (arv->region(), *res, (*res)->position());
5003 while (res != filter.results.end()) {
5004 playlist->add_region (*res, (*res)->position());
5010 /* We might have removed regions, which alters other regions' layering_index,
5011 so we need to do a recursive diff here.
5013 vector<Command*> cmds;
5014 playlist->rdiff (cmds);
5015 _session->add_commands (cmds);
5017 _session->add_command(new StatefulDiffCommand (playlist));
5023 progress->ascend ();
5031 commit_reversible_command ();
5034 set_canvas_cursor (current_canvas_cursor);
5038 Editor::external_edit_region ()
5044 Editor::reset_region_gain_envelopes ()
5046 RegionSelection rs = get_regions_from_selection_and_entered ();
5048 if (!_session || rs.empty()) {
5052 _session->begin_reversible_command (_("reset region gain"));
5054 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5055 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
5057 boost::shared_ptr<AutomationList> alist (arv->audio_region()->envelope());
5058 XMLNode& before (alist->get_state());
5060 arv->audio_region()->set_default_envelope ();
5061 _session->add_command (new MementoCommand<AutomationList>(*arv->audio_region()->envelope().get(), &before, &alist->get_state()));
5065 _session->commit_reversible_command ();
5069 Editor::set_region_gain_visibility (RegionView* rv)
5071 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (rv);
5073 arv->update_envelope_visibility();
5078 Editor::set_gain_envelope_visibility ()
5084 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5085 AudioTimeAxisView* v = dynamic_cast<AudioTimeAxisView*>(*i);
5087 v->audio_view()->foreach_regionview (sigc::mem_fun (this, &Editor::set_region_gain_visibility));
5093 Editor::toggle_gain_envelope_active ()
5095 if (_ignore_region_action) {
5099 RegionSelection rs = get_regions_from_selection_and_entered ();
5101 if (!_session || rs.empty()) {
5105 _session->begin_reversible_command (_("region gain envelope active"));
5107 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5108 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
5110 arv->region()->clear_changes ();
5111 arv->audio_region()->set_envelope_active (!arv->audio_region()->envelope_active());
5112 _session->add_command (new StatefulDiffCommand (arv->region()));
5116 _session->commit_reversible_command ();
5120 Editor::toggle_region_lock ()
5122 if (_ignore_region_action) {
5126 RegionSelection rs = get_regions_from_selection_and_entered ();
5128 if (!_session || rs.empty()) {
5132 _session->begin_reversible_command (_("toggle region lock"));
5134 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5135 (*i)->region()->clear_changes ();
5136 (*i)->region()->set_locked (!(*i)->region()->locked());
5137 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5140 _session->commit_reversible_command ();
5144 Editor::toggle_region_video_lock ()
5146 if (_ignore_region_action) {
5150 RegionSelection rs = get_regions_from_selection_and_entered ();
5152 if (!_session || rs.empty()) {
5156 _session->begin_reversible_command (_("Toggle Video Lock"));
5158 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5159 (*i)->region()->clear_changes ();
5160 (*i)->region()->set_video_locked (!(*i)->region()->video_locked());
5161 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5164 _session->commit_reversible_command ();
5168 Editor::toggle_region_lock_style ()
5170 if (_ignore_region_action) {
5174 RegionSelection rs = get_regions_from_selection_and_entered ();
5176 if (!_session || rs.empty()) {
5180 _session->begin_reversible_command (_("region lock style"));
5182 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5183 (*i)->region()->clear_changes ();
5184 PositionLockStyle const ns = (*i)->region()->position_lock_style() == AudioTime ? MusicTime : AudioTime;
5185 (*i)->region()->set_position_lock_style (ns);
5186 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5189 _session->commit_reversible_command ();
5193 Editor::toggle_opaque_region ()
5195 if (_ignore_region_action) {
5199 RegionSelection rs = get_regions_from_selection_and_entered ();
5201 if (!_session || rs.empty()) {
5205 _session->begin_reversible_command (_("change region opacity"));
5207 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5208 (*i)->region()->clear_changes ();
5209 (*i)->region()->set_opaque (!(*i)->region()->opaque());
5210 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5213 _session->commit_reversible_command ();
5217 Editor::toggle_record_enable ()
5219 bool new_state = false;
5221 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5222 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5225 if (!rtav->is_track())
5229 new_state = !rtav->track()->record_enabled();
5233 rtav->track()->set_record_enabled (new_state, this);
5238 Editor::toggle_solo ()
5240 bool new_state = false;
5242 boost::shared_ptr<RouteList> rl (new RouteList);
5244 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5245 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5252 new_state = !rtav->route()->soloed ();
5256 rl->push_back (rtav->route());
5259 _session->set_solo (rl, new_state, Session::rt_cleanup, true);
5263 Editor::toggle_mute ()
5265 bool new_state = false;
5267 boost::shared_ptr<RouteList> rl (new RouteList);
5269 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5270 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5277 new_state = !rtav->route()->muted();
5281 rl->push_back (rtav->route());
5284 _session->set_mute (rl, new_state, Session::rt_cleanup, true);
5288 Editor::toggle_solo_isolate ()
5294 Editor::fade_range ()
5296 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
5298 begin_reversible_command (_("fade range"));
5300 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
5301 (*i)->fade_range (selection->time);
5304 commit_reversible_command ();
5309 Editor::set_fade_length (bool in)
5311 RegionSelection rs = get_regions_from_selection_and_entered ();
5317 /* we need a region to measure the offset from the start */
5319 RegionView* rv = rs.front ();
5321 framepos_t pos = get_preferred_edit_position();
5325 if (pos > rv->region()->last_frame() || pos < rv->region()->first_frame()) {
5326 /* edit point is outside the relevant region */
5331 if (pos <= rv->region()->position()) {
5335 len = pos - rv->region()->position();
5336 cmd = _("set fade in length");
5338 if (pos >= rv->region()->last_frame()) {
5342 len = rv->region()->last_frame() - pos;
5343 cmd = _("set fade out length");
5346 begin_reversible_command (cmd);
5348 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5349 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5355 boost::shared_ptr<AutomationList> alist;
5357 alist = tmp->audio_region()->fade_in();
5359 alist = tmp->audio_region()->fade_out();
5362 XMLNode &before = alist->get_state();
5365 tmp->audio_region()->set_fade_in_length (len);
5366 tmp->audio_region()->set_fade_in_active (true);
5368 tmp->audio_region()->set_fade_out_length (len);
5369 tmp->audio_region()->set_fade_out_active (true);
5372 XMLNode &after = alist->get_state();
5373 _session->add_command(new MementoCommand<AutomationList>(*alist, &before, &after));
5376 commit_reversible_command ();
5380 Editor::set_fade_in_shape (FadeShape shape)
5382 RegionSelection rs = get_regions_from_selection_and_entered ();
5388 begin_reversible_command (_("set fade in shape"));
5390 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5391 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5397 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_in();
5398 XMLNode &before = alist->get_state();
5400 tmp->audio_region()->set_fade_in_shape (shape);
5402 XMLNode &after = alist->get_state();
5403 _session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
5406 commit_reversible_command ();
5411 Editor::set_fade_out_shape (FadeShape shape)
5413 RegionSelection rs = get_regions_from_selection_and_entered ();
5419 begin_reversible_command (_("set fade out shape"));
5421 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5422 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5428 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_out();
5429 XMLNode &before = alist->get_state();
5431 tmp->audio_region()->set_fade_out_shape (shape);
5433 XMLNode &after = alist->get_state();
5434 _session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
5437 commit_reversible_command ();
5441 Editor::set_fade_in_active (bool yn)
5443 RegionSelection rs = get_regions_from_selection_and_entered ();
5449 begin_reversible_command (_("set fade in active"));
5451 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5452 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5459 boost::shared_ptr<AudioRegion> ar (tmp->audio_region());
5461 ar->clear_changes ();
5462 ar->set_fade_in_active (yn);
5463 _session->add_command (new StatefulDiffCommand (ar));
5466 commit_reversible_command ();
5470 Editor::set_fade_out_active (bool yn)
5472 RegionSelection rs = get_regions_from_selection_and_entered ();
5478 begin_reversible_command (_("set fade out active"));
5480 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5481 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5487 boost::shared_ptr<AudioRegion> ar (tmp->audio_region());
5489 ar->clear_changes ();
5490 ar->set_fade_out_active (yn);
5491 _session->add_command(new StatefulDiffCommand (ar));
5494 commit_reversible_command ();
5498 Editor::toggle_region_fades (int dir)
5500 if (_ignore_region_action) {
5504 boost::shared_ptr<AudioRegion> ar;
5507 RegionSelection rs = get_regions_from_selection_and_entered ();
5513 RegionSelection::iterator i;
5514 for (i = rs.begin(); i != rs.end(); ++i) {
5515 if ((ar = boost::dynamic_pointer_cast<AudioRegion>((*i)->region())) != 0) {
5517 yn = ar->fade_out_active ();
5519 yn = ar->fade_in_active ();
5525 if (i == rs.end()) {
5529 /* XXX should this undo-able? */
5531 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5532 if ((ar = boost::dynamic_pointer_cast<AudioRegion>((*i)->region())) == 0) {
5535 if (dir == 1 || dir == 0) {
5536 ar->set_fade_in_active (!yn);
5539 if (dir == -1 || dir == 0) {
5540 ar->set_fade_out_active (!yn);
5546 /** Update region fade visibility after its configuration has been changed */
5548 Editor::update_region_fade_visibility ()
5550 bool _fade_visibility = _session->config.get_show_region_fades ();
5552 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5553 AudioTimeAxisView* v = dynamic_cast<AudioTimeAxisView*>(*i);
5555 if (_fade_visibility) {
5556 v->audio_view()->show_all_fades ();
5558 v->audio_view()->hide_all_fades ();
5565 Editor::set_edit_point ()
5570 if (!mouse_frame (where, ignored)) {
5576 if (selection->markers.empty()) {
5578 mouse_add_new_marker (where);
5583 Location* loc = find_location_from_marker (selection->markers.front(), ignored);
5586 loc->move_to (where);
5592 Editor::set_playhead_cursor ()
5594 if (entered_marker) {
5595 _session->request_locate (entered_marker->position(), _session->transport_rolling());
5600 if (!mouse_frame (where, ignored)) {
5607 _session->request_locate (where, _session->transport_rolling());
5611 if ( Config->get_follow_edits() )
5612 cancel_time_selection();
5616 Editor::split_region ()
5618 if ( !selection->time.empty()) {
5619 separate_regions_between (selection->time);
5623 RegionSelection rs = get_regions_from_selection_and_edit_point ();
5625 framepos_t where = get_preferred_edit_position ();
5631 split_regions_at (where, rs);
5634 struct EditorOrderRouteSorter {
5635 bool operator() (boost::shared_ptr<Route> a, boost::shared_ptr<Route> b) {
5636 return a->order_key () < b->order_key ();
5641 Editor::select_next_route()
5643 if (selection->tracks.empty()) {
5644 selection->set (track_views.front());
5648 TimeAxisView* current = selection->tracks.front();
5652 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5653 if (*i == current) {
5655 if (i != track_views.end()) {
5658 current = (*(track_views.begin()));
5659 //selection->set (*(track_views.begin()));
5664 rui = dynamic_cast<RouteUI *>(current);
5665 } while ( current->hidden() || (rui != NULL && !rui->route()->active()));
5667 selection->set(current);
5669 ensure_time_axis_view_is_visible (*current, false);
5673 Editor::select_prev_route()
5675 if (selection->tracks.empty()) {
5676 selection->set (track_views.front());
5680 TimeAxisView* current = selection->tracks.front();
5684 for (TrackViewList::reverse_iterator i = track_views.rbegin(); i != track_views.rend(); ++i) {
5685 if (*i == current) {
5687 if (i != track_views.rend()) {
5690 current = *(track_views.rbegin());
5695 rui = dynamic_cast<RouteUI *>(current);
5696 } while ( current->hidden() || (rui != NULL && !rui->route()->active()));
5698 selection->set (current);
5700 ensure_time_axis_view_is_visible (*current, false);
5704 Editor::set_loop_from_selection (bool play)
5706 if (_session == 0 || selection->time.empty()) {
5710 framepos_t start = selection->time[clicked_selection].start;
5711 framepos_t end = selection->time[clicked_selection].end;
5713 set_loop_range (start, end, _("set loop range from selection"));
5716 _session->request_play_loop (true);
5717 _session->request_locate (start, true);
5722 Editor::set_loop_from_edit_range (bool play)
5724 if (_session == 0) {
5731 if (!get_edit_op_range (start, end)) {
5735 set_loop_range (start, end, _("set loop range from edit range"));
5738 _session->request_play_loop (true);
5739 _session->request_locate (start, true);
5744 Editor::set_loop_from_region (bool play)
5746 framepos_t start = max_framepos;
5749 RegionSelection rs = get_regions_from_selection_and_entered ();
5755 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5756 if ((*i)->region()->position() < start) {
5757 start = (*i)->region()->position();
5759 if ((*i)->region()->last_frame() + 1 > end) {
5760 end = (*i)->region()->last_frame() + 1;
5764 set_loop_range (start, end, _("set loop range from region"));
5767 _session->request_play_loop (true);
5768 _session->request_locate (start, true);
5773 Editor::set_punch_from_selection ()
5775 if (_session == 0 || selection->time.empty()) {
5779 framepos_t start = selection->time[clicked_selection].start;
5780 framepos_t end = selection->time[clicked_selection].end;
5782 set_punch_range (start, end, _("set punch range from selection"));
5786 Editor::set_punch_from_edit_range ()
5788 if (_session == 0) {
5795 if (!get_edit_op_range (start, end)) {
5799 set_punch_range (start, end, _("set punch range from edit range"));
5803 Editor::set_punch_from_region ()
5805 framepos_t start = max_framepos;
5808 RegionSelection rs = get_regions_from_selection_and_entered ();
5814 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5815 if ((*i)->region()->position() < start) {
5816 start = (*i)->region()->position();
5818 if ((*i)->region()->last_frame() + 1 > end) {
5819 end = (*i)->region()->last_frame() + 1;
5823 set_punch_range (start, end, _("set punch range from region"));
5827 Editor::pitch_shift_region ()
5829 RegionSelection rs = get_regions_from_selection_and_entered ();
5831 RegionSelection audio_rs;
5832 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5833 if (dynamic_cast<AudioRegionView*> (*i)) {
5834 audio_rs.push_back (*i);
5838 if (audio_rs.empty()) {
5842 pitch_shift (audio_rs, 1.2);
5846 Editor::transpose_region ()
5848 RegionSelection rs = get_regions_from_selection_and_entered ();
5850 list<MidiRegionView*> midi_region_views;
5851 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5852 MidiRegionView* mrv = dynamic_cast<MidiRegionView*> (*i);
5854 midi_region_views.push_back (mrv);
5859 int const r = d.run ();
5860 if (r != RESPONSE_ACCEPT) {
5864 for (list<MidiRegionView*>::iterator i = midi_region_views.begin(); i != midi_region_views.end(); ++i) {
5865 (*i)->midi_region()->transpose (d.semitones ());
5870 Editor::set_tempo_from_region ()
5872 RegionSelection rs = get_regions_from_selection_and_entered ();
5874 if (!_session || rs.empty()) {
5878 RegionView* rv = rs.front();
5880 define_one_bar (rv->region()->position(), rv->region()->last_frame() + 1);
5884 Editor::use_range_as_bar ()
5886 framepos_t start, end;
5887 if (get_edit_op_range (start, end)) {
5888 define_one_bar (start, end);
5893 Editor::define_one_bar (framepos_t start, framepos_t end)
5895 framepos_t length = end - start;
5897 const Meter& m (_session->tempo_map().meter_at (start));
5899 /* length = 1 bar */
5901 /* now we want frames per beat.
5902 we have frames per bar, and beats per bar, so ...
5905 /* XXXX METER MATH */
5907 double frames_per_beat = length / m.divisions_per_bar();
5909 /* beats per minute = */
5911 double beats_per_minute = (_session->frame_rate() * 60.0) / frames_per_beat;
5913 /* now decide whether to:
5915 (a) set global tempo
5916 (b) add a new tempo marker
5920 const TempoSection& t (_session->tempo_map().tempo_section_at (start));
5922 bool do_global = false;
5924 if ((_session->tempo_map().n_tempos() == 1) && (_session->tempo_map().n_meters() == 1)) {
5926 /* only 1 tempo & 1 meter: ask if the user wants to set the tempo
5927 at the start, or create a new marker
5930 vector<string> options;
5931 options.push_back (_("Cancel"));
5932 options.push_back (_("Add new marker"));
5933 options.push_back (_("Set global tempo"));
5936 _("Define one bar"),
5937 _("Do you want to set the global tempo or add a new tempo marker?"),
5941 c.set_default_response (2);
5957 /* more than 1 tempo and/or meter section already, go ahead do the "usual":
5958 if the marker is at the region starter, change it, otherwise add
5963 begin_reversible_command (_("set tempo from region"));
5964 XMLNode& before (_session->tempo_map().get_state());
5967 _session->tempo_map().change_initial_tempo (beats_per_minute, t.note_type());
5968 } else if (t.frame() == start) {
5969 _session->tempo_map().change_existing_tempo_at (start, beats_per_minute, t.note_type());
5971 Timecode::BBT_Time bbt;
5972 _session->tempo_map().bbt_time (start, bbt);
5973 _session->tempo_map().add_tempo (Tempo (beats_per_minute, t.note_type()), bbt);
5976 XMLNode& after (_session->tempo_map().get_state());
5978 _session->add_command (new MementoCommand<TempoMap>(_session->tempo_map(), &before, &after));
5979 commit_reversible_command ();
5983 Editor::split_region_at_transients ()
5985 AnalysisFeatureList positions;
5987 RegionSelection rs = get_regions_from_selection_and_entered ();
5989 if (!_session || rs.empty()) {
5993 _session->begin_reversible_command (_("split regions"));
5995 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ) {
5997 RegionSelection::iterator tmp;
6002 boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion> ((*i)->region());
6004 if (ar && (ar->get_transients (positions) == 0)) {
6005 split_region_at_points ((*i)->region(), positions, true);
6012 _session->commit_reversible_command ();
6017 Editor::split_region_at_points (boost::shared_ptr<Region> r, AnalysisFeatureList& positions, bool can_ferret, bool select_new)
6019 bool use_rhythmic_rodent = false;
6021 boost::shared_ptr<Playlist> pl = r->playlist();
6023 list<boost::shared_ptr<Region> > new_regions;
6029 if (positions.empty()) {
6034 if (positions.size() > 20 && can_ferret) {
6035 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);
6036 MessageDialog msg (msgstr,
6039 Gtk::BUTTONS_OK_CANCEL);
6042 msg.add_button (_("Call for the Ferret!"), RESPONSE_APPLY);
6043 msg.set_secondary_text (_("Press OK to continue with this split operation\nor ask the Ferret dialog to tune the analysis"));
6045 msg.set_secondary_text (_("Press OK to continue with this split operation"));
6048 msg.set_title (_("Excessive split?"));
6051 int response = msg.run();
6057 case RESPONSE_APPLY:
6058 use_rhythmic_rodent = true;
6065 if (use_rhythmic_rodent) {
6066 show_rhythm_ferret ();
6070 AnalysisFeatureList::const_iterator x;
6072 pl->clear_changes ();
6073 pl->clear_owned_changes ();
6075 x = positions.begin();
6077 if (x == positions.end()) {
6082 pl->remove_region (r);
6086 while (x != positions.end()) {
6088 /* deal with positons that are out of scope of present region bounds */
6089 if (*x <= 0 || *x > r->length()) {
6094 /* file start = original start + how far we from the initial position ?
6097 framepos_t file_start = r->start() + pos;
6099 /* length = next position - current position
6102 framepos_t len = (*x) - pos;
6104 /* XXX we do we really want to allow even single-sample regions?
6105 shouldn't we have some kind of lower limit on region size?
6114 if (RegionFactory::region_name (new_name, r->name())) {
6118 /* do NOT announce new regions 1 by one, just wait till they are all done */
6122 plist.add (ARDOUR::Properties::start, file_start);
6123 plist.add (ARDOUR::Properties::length, len);
6124 plist.add (ARDOUR::Properties::name, new_name);
6125 plist.add (ARDOUR::Properties::layer, 0);
6127 boost::shared_ptr<Region> nr = RegionFactory::create (r->sources(), plist, false);
6128 /* because we set annouce to false, manually add the new region to the
6131 RegionFactory::map_add (nr);
6133 pl->add_region (nr, r->position() + pos);
6136 new_regions.push_front(nr);
6145 RegionFactory::region_name (new_name, r->name());
6147 /* Add the final region */
6150 plist.add (ARDOUR::Properties::start, r->start() + pos);
6151 plist.add (ARDOUR::Properties::length, r->last_frame() - (r->position() + pos) + 1);
6152 plist.add (ARDOUR::Properties::name, new_name);
6153 plist.add (ARDOUR::Properties::layer, 0);
6155 boost::shared_ptr<Region> nr = RegionFactory::create (r->sources(), plist, false);
6156 /* because we set annouce to false, manually add the new region to the
6159 RegionFactory::map_add (nr);
6160 pl->add_region (nr, r->position() + pos);
6163 new_regions.push_front(nr);
6168 /* We might have removed regions, which alters other regions' layering_index,
6169 so we need to do a recursive diff here.
6171 vector<Command*> cmds;
6173 _session->add_commands (cmds);
6175 _session->add_command (new StatefulDiffCommand (pl));
6179 for (list<boost::shared_ptr<Region> >::iterator i = new_regions.begin(); i != new_regions.end(); ++i){
6180 set_selected_regionview_from_region_list ((*i), Selection::Add);
6186 Editor::place_transient()
6192 RegionSelection rs = get_regions_from_selection_and_edit_point ();
6198 framepos_t where = get_preferred_edit_position();
6200 _session->begin_reversible_command (_("place transient"));
6202 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6203 framepos_t position = (*r)->region()->position();
6204 (*r)->region()->add_transient(where - position);
6207 _session->commit_reversible_command ();
6211 Editor::remove_transient(ArdourCanvas::Item* item)
6217 ArdourCanvas::Line* _line = reinterpret_cast<ArdourCanvas::Line*> (item);
6220 AudioRegionView* _arv = reinterpret_cast<AudioRegionView*> (item->get_data ("regionview"));
6221 _arv->remove_transient (*(float*) _line->get_data ("position"));
6225 Editor::snap_regions_to_grid ()
6227 list <boost::shared_ptr<Playlist > > used_playlists;
6229 RegionSelection rs = get_regions_from_selection_and_entered ();
6231 if (!_session || rs.empty()) {
6235 _session->begin_reversible_command (_("snap regions to grid"));
6237 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6239 boost::shared_ptr<Playlist> pl = (*r)->region()->playlist();
6241 if (!pl->frozen()) {
6242 /* we haven't seen this playlist before */
6244 /* remember used playlists so we can thaw them later */
6245 used_playlists.push_back(pl);
6249 framepos_t start_frame = (*r)->region()->first_frame ();
6250 snap_to (start_frame);
6251 (*r)->region()->set_position (start_frame);
6254 while (used_playlists.size() > 0) {
6255 list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
6257 used_playlists.pop_front();
6260 _session->commit_reversible_command ();
6264 Editor::close_region_gaps ()
6266 list <boost::shared_ptr<Playlist > > used_playlists;
6268 RegionSelection rs = get_regions_from_selection_and_entered ();
6270 if (!_session || rs.empty()) {
6274 Dialog dialog (_("Close Region Gaps"));
6277 table.set_spacings (12);
6278 table.set_border_width (12);
6279 Label* l = manage (left_aligned_label (_("Crossfade length")));
6280 table.attach (*l, 0, 1, 0, 1);
6282 SpinButton spin_crossfade (1, 0);
6283 spin_crossfade.set_range (0, 15);
6284 spin_crossfade.set_increments (1, 1);
6285 spin_crossfade.set_value (5);
6286 table.attach (spin_crossfade, 1, 2, 0, 1);
6288 table.attach (*manage (new Label (_("ms"))), 2, 3, 0, 1);
6290 l = manage (left_aligned_label (_("Pull-back length")));
6291 table.attach (*l, 0, 1, 1, 2);
6293 SpinButton spin_pullback (1, 0);
6294 spin_pullback.set_range (0, 100);
6295 spin_pullback.set_increments (1, 1);
6296 spin_pullback.set_value(30);
6297 table.attach (spin_pullback, 1, 2, 1, 2);
6299 table.attach (*manage (new Label (_("ms"))), 2, 3, 1, 2);
6301 dialog.get_vbox()->pack_start (table);
6302 dialog.add_button (Stock::CANCEL, RESPONSE_CANCEL);
6303 dialog.add_button (_("Ok"), RESPONSE_ACCEPT);
6306 if (dialog.run () == RESPONSE_CANCEL) {
6310 framepos_t crossfade_len = spin_crossfade.get_value();
6311 framepos_t pull_back_frames = spin_pullback.get_value();
6313 crossfade_len = lrintf (crossfade_len * _session->frame_rate()/1000);
6314 pull_back_frames = lrintf (pull_back_frames * _session->frame_rate()/1000);
6316 /* Iterate over the region list and make adjacent regions overlap by crossfade_len_ms */
6318 _session->begin_reversible_command (_("close region gaps"));
6321 boost::shared_ptr<Region> last_region;
6323 rs.sort_by_position_and_track();
6325 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6327 boost::shared_ptr<Playlist> pl = (*r)->region()->playlist();
6329 if (!pl->frozen()) {
6330 /* we haven't seen this playlist before */
6332 /* remember used playlists so we can thaw them later */
6333 used_playlists.push_back(pl);
6337 framepos_t position = (*r)->region()->position();
6339 if (idx == 0 || position < last_region->position()){
6340 last_region = (*r)->region();
6345 (*r)->region()->trim_front( (position - pull_back_frames));
6346 last_region->trim_end( (position - pull_back_frames + crossfade_len));
6348 last_region = (*r)->region();
6353 while (used_playlists.size() > 0) {
6354 list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
6356 used_playlists.pop_front();
6359 _session->commit_reversible_command ();
6363 Editor::tab_to_transient (bool forward)
6365 AnalysisFeatureList positions;
6367 RegionSelection rs = get_regions_from_selection_and_entered ();
6373 framepos_t pos = _session->audible_frame ();
6375 if (!selection->tracks.empty()) {
6377 /* don't waste time searching for transients in duplicate playlists.
6380 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
6382 for (TrackViewList::iterator t = ts.begin(); t != ts.end(); ++t) {
6384 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*t);
6387 boost::shared_ptr<Track> tr = rtv->track();
6389 boost::shared_ptr<Playlist> pl = tr->playlist ();
6391 framepos_t result = pl->find_next_transient (pos, forward ? 1 : -1);
6394 positions.push_back (result);
6407 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6408 (*r)->region()->get_transients (positions);
6412 TransientDetector::cleanup_transients (positions, _session->frame_rate(), 3.0);
6415 AnalysisFeatureList::iterator x;
6417 for (x = positions.begin(); x != positions.end(); ++x) {
6423 if (x != positions.end ()) {
6424 _session->request_locate (*x);
6428 AnalysisFeatureList::reverse_iterator x;
6430 for (x = positions.rbegin(); x != positions.rend(); ++x) {
6436 if (x != positions.rend ()) {
6437 _session->request_locate (*x);
6443 Editor::playhead_forward_to_grid ()
6449 framepos_t pos = playhead_cursor->current_frame ();
6450 if (pos < max_framepos - 1) {
6452 snap_to_internal (pos, 1, false);
6453 _session->request_locate (pos);
6459 Editor::playhead_backward_to_grid ()
6465 framepos_t pos = playhead_cursor->current_frame ();
6468 snap_to_internal (pos, -1, false);
6469 _session->request_locate (pos);
6474 Editor::set_track_height (Height h)
6476 TrackSelection& ts (selection->tracks);
6478 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
6479 (*x)->set_height_enum (h);
6484 Editor::toggle_tracks_active ()
6486 TrackSelection& ts (selection->tracks);
6488 bool target = false;
6494 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
6495 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*x);
6499 target = !rtv->_route->active();
6502 rtv->_route->set_active (target, this);
6508 Editor::remove_tracks ()
6510 TrackSelection& ts (selection->tracks);
6516 vector<string> choices;
6520 const char* trackstr;
6522 vector<boost::shared_ptr<Route> > routes;
6523 bool special_bus = false;
6525 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
6526 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*x);
6530 if (rtv->is_track()) {
6535 routes.push_back (rtv->_route);
6537 if (rtv->route()->is_master() || rtv->route()->is_monitor()) {
6542 if (special_bus && !Config->get_allow_special_bus_removal()) {
6543 MessageDialog msg (_("That would be bad news ...."),
6547 msg.set_secondary_text (string_compose (_(
6548 "Removing the master or monitor bus is such a bad idea\n\
6549 that %1 is not going to allow it.\n\
6551 If you really want to do this sort of thing\n\
6552 edit your ardour.rc file to set the\n\
6553 \"allow-special-bus-removal\" option to be \"yes\""), PROGRAM_NAME));
6560 if (ntracks + nbusses == 0) {
6565 trackstr = _("tracks");
6567 trackstr = _("track");
6571 busstr = _("busses");
6578 prompt = string_compose (_("Do you really want to remove %1 %2 and %3 %4?\n"
6579 "(You may also lose the playlists associated with the %2)\n\n"
6580 "This action cannot be undone, and the session file will be overwritten!"),
6581 ntracks, trackstr, nbusses, busstr);
6583 prompt = string_compose (_("Do you really want to remove %1 %2?\n"
6584 "(You may also lose the playlists associated with the %2)\n\n"
6585 "This action cannot be undone, and the session file will be overwritten!"),
6588 } else if (nbusses) {
6589 prompt = string_compose (_("Do you really want to remove %1 %2?\n\n"
6590 "This action cannot be undon, and the session file will be overwritten"),
6594 choices.push_back (_("No, do nothing."));
6595 if (ntracks + nbusses > 1) {
6596 choices.push_back (_("Yes, remove them."));
6598 choices.push_back (_("Yes, remove it."));
6603 title = string_compose (_("Remove %1"), trackstr);
6605 title = string_compose (_("Remove %1"), busstr);
6608 Choice prompter (title, prompt, choices);
6610 if (prompter.run () != 1) {
6615 Session::StateProtector sp (_session);
6616 for (vector<boost::shared_ptr<Route> >::iterator x = routes.begin(); x != routes.end(); ++x) {
6617 _session->remove_route (*x);
6623 Editor::do_insert_time ()
6625 if (selection->tracks.empty()) {
6629 InsertTimeDialog d (*this);
6630 int response = d.run ();
6632 if (response != RESPONSE_OK) {
6636 if (d.distance() == 0) {
6640 InsertTimeOption opt = d.intersected_region_action ();
6643 get_preferred_edit_position(),
6649 d.move_glued_markers(),
6650 d.move_locked_markers(),
6656 Editor::insert_time (
6657 framepos_t pos, framecnt_t frames, InsertTimeOption opt,
6658 bool all_playlists, bool ignore_music_glue, bool markers_too, bool glued_markers_too, bool locked_markers_too, bool tempo_too
6661 bool commit = false;
6663 if (Config->get_edit_mode() == Lock) {
6667 begin_reversible_command (_("insert time"));
6669 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
6671 for (TrackViewList::iterator x = ts.begin(); x != ts.end(); ++x) {
6675 /* don't operate on any playlist more than once, which could
6676 * happen if "all playlists" is enabled, but there is more
6677 * than 1 track using playlists "from" a given track.
6680 set<boost::shared_ptr<Playlist> > pl;
6682 if (all_playlists) {
6683 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*x);
6685 vector<boost::shared_ptr<Playlist> > all = _session->playlists->playlists_for_track (rtav->track ());
6686 for (vector<boost::shared_ptr<Playlist> >::iterator p = all.begin(); p != all.end(); ++p) {
6691 if ((*x)->playlist ()) {
6692 pl.insert ((*x)->playlist ());
6696 for (set<boost::shared_ptr<Playlist> >::iterator i = pl.begin(); i != pl.end(); ++i) {
6698 (*i)->clear_changes ();
6699 (*i)->clear_owned_changes ();
6701 if (opt == SplitIntersected) {
6705 (*i)->shift (pos, frames, (opt == MoveIntersected), ignore_music_glue);
6707 vector<Command*> cmds;
6709 _session->add_commands (cmds);
6711 _session->add_command (new StatefulDiffCommand (*i));
6716 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*x);
6718 rtav->route ()->shift (pos, frames);
6726 XMLNode& before (_session->locations()->get_state());
6727 Locations::LocationList copy (_session->locations()->list());
6729 for (Locations::LocationList::iterator i = copy.begin(); i != copy.end(); ++i) {
6731 Locations::LocationList::const_iterator tmp;
6733 bool const was_locked = (*i)->locked ();
6734 if (locked_markers_too) {
6738 if ((*i)->position_lock_style() == AudioTime || glued_markers_too) {
6740 if ((*i)->start() >= pos) {
6741 (*i)->set_start ((*i)->start() + frames);
6742 if (!(*i)->is_mark()) {
6743 (*i)->set_end ((*i)->end() + frames);
6756 XMLNode& after (_session->locations()->get_state());
6757 _session->add_command (new MementoCommand<Locations>(*_session->locations(), &before, &after));
6762 _session->tempo_map().insert_time (pos, frames);
6766 commit_reversible_command ();
6771 Editor::fit_selected_tracks ()
6773 if (!selection->tracks.empty()) {
6774 fit_tracks (selection->tracks);
6778 /* no selected tracks - use tracks with selected regions */
6780 if (!selection->regions.empty()) {
6781 for (RegionSelection::iterator r = selection->regions.begin(); r != selection->regions.end(); ++r) {
6782 tvl.push_back (&(*r)->get_time_axis_view ());
6788 } else if (internal_editing()) {
6789 /* no selected tracks, or regions, but in internal edit mode, so follow the mouse and use
6792 if (entered_track) {
6793 tvl.push_back (entered_track);
6802 Editor::fit_tracks (TrackViewList & tracks)
6804 if (tracks.empty()) {
6808 uint32_t child_heights = 0;
6809 int visible_tracks = 0;
6811 for (TrackSelection::iterator t = tracks.begin(); t != tracks.end(); ++t) {
6813 if (!(*t)->marked_for_display()) {
6817 child_heights += (*t)->effective_height() - (*t)->current_height();
6821 /* compute the per-track height from:
6823 total canvas visible height -
6824 height that will be taken by visible children of selected
6825 tracks - height of the ruler/hscroll area
6827 uint32_t h = (uint32_t) floor ((trackviews_height() - child_heights) / visible_tracks);
6828 double first_y_pos = DBL_MAX;
6830 if (h < TimeAxisView::preset_height (HeightSmall)) {
6831 MessageDialog msg (*this, _("There are too many tracks to fit in the current window"));
6832 /* too small to be displayed */
6836 undo_visual_stack.push_back (current_visual_state (true));
6837 no_save_visual = true;
6839 /* build a list of all tracks, including children */
6842 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
6844 TimeAxisView::Children c = (*i)->get_child_list ();
6845 for (TimeAxisView::Children::iterator j = c.begin(); j != c.end(); ++j) {
6846 all.push_back (j->get());
6850 bool prev_was_selected = false;
6851 bool is_selected = tracks.contains (all.front());
6852 bool next_is_selected;
6854 for (TrackViewList::iterator t = all.begin(); t != all.end(); ++t) {
6856 TrackViewList::iterator next;
6861 if (next != all.end()) {
6862 next_is_selected = tracks.contains (*next);
6864 next_is_selected = false;
6867 if ((*t)->marked_for_display ()) {
6869 (*t)->set_height (h);
6870 first_y_pos = std::min ((*t)->y_position (), first_y_pos);
6872 if (prev_was_selected && next_is_selected) {
6873 hide_track_in_display (*t);
6878 prev_was_selected = is_selected;
6879 is_selected = next_is_selected;
6883 set the controls_layout height now, because waiting for its size
6884 request signal handler will cause the vertical adjustment setting to fail
6887 controls_layout.property_height () = _full_canvas_height;
6888 vertical_adjustment.set_value (first_y_pos);
6890 redo_visual_stack.push_back (current_visual_state (true));
6892 visible_tracks_selector.set_text (_("Sel"));
6896 Editor::save_visual_state (uint32_t n)
6898 while (visual_states.size() <= n) {
6899 visual_states.push_back (0);
6902 if (visual_states[n] != 0) {
6903 delete visual_states[n];
6906 visual_states[n] = current_visual_state (true);
6911 Editor::goto_visual_state (uint32_t n)
6913 if (visual_states.size() <= n) {
6917 if (visual_states[n] == 0) {
6921 use_visual_state (*visual_states[n]);
6925 Editor::start_visual_state_op (uint32_t n)
6927 save_visual_state (n);
6929 PopUp* pup = new PopUp (WIN_POS_MOUSE, 1000, true);
6931 snprintf (buf, sizeof (buf), _("Saved view %u"), n+1);
6932 pup->set_text (buf);
6937 Editor::cancel_visual_state_op (uint32_t n)
6939 goto_visual_state (n);
6943 Editor::toggle_region_mute ()
6945 if (_ignore_region_action) {
6949 RegionSelection rs = get_regions_from_selection_and_entered ();
6955 if (rs.size() > 1) {
6956 begin_reversible_command (_("mute regions"));
6958 begin_reversible_command (_("mute region"));
6961 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
6963 (*i)->region()->playlist()->clear_changes ();
6964 (*i)->region()->set_muted (!(*i)->region()->muted ());
6965 _session->add_command (new StatefulDiffCommand ((*i)->region()->playlist()));
6969 commit_reversible_command ();
6973 Editor::combine_regions ()
6975 /* foreach track with selected regions, take all selected regions
6976 and join them into a new region containing the subregions (as a
6980 typedef set<RouteTimeAxisView*> RTVS;
6983 if (selection->regions.empty()) {
6987 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
6988 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(&(*i)->get_time_axis_view());
6991 tracks.insert (rtv);
6995 begin_reversible_command (_("combine regions"));
6997 vector<RegionView*> new_selection;
6999 for (RTVS::iterator i = tracks.begin(); i != tracks.end(); ++i) {
7002 if ((rv = (*i)->combine_regions ()) != 0) {
7003 new_selection.push_back (rv);
7007 selection->clear_regions ();
7008 for (vector<RegionView*>::iterator i = new_selection.begin(); i != new_selection.end(); ++i) {
7009 selection->add (*i);
7012 commit_reversible_command ();
7016 Editor::uncombine_regions ()
7018 typedef set<RouteTimeAxisView*> RTVS;
7021 if (selection->regions.empty()) {
7025 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
7026 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(&(*i)->get_time_axis_view());
7029 tracks.insert (rtv);
7033 begin_reversible_command (_("uncombine regions"));
7035 for (RTVS::iterator i = tracks.begin(); i != tracks.end(); ++i) {
7036 (*i)->uncombine_regions ();
7039 commit_reversible_command ();
7043 Editor::toggle_midi_input_active (bool flip_others)
7046 boost::shared_ptr<RouteList> rl (new RouteList);
7048 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
7049 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
7055 boost::shared_ptr<MidiTrack> mt = rtav->midi_track();
7058 rl->push_back (rtav->route());
7059 onoff = !mt->input_active();
7063 _session->set_exclusive_input_active (rl, onoff, flip_others);
7070 lock_dialog = new Gtk::Dialog (string_compose (_("%1: Locked"), PROGRAM_NAME), true);
7072 Gtk::Image* padlock = manage (new Gtk::Image (ARDOUR_UI_UTILS::get_icon ("padlock_closed")));
7073 lock_dialog->get_vbox()->pack_start (*padlock);
7075 ArdourButton* b = manage (new ArdourButton);
7076 b->set_name ("lock button");
7077 b->set_markup (string_compose ("<span size=\"large\" weight=\"bold\">%1</span>", _("Click to unlock")));
7078 b->signal_clicked.connect (sigc::mem_fun (*this, &Editor::unlock));
7079 lock_dialog->get_vbox()->pack_start (*b);
7081 lock_dialog->get_vbox()->show_all ();
7082 lock_dialog->set_size_request (200, 200);
7086 /* The global menu bar continues to be accessible to applications
7087 with modal dialogs, which means that we need to desensitize
7088 all items in the menu bar. Since those items are really just
7089 proxies for actions, that means disabling all actions.
7091 ActionManager::disable_all_actions ();
7093 lock_dialog->present ();
7099 lock_dialog->hide ();
7102 ActionManager::pop_action_state ();
7105 if (ARDOUR_UI::config()->get_lock_gui_after_seconds()) {
7106 start_lock_event_timing ();
7111 Editor::bring_in_callback (Gtk::Label* label, uint32_t n, uint32_t total, string name)
7113 Gtkmm2ext::UI::instance()->call_slot (invalidator (*this), boost::bind (&Editor::update_bring_in_message, this, label, n, total, name));
7117 Editor::update_bring_in_message (Gtk::Label* label, uint32_t n, uint32_t total, string name)
7119 label->set_text (string_compose ("Copying %1, %2 of %3", name, n, total));
7120 Gtkmm2ext::UI::instance()->flush_pending ();
7124 Editor::bring_all_sources_into_session ()
7131 ArdourDialog w (_("Moving embedded files into session folder"));
7132 w.get_vbox()->pack_start (msg);
7135 /* flush all pending GUI events because we're about to start copying
7139 Gtkmm2ext::UI::instance()->flush_pending ();
7143 _session->bring_all_sources_into_session (boost::bind (&Editor::bring_in_callback, this, &msg, _1, _2, _3));