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 */
31 #include "pbd/error.h"
32 #include "pbd/basename.h"
33 #include "pbd/pthread_utils.h"
34 #include "pbd/memento_command.h"
35 #include "pbd/unwind.h"
36 #include "pbd/whitespace.h"
37 #include "pbd/stateful_diff_command.h"
39 #include <gtkmm2ext/utils.h>
40 #include <gtkmm2ext/choice.h>
41 #include <gtkmm2ext/popup.h>
43 #include "ardour/audio_track.h"
44 #include "ardour/audioregion.h"
45 #include "ardour/dB.h"
46 #include "ardour/location.h"
47 #include "ardour/midi_region.h"
48 #include "ardour/midi_track.h"
49 #include "ardour/operations.h"
50 #include "ardour/playlist_factory.h"
51 #include "ardour/profile.h"
52 #include "ardour/quantize.h"
53 #include "ardour/region_factory.h"
54 #include "ardour/reverse.h"
55 #include "ardour/session.h"
56 #include "ardour/session_playlists.h"
57 #include "ardour/strip_silence.h"
58 #include "ardour/transient_detector.h"
60 #include "canvas/canvas.h"
63 #include "ardour_ui.h"
64 #include "audio_region_view.h"
65 #include "audio_streamview.h"
66 #include "audio_time_axis.h"
67 #include "automation_region_view.h"
68 #include "automation_time_axis.h"
69 #include "control_point.h"
73 #include "editor_cursors.h"
74 #include "editor_drag.h"
75 #include "editor_regions.h"
76 #include "editor_routes.h"
77 #include "gui_thread.h"
78 #include "insert_time_dialog.h"
79 #include "interthread_progress_window.h"
80 #include "item_counts.h"
82 #include "midi_region_view.h"
83 #include "mixer_strip.h"
84 #include "mouse_cursors.h"
85 #include "normalize_dialog.h"
86 #include "patch_change_dialog.h"
87 #include "quantize_dialog.h"
88 #include "region_gain_line.h"
89 #include "rgb_macros.h"
90 #include "route_time_axis.h"
91 #include "selection.h"
92 #include "selection_templates.h"
93 #include "streamview.h"
94 #include "strip_silence_dialog.h"
95 #include "time_axis_view.h"
96 #include "transpose_dialog.h"
101 using namespace ARDOUR;
104 using namespace Gtkmm2ext;
105 using namespace Editing;
106 using Gtkmm2ext::Keyboard;
108 /***********************************************************************
110 ***********************************************************************/
113 Editor::undo (uint32_t n)
115 if (_drags->active ()) {
125 Editor::redo (uint32_t n)
127 if (_drags->active ()) {
137 Editor::split_regions_at (framepos_t where, RegionSelection& regions)
141 RegionSelection pre_selected_regions = selection->regions;
142 bool working_on_selection = !pre_selected_regions.empty();
144 list<boost::shared_ptr<Playlist> > used_playlists;
145 list<RouteTimeAxisView*> used_trackviews;
147 if (regions.empty()) {
151 begin_reversible_command (_("split"));
153 // if splitting a single region, and snap-to is using
154 // region boundaries, don't pay attention to them
156 if (regions.size() == 1) {
157 switch (_snap_type) {
158 case SnapToRegionStart:
159 case SnapToRegionSync:
160 case SnapToRegionEnd:
169 EditorFreeze(); /* Emit Signal */
172 for (RegionSelection::iterator a = regions.begin(); a != regions.end(); ) {
174 RegionSelection::iterator tmp;
176 /* XXX this test needs to be more complicated, to make sure we really
177 have something to split.
180 if (!(*a)->region()->covers (where)) {
188 boost::shared_ptr<Playlist> pl = (*a)->region()->playlist();
196 /* we haven't seen this playlist before */
198 /* remember used playlists so we can thaw them later */
199 used_playlists.push_back(pl);
201 TimeAxisView& tv = (*a)->get_time_axis_view();
202 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (&tv);
204 used_trackviews.push_back (rtv);
211 pl->clear_changes ();
212 pl->split_region ((*a)->region(), where);
213 _session->add_command (new StatefulDiffCommand (pl));
219 vector<sigc::connection> region_added_connections;
221 for (list<RouteTimeAxisView*>::iterator i = used_trackviews.begin(); i != used_trackviews.end(); ++i) {
222 region_added_connections.push_back ((*i)->view()->RegionViewAdded.connect (sigc::mem_fun(*this, &Editor::collect_new_region_view)));
225 latest_regionviews.clear ();
227 while (used_playlists.size() > 0) {
228 list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
230 used_playlists.pop_front();
233 for (vector<sigc::connection>::iterator c = region_added_connections.begin(); c != region_added_connections.end(); ++c) {
237 commit_reversible_command ();
240 EditorThaw(); /* Emit Signal */
243 if (ARDOUR::Profile->get_mixbus()) {
244 //IFF we were working on selected regions, try to reinstate the other region selections that existed before the freeze/thaw.
245 _ignore_follow_edits = true; //a split will change the region selection in mysterious ways; its not practical or wanted to follow this edit
246 if( working_on_selection ) {
247 selection->add ( pre_selected_regions );
248 selection->add (latest_regionviews); //these are the new regions created after the split
250 _ignore_follow_edits = false;
254 /** Move one extreme of the current range selection. If more than one range is selected,
255 * the start of the earliest range or the end of the latest range is moved.
257 * @param move_end true to move the end of the current range selection, false to move
259 * @param next true to move the extreme to the next region boundary, false to move to
263 Editor::move_range_selection_start_or_end_to_region_boundary (bool move_end, bool next)
265 if (selection->time.start() == selection->time.end_frame()) {
269 framepos_t start = selection->time.start ();
270 framepos_t end = selection->time.end_frame ();
272 /* the position of the thing we may move */
273 framepos_t pos = move_end ? end : start;
274 int dir = next ? 1 : -1;
276 /* so we don't find the current region again */
277 if (dir > 0 || pos > 0) {
281 framepos_t const target = get_region_boundary (pos, dir, true, false);
296 begin_reversible_command (_("alter selection"));
297 selection->set_preserving_all_ranges (start, end);
298 commit_reversible_command ();
302 Editor::nudge_forward_release (GdkEventButton* ev)
304 if (ev->state & Keyboard::PrimaryModifier) {
305 nudge_forward (false, true);
307 nudge_forward (false, false);
313 Editor::nudge_backward_release (GdkEventButton* ev)
315 if (ev->state & Keyboard::PrimaryModifier) {
316 nudge_backward (false, true);
318 nudge_backward (false, false);
325 Editor::nudge_forward (bool next, bool force_playhead)
328 framepos_t next_distance;
334 RegionSelection rs = get_regions_from_selection_and_entered ();
336 if (!force_playhead && !rs.empty()) {
338 begin_reversible_command (_("nudge regions forward"));
340 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
341 boost::shared_ptr<Region> r ((*i)->region());
343 distance = get_nudge_distance (r->position(), next_distance);
346 distance = next_distance;
350 r->set_position (r->position() + distance);
351 _session->add_command (new StatefulDiffCommand (r));
354 commit_reversible_command ();
357 } else if (!force_playhead && !selection->markers.empty()) {
361 begin_reversible_command (_("nudge location forward"));
363 for (MarkerSelection::iterator i = selection->markers.begin(); i != selection->markers.end(); ++i) {
365 Location* loc = find_location_from_marker ((*i), is_start);
369 XMLNode& before (loc->get_state());
372 distance = get_nudge_distance (loc->start(), next_distance);
374 distance = next_distance;
376 if (max_framepos - distance > loc->start() + loc->length()) {
377 loc->set_start (loc->start() + distance);
379 loc->set_start (max_framepos - loc->length());
382 distance = get_nudge_distance (loc->end(), next_distance);
384 distance = next_distance;
386 if (max_framepos - distance > loc->end()) {
387 loc->set_end (loc->end() + distance);
389 loc->set_end (max_framepos);
392 XMLNode& after (loc->get_state());
393 _session->add_command (new MementoCommand<Location>(*loc, &before, &after));
397 commit_reversible_command ();
400 distance = get_nudge_distance (playhead_cursor->current_frame (), next_distance);
401 _session->request_locate (playhead_cursor->current_frame () + distance);
406 Editor::nudge_backward (bool next, bool force_playhead)
409 framepos_t next_distance;
415 RegionSelection rs = get_regions_from_selection_and_entered ();
417 if (!force_playhead && !rs.empty()) {
419 begin_reversible_command (_("nudge regions backward"));
421 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
422 boost::shared_ptr<Region> r ((*i)->region());
424 distance = get_nudge_distance (r->position(), next_distance);
427 distance = next_distance;
432 if (r->position() > distance) {
433 r->set_position (r->position() - distance);
437 _session->add_command (new StatefulDiffCommand (r));
440 commit_reversible_command ();
442 } else if (!force_playhead && !selection->markers.empty()) {
446 begin_reversible_command (_("nudge location forward"));
448 for (MarkerSelection::iterator i = selection->markers.begin(); i != selection->markers.end(); ++i) {
450 Location* loc = find_location_from_marker ((*i), is_start);
454 XMLNode& before (loc->get_state());
457 distance = get_nudge_distance (loc->start(), next_distance);
459 distance = next_distance;
461 if (distance < loc->start()) {
462 loc->set_start (loc->start() - distance);
467 distance = get_nudge_distance (loc->end(), next_distance);
470 distance = next_distance;
473 if (distance < loc->end() - loc->length()) {
474 loc->set_end (loc->end() - distance);
476 loc->set_end (loc->length());
480 XMLNode& after (loc->get_state());
481 _session->add_command (new MementoCommand<Location>(*loc, &before, &after));
485 commit_reversible_command ();
489 distance = get_nudge_distance (playhead_cursor->current_frame (), next_distance);
491 if (playhead_cursor->current_frame () > distance) {
492 _session->request_locate (playhead_cursor->current_frame () - distance);
494 _session->goto_start();
500 Editor::nudge_forward_capture_offset ()
502 RegionSelection rs = get_regions_from_selection_and_entered ();
504 if (!_session || rs.empty()) {
508 begin_reversible_command (_("nudge forward"));
510 framepos_t const distance = _session->worst_output_latency();
512 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
513 boost::shared_ptr<Region> r ((*i)->region());
516 r->set_position (r->position() + distance);
517 _session->add_command(new StatefulDiffCommand (r));
520 commit_reversible_command ();
524 Editor::nudge_backward_capture_offset ()
526 RegionSelection rs = get_regions_from_selection_and_entered ();
528 if (!_session || rs.empty()) {
532 begin_reversible_command (_("nudge backward"));
534 framepos_t const distance = _session->worst_output_latency();
536 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
537 boost::shared_ptr<Region> r ((*i)->region());
541 if (r->position() > distance) {
542 r->set_position (r->position() - distance);
546 _session->add_command(new StatefulDiffCommand (r));
549 commit_reversible_command ();
552 struct RegionSelectionPositionSorter {
553 bool operator() (RegionView* a, RegionView* b) {
554 return a->region()->position() < b->region()->position();
559 Editor::sequence_regions ()
562 framepos_t r_end_prev;
570 RegionSelection rs = get_regions_from_selection_and_entered ();
571 rs.sort(RegionSelectionPositionSorter());
575 begin_reversible_command (_("sequence regions"));
576 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
577 boost::shared_ptr<Region> r ((*i)->region());
585 if(r->position_locked())
592 r->set_position(r_end_prev);
595 _session->add_command (new StatefulDiffCommand (r));
597 r_end=r->position() + r->length();
601 commit_reversible_command ();
609 Editor::move_to_start ()
611 _session->goto_start ();
615 Editor::move_to_end ()
618 _session->request_locate (_session->current_end_frame());
622 Editor::build_region_boundary_cache ()
625 vector<RegionPoint> interesting_points;
626 boost::shared_ptr<Region> r;
627 TrackViewList tracks;
630 region_boundary_cache.clear ();
636 switch (_snap_type) {
637 case SnapToRegionStart:
638 interesting_points.push_back (Start);
640 case SnapToRegionEnd:
641 interesting_points.push_back (End);
643 case SnapToRegionSync:
644 interesting_points.push_back (SyncPoint);
646 case SnapToRegionBoundary:
647 interesting_points.push_back (Start);
648 interesting_points.push_back (End);
651 fatal << string_compose (_("build_region_boundary_cache called with snap_type = %1"), _snap_type) << endmsg;
652 abort(); /*NOTREACHED*/
656 TimeAxisView *ontrack = 0;
659 if (!selection->tracks.empty()) {
660 tlist = selection->tracks.filter_to_unique_playlists ();
662 tlist = track_views.filter_to_unique_playlists ();
665 while (pos < _session->current_end_frame() && !at_end) {
668 framepos_t lpos = max_framepos;
670 for (vector<RegionPoint>::iterator p = interesting_points.begin(); p != interesting_points.end(); ++p) {
672 if ((r = find_next_region (pos, *p, 1, tlist, &ontrack)) == 0) {
673 if (*p == interesting_points.back()) {
676 /* move to next point type */
682 rpos = r->first_frame();
686 rpos = r->last_frame();
690 rpos = r->sync_position ();
698 RouteTimeAxisView *rtav;
700 if (ontrack != 0 && (rtav = dynamic_cast<RouteTimeAxisView*>(ontrack)) != 0 ) {
701 if (rtav->track() != 0) {
702 speed = rtav->track()->speed();
706 rpos = track_frame_to_session_frame (rpos, speed);
712 /* prevent duplicates, but we don't use set<> because we want to be able
716 vector<framepos_t>::iterator ri;
718 for (ri = region_boundary_cache.begin(); ri != region_boundary_cache.end(); ++ri) {
724 if (ri == region_boundary_cache.end()) {
725 region_boundary_cache.push_back (rpos);
732 /* finally sort to be sure that the order is correct */
734 sort (region_boundary_cache.begin(), region_boundary_cache.end());
737 boost::shared_ptr<Region>
738 Editor::find_next_region (framepos_t frame, RegionPoint point, int32_t dir, TrackViewList& tracks, TimeAxisView **ontrack)
740 TrackViewList::iterator i;
741 framepos_t closest = max_framepos;
742 boost::shared_ptr<Region> ret;
746 framepos_t track_frame;
747 RouteTimeAxisView *rtav;
749 for (i = tracks.begin(); i != tracks.end(); ++i) {
752 boost::shared_ptr<Region> r;
755 if ( (rtav = dynamic_cast<RouteTimeAxisView*>(*i)) != 0 ) {
756 if (rtav->track()!=0)
757 track_speed = rtav->track()->speed();
760 track_frame = session_frame_to_track_frame(frame, track_speed);
762 if ((r = (*i)->find_next_region (track_frame, point, dir)) == 0) {
768 rpos = r->first_frame ();
772 rpos = r->last_frame ();
776 rpos = r->sync_position ();
780 // rpos is a "track frame", converting it to "_session frame"
781 rpos = track_frame_to_session_frame(rpos, track_speed);
784 distance = rpos - frame;
786 distance = frame - rpos;
789 if (distance < closest) {
801 Editor::find_next_region_boundary (framepos_t pos, int32_t dir, const TrackViewList& tracks)
803 framecnt_t distance = max_framepos;
804 framepos_t current_nearest = -1;
806 for (TrackViewList::const_iterator i = tracks.begin(); i != tracks.end(); ++i) {
807 framepos_t contender;
810 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*i);
816 if ((contender = rtv->find_next_region_boundary (pos, dir)) < 0) {
820 d = ::llabs (pos - contender);
823 current_nearest = contender;
828 return current_nearest;
832 Editor::get_region_boundary (framepos_t pos, int32_t dir, bool with_selection, bool only_onscreen)
837 if (with_selection && Config->get_region_boundaries_from_selected_tracks()) {
839 if (!selection->tracks.empty()) {
841 target = find_next_region_boundary (pos, dir, selection->tracks);
845 if (only_onscreen || Config->get_region_boundaries_from_onscreen_tracks()) {
846 get_onscreen_tracks (tvl);
847 target = find_next_region_boundary (pos, dir, tvl);
849 target = find_next_region_boundary (pos, dir, track_views);
855 if (only_onscreen || Config->get_region_boundaries_from_onscreen_tracks()) {
856 get_onscreen_tracks (tvl);
857 target = find_next_region_boundary (pos, dir, tvl);
859 target = find_next_region_boundary (pos, dir, track_views);
867 Editor::cursor_to_region_boundary (bool with_selection, int32_t dir)
869 framepos_t pos = playhead_cursor->current_frame ();
876 // so we don't find the current region again..
877 if (dir > 0 || pos > 0) {
881 if ((target = get_region_boundary (pos, dir, with_selection, false)) < 0) {
885 _session->request_locate (target);
889 Editor::cursor_to_next_region_boundary (bool with_selection)
891 cursor_to_region_boundary (with_selection, 1);
895 Editor::cursor_to_previous_region_boundary (bool with_selection)
897 cursor_to_region_boundary (with_selection, -1);
901 Editor::cursor_to_region_point (EditorCursor* cursor, RegionPoint point, int32_t dir)
903 boost::shared_ptr<Region> r;
904 framepos_t pos = cursor->current_frame ();
910 TimeAxisView *ontrack = 0;
912 // so we don't find the current region again..
916 if (!selection->tracks.empty()) {
918 r = find_next_region (pos, point, dir, selection->tracks, &ontrack);
920 } else if (clicked_axisview) {
923 t.push_back (clicked_axisview);
925 r = find_next_region (pos, point, dir, t, &ontrack);
929 r = find_next_region (pos, point, dir, track_views, &ontrack);
938 pos = r->first_frame ();
942 pos = r->last_frame ();
946 pos = r->sync_position ();
951 RouteTimeAxisView *rtav;
953 if ( ontrack != 0 && (rtav = dynamic_cast<RouteTimeAxisView*>(ontrack)) != 0 ) {
954 if (rtav->track() != 0) {
955 speed = rtav->track()->speed();
959 pos = track_frame_to_session_frame(pos, speed);
961 if (cursor == playhead_cursor) {
962 _session->request_locate (pos);
964 cursor->set_position (pos);
969 Editor::cursor_to_next_region_point (EditorCursor* cursor, RegionPoint point)
971 cursor_to_region_point (cursor, point, 1);
975 Editor::cursor_to_previous_region_point (EditorCursor* cursor, RegionPoint point)
977 cursor_to_region_point (cursor, point, -1);
981 Editor::cursor_to_selection_start (EditorCursor *cursor)
985 switch (mouse_mode) {
987 if (!selection->regions.empty()) {
988 pos = selection->regions.start();
993 if (!selection->time.empty()) {
994 pos = selection->time.start ();
1002 if (cursor == playhead_cursor) {
1003 _session->request_locate (pos);
1005 cursor->set_position (pos);
1010 Editor::cursor_to_selection_end (EditorCursor *cursor)
1014 switch (mouse_mode) {
1016 if (!selection->regions.empty()) {
1017 pos = selection->regions.end_frame();
1022 if (!selection->time.empty()) {
1023 pos = selection->time.end_frame ();
1031 if (cursor == playhead_cursor) {
1032 _session->request_locate (pos);
1034 cursor->set_position (pos);
1039 Editor::selected_marker_to_region_boundary (bool with_selection, int32_t dir)
1049 if (selection->markers.empty()) {
1053 if (!mouse_frame (mouse, ignored)) {
1057 add_location_mark (mouse);
1060 if ((loc = find_location_from_marker (selection->markers.front(), ignored)) == 0) {
1064 framepos_t pos = loc->start();
1066 // so we don't find the current region again..
1067 if (dir > 0 || pos > 0) {
1071 if ((target = get_region_boundary (pos, dir, with_selection, false)) < 0) {
1075 loc->move_to (target);
1079 Editor::selected_marker_to_next_region_boundary (bool with_selection)
1081 selected_marker_to_region_boundary (with_selection, 1);
1085 Editor::selected_marker_to_previous_region_boundary (bool with_selection)
1087 selected_marker_to_region_boundary (with_selection, -1);
1091 Editor::selected_marker_to_region_point (RegionPoint point, int32_t dir)
1093 boost::shared_ptr<Region> r;
1098 if (!_session || selection->markers.empty()) {
1102 if ((loc = find_location_from_marker (selection->markers.front(), ignored)) == 0) {
1106 TimeAxisView *ontrack = 0;
1110 // so we don't find the current region again..
1114 if (!selection->tracks.empty()) {
1116 r = find_next_region (pos, point, dir, selection->tracks, &ontrack);
1120 r = find_next_region (pos, point, dir, track_views, &ontrack);
1129 pos = r->first_frame ();
1133 pos = r->last_frame ();
1137 pos = r->adjust_to_sync (r->first_frame());
1142 RouteTimeAxisView *rtav;
1144 if (ontrack != 0 && (rtav = dynamic_cast<RouteTimeAxisView*>(ontrack)) != 0) {
1145 if (rtav->track() != 0) {
1146 speed = rtav->track()->speed();
1150 pos = track_frame_to_session_frame(pos, speed);
1156 Editor::selected_marker_to_next_region_point (RegionPoint point)
1158 selected_marker_to_region_point (point, 1);
1162 Editor::selected_marker_to_previous_region_point (RegionPoint point)
1164 selected_marker_to_region_point (point, -1);
1168 Editor::selected_marker_to_selection_start ()
1174 if (!_session || selection->markers.empty()) {
1178 if ((loc = find_location_from_marker (selection->markers.front(), ignored)) == 0) {
1182 switch (mouse_mode) {
1184 if (!selection->regions.empty()) {
1185 pos = selection->regions.start();
1190 if (!selection->time.empty()) {
1191 pos = selection->time.start ();
1203 Editor::selected_marker_to_selection_end ()
1209 if (!_session || selection->markers.empty()) {
1213 if ((loc = find_location_from_marker (selection->markers.front(), ignored)) == 0) {
1217 switch (mouse_mode) {
1219 if (!selection->regions.empty()) {
1220 pos = selection->regions.end_frame();
1225 if (!selection->time.empty()) {
1226 pos = selection->time.end_frame ();
1238 Editor::scroll_playhead (bool forward)
1240 framepos_t pos = playhead_cursor->current_frame ();
1241 framecnt_t delta = (framecnt_t) floor (current_page_samples() / 0.8);
1244 if (pos == max_framepos) {
1248 if (pos < max_framepos - delta) {
1267 _session->request_locate (pos);
1271 Editor::cursor_align (bool playhead_to_edit)
1277 if (playhead_to_edit) {
1279 if (selection->markers.empty()) {
1283 _session->request_locate (selection->markers.front()->position(), _session->transport_rolling());
1286 /* move selected markers to playhead */
1288 for (MarkerSelection::iterator i = selection->markers.begin(); i != selection->markers.end(); ++i) {
1291 Location* loc = find_location_from_marker (*i, ignored);
1293 if (loc->is_mark()) {
1294 loc->set_start (playhead_cursor->current_frame ());
1296 loc->set (playhead_cursor->current_frame (),
1297 playhead_cursor->current_frame () + loc->length());
1304 Editor::scroll_backward (float pages)
1306 framepos_t const one_page = (framepos_t) rint (_visible_canvas_width * samples_per_pixel);
1307 framepos_t const cnt = (framepos_t) floor (pages * one_page);
1310 if (leftmost_frame < cnt) {
1313 frame = leftmost_frame - cnt;
1316 reset_x_origin (frame);
1320 Editor::scroll_forward (float pages)
1322 framepos_t const one_page = (framepos_t) rint (_visible_canvas_width * samples_per_pixel);
1323 framepos_t const cnt = (framepos_t) floor (pages * one_page);
1326 if (max_framepos - cnt < leftmost_frame) {
1327 frame = max_framepos - cnt;
1329 frame = leftmost_frame + cnt;
1332 reset_x_origin (frame);
1336 Editor::scroll_tracks_down ()
1338 double vert_value = vertical_adjustment.get_value() + vertical_adjustment.get_page_size();
1339 if (vert_value > vertical_adjustment.get_upper() - _visible_canvas_height) {
1340 vert_value = vertical_adjustment.get_upper() - _visible_canvas_height;
1343 vertical_adjustment.set_value (vert_value);
1347 Editor::scroll_tracks_up ()
1349 vertical_adjustment.set_value (vertical_adjustment.get_value() - vertical_adjustment.get_page_size());
1353 Editor::scroll_tracks_down_line ()
1355 double vert_value = vertical_adjustment.get_value() + 60;
1357 if (vert_value > vertical_adjustment.get_upper() - _visible_canvas_height) {
1358 vert_value = vertical_adjustment.get_upper() - _visible_canvas_height;
1361 vertical_adjustment.set_value (vert_value);
1365 Editor::scroll_tracks_up_line ()
1367 reset_y_origin (vertical_adjustment.get_value() - 60);
1371 Editor::scroll_down_one_track ()
1373 TrackViewList::reverse_iterator next = track_views.rend();
1374 std::pair<TimeAxisView*,double> res;
1375 const double top_of_trackviews = vertical_adjustment.get_value();
1377 for (TrackViewList::reverse_iterator t = track_views.rbegin(); t != track_views.rend(); ++t) {
1378 if ((*t)->hidden()) {
1383 /* If this is the upper-most visible trackview, we want to display
1384 the one above it (next)
1387 res = (*t)->covers_y_position (top_of_trackviews);
1395 /* move to the track below the first one that covers the */
1397 if (next != track_views.rend()) {
1398 ensure_time_axis_view_is_visible (**next, true);
1406 Editor::scroll_up_one_track ()
1408 TrackViewList::iterator prev = track_views.end();
1409 std::pair<TimeAxisView*,double> res;
1410 double top_of_trackviews = vertical_adjustment.get_value ();
1412 for (TrackViewList::iterator t = track_views.begin(); t != track_views.end(); ++t) {
1414 if ((*t)->hidden()) {
1418 /* find the trackview at the top of the trackview group */
1419 res = (*t)->covers_y_position (top_of_trackviews);
1428 if (prev != track_views.end()) {
1429 ensure_time_axis_view_is_visible (**prev, true);
1439 Editor::tav_zoom_step (bool coarser)
1441 DisplaySuspender ds;
1445 if (selection->tracks.empty()) {
1448 ts = &selection->tracks;
1451 for (TrackViewList::iterator i = ts->begin(); i != ts->end(); ++i) {
1452 TimeAxisView *tv = (static_cast<TimeAxisView*>(*i));
1453 tv->step_height (coarser);
1458 Editor::tav_zoom_smooth (bool coarser, bool force_all)
1460 DisplaySuspender ds;
1464 if (selection->tracks.empty() || force_all) {
1467 ts = &selection->tracks;
1470 for (TrackViewList::iterator i = ts->begin(); i != ts->end(); ++i) {
1471 TimeAxisView *tv = (static_cast<TimeAxisView*>(*i));
1472 uint32_t h = tv->current_height ();
1477 if (h >= TimeAxisView::preset_height (HeightSmall)) {
1482 tv->set_height (h + 5);
1489 Editor::temporal_zoom_step (bool coarser)
1491 ENSURE_GUI_THREAD (*this, &Editor::temporal_zoom_step, coarser)
1493 framecnt_t nspp = samples_per_pixel;
1501 temporal_zoom (nspp);
1505 Editor::temporal_zoom (framecnt_t fpp)
1511 framepos_t current_page = current_page_samples();
1512 framepos_t current_leftmost = leftmost_frame;
1513 framepos_t current_rightmost;
1514 framepos_t current_center;
1515 framepos_t new_page_size;
1516 framepos_t half_page_size;
1517 framepos_t leftmost_after_zoom = 0;
1519 bool in_track_canvas;
1523 if (fpp == samples_per_pixel) {
1527 // Imposing an arbitrary limit to zoom out as too much zoom out produces
1528 // segfaults for lack of memory. If somebody decides this is not high enough I
1529 // believe it can be raisen to higher values but some limit must be in place.
1531 // This constant represents 1 day @ 48kHz on a 1600 pixel wide display
1532 // all of which is used for the editor track displays. The whole day
1533 // would be 4147200000 samples, so 2592000 samples per pixel.
1535 nfpp = min (fpp, (framecnt_t) 2592000);
1536 nfpp = max ((framecnt_t) 1, nfpp);
1538 new_page_size = (framepos_t) floor (_visible_canvas_width * nfpp);
1539 half_page_size = new_page_size / 2;
1541 switch (zoom_focus) {
1543 leftmost_after_zoom = current_leftmost;
1546 case ZoomFocusRight:
1547 current_rightmost = leftmost_frame + current_page;
1548 if (current_rightmost < new_page_size) {
1549 leftmost_after_zoom = 0;
1551 leftmost_after_zoom = current_rightmost - new_page_size;
1555 case ZoomFocusCenter:
1556 current_center = current_leftmost + (current_page/2);
1557 if (current_center < half_page_size) {
1558 leftmost_after_zoom = 0;
1560 leftmost_after_zoom = current_center - half_page_size;
1564 case ZoomFocusPlayhead:
1565 /* centre playhead */
1566 l = playhead_cursor->current_frame () - (new_page_size * 0.5);
1569 leftmost_after_zoom = 0;
1570 } else if (l > max_framepos) {
1571 leftmost_after_zoom = max_framepos - new_page_size;
1573 leftmost_after_zoom = (framepos_t) l;
1577 case ZoomFocusMouse:
1578 /* try to keep the mouse over the same point in the display */
1580 if (!mouse_frame (where, in_track_canvas)) {
1581 /* use playhead instead */
1582 where = playhead_cursor->current_frame ();
1584 if (where < half_page_size) {
1585 leftmost_after_zoom = 0;
1587 leftmost_after_zoom = where - half_page_size;
1592 l = - ((new_page_size * ((where - current_leftmost)/(double)current_page)) - where);
1595 leftmost_after_zoom = 0;
1596 } else if (l > max_framepos) {
1597 leftmost_after_zoom = max_framepos - new_page_size;
1599 leftmost_after_zoom = (framepos_t) l;
1606 /* try to keep the edit point in the same place */
1607 where = get_preferred_edit_position ();
1611 double l = - ((new_page_size * ((where - current_leftmost)/(double)current_page)) - where);
1614 leftmost_after_zoom = 0;
1615 } else if (l > max_framepos) {
1616 leftmost_after_zoom = max_framepos - new_page_size;
1618 leftmost_after_zoom = (framepos_t) l;
1622 /* edit point not defined */
1629 // leftmost_after_zoom = min (leftmost_after_zoom, _session->current_end_frame());
1631 reposition_and_zoom (leftmost_after_zoom, nfpp);
1635 Editor::calc_extra_zoom_edges(framepos_t &start, framepos_t &end)
1637 /* this func helps make sure we leave a little space
1638 at each end of the editor so that the zoom doesn't fit the region
1639 precisely to the screen.
1642 GdkScreen* screen = gdk_screen_get_default ();
1643 const gint pixwidth = gdk_screen_get_width (screen);
1644 const gint mmwidth = gdk_screen_get_width_mm (screen);
1645 const double pix_per_mm = (double) pixwidth/ (double) mmwidth;
1646 const double one_centimeter_in_pixels = pix_per_mm * 10.0;
1648 const framepos_t range = end - start;
1649 const framecnt_t new_fpp = (framecnt_t) ceil ((double) range / (double) _visible_canvas_width);
1650 const framepos_t extra_samples = (framepos_t) floor (one_centimeter_in_pixels * new_fpp);
1652 if (start > extra_samples) {
1653 start -= extra_samples;
1658 if (max_framepos - extra_samples > end) {
1659 end += extra_samples;
1666 Editor::temporal_zoom_region (bool both_axes)
1668 framepos_t start = max_framepos;
1670 set<TimeAxisView*> tracks;
1672 RegionSelection rs = get_regions_from_selection_and_entered ();
1678 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
1680 if ((*i)->region()->position() < start) {
1681 start = (*i)->region()->position();
1684 if ((*i)->region()->last_frame() + 1 > end) {
1685 end = (*i)->region()->last_frame() + 1;
1688 tracks.insert (&((*i)->get_time_axis_view()));
1691 if ((start == 0 && end == 0) || end < start) {
1695 calc_extra_zoom_edges (start, end);
1697 /* if we're zooming on both axes we need to save track heights etc.
1700 undo_visual_stack.push_back (current_visual_state (both_axes));
1702 PBD::Unwinder<bool> nsv (no_save_visual, true);
1704 temporal_zoom_by_frame (start, end);
1707 uint32_t per_track_height = (uint32_t) floor ((_visible_canvas_height - 10.0) / tracks.size());
1709 /* set visible track heights appropriately */
1711 for (set<TimeAxisView*>::iterator t = tracks.begin(); t != tracks.end(); ++t) {
1712 (*t)->set_height (per_track_height);
1715 /* hide irrelevant tracks */
1717 DisplaySuspender ds;
1719 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1720 if (find (tracks.begin(), tracks.end(), (*i)) == tracks.end()) {
1721 hide_track_in_display (*i);
1725 vertical_adjustment.set_value (0.0);
1728 redo_visual_stack.push_back (current_visual_state (both_axes));
1732 Editor::zoom_to_region (bool both_axes)
1734 temporal_zoom_region (both_axes);
1738 Editor::temporal_zoom_selection (bool both_axes)
1740 if (!selection) return;
1742 //if a range is selected, zoom to that
1743 if (!selection->time.empty()) {
1745 framepos_t start = selection->time.start();
1746 framepos_t end = selection->time.end_frame();
1748 calc_extra_zoom_edges(start, end);
1750 temporal_zoom_by_frame (start, end);
1753 fit_selected_tracks();
1756 temporal_zoom_region (both_axes);
1763 Editor::temporal_zoom_session ()
1765 ENSURE_GUI_THREAD (*this, &Editor::temporal_zoom_session)
1768 framecnt_t start = _session->current_start_frame();
1769 framecnt_t end = _session->current_end_frame();
1771 if (_session->actively_recording () ) {
1772 framepos_t cur = playhead_cursor->current_frame ();
1774 /* recording beyond the end marker; zoom out
1775 * by 5 seconds more so that if 'follow
1776 * playhead' is active we don't immediately
1779 end = cur + _session->frame_rate() * 5;
1783 if ((start == 0 && end == 0) || end < start) {
1787 calc_extra_zoom_edges(start, end);
1789 temporal_zoom_by_frame (start, end);
1794 Editor::temporal_zoom_by_frame (framepos_t start, framepos_t end)
1796 if (!_session) return;
1798 if ((start == 0 && end == 0) || end < start) {
1802 framepos_t range = end - start;
1804 const framecnt_t new_fpp = (framecnt_t) ceil ((double) range / (double) _visible_canvas_width);
1806 framepos_t new_page = range;
1807 framepos_t middle = (framepos_t) floor ((double) start + ((double) range / 2.0f));
1808 framepos_t new_leftmost = (framepos_t) floor ((double) middle - ((double) new_page / 2.0f));
1810 if (new_leftmost > middle) {
1814 if (new_leftmost < 0) {
1818 reposition_and_zoom (new_leftmost, new_fpp);
1822 Editor::temporal_zoom_to_frame (bool coarser, framepos_t frame)
1828 framecnt_t range_before = frame - leftmost_frame;
1832 if (samples_per_pixel <= 1) {
1835 new_spp = samples_per_pixel + (samples_per_pixel/2);
1837 range_before += range_before/2;
1839 if (samples_per_pixel >= 1) {
1840 new_spp = samples_per_pixel - (samples_per_pixel/2);
1842 /* could bail out here since we cannot zoom any finer,
1843 but leave that to the equality test below
1845 new_spp = samples_per_pixel;
1848 range_before -= range_before/2;
1851 if (new_spp == samples_per_pixel) {
1855 /* zoom focus is automatically taken as @param frame when this
1859 framepos_t new_leftmost = frame - (framepos_t)range_before;
1861 if (new_leftmost > frame) {
1865 if (new_leftmost < 0) {
1869 reposition_and_zoom (new_leftmost, new_spp);
1874 Editor::choose_new_marker_name(string &name) {
1876 if (!Config->get_name_new_markers()) {
1877 /* don't prompt user for a new name */
1881 ArdourPrompter dialog (true);
1883 dialog.set_prompt (_("New Name:"));
1885 dialog.set_title (_("New Location Marker"));
1887 dialog.set_name ("MarkNameWindow");
1888 dialog.set_size_request (250, -1);
1889 dialog.set_position (Gtk::WIN_POS_MOUSE);
1891 dialog.add_button (Stock::OK, RESPONSE_ACCEPT);
1892 dialog.set_initial_text (name);
1896 switch (dialog.run ()) {
1897 case RESPONSE_ACCEPT:
1903 dialog.get_result(name);
1910 Editor::add_location_from_selection ()
1914 if (selection->time.empty()) {
1918 if (_session == 0 || clicked_axisview == 0) {
1922 framepos_t start = selection->time[clicked_selection].start;
1923 framepos_t end = selection->time[clicked_selection].end;
1925 _session->locations()->next_available_name(rangename,"selection");
1926 Location *location = new Location (*_session, start, end, rangename, Location::IsRangeMarker);
1928 _session->begin_reversible_command (_("add marker"));
1929 XMLNode &before = _session->locations()->get_state();
1930 _session->locations()->add (location, true);
1931 XMLNode &after = _session->locations()->get_state();
1932 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
1933 _session->commit_reversible_command ();
1937 Editor::add_location_mark (framepos_t where)
1941 select_new_marker = true;
1943 _session->locations()->next_available_name(markername,"mark");
1944 if (!choose_new_marker_name(markername)) {
1947 Location *location = new Location (*_session, where, where, markername, Location::IsMark);
1948 _session->begin_reversible_command (_("add marker"));
1949 XMLNode &before = _session->locations()->get_state();
1950 _session->locations()->add (location, true);
1951 XMLNode &after = _session->locations()->get_state();
1952 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
1953 _session->commit_reversible_command ();
1957 Editor::add_location_from_playhead_cursor ()
1959 add_location_mark (_session->audible_frame());
1963 Editor::remove_location_at_playhead_cursor ()
1968 _session->begin_reversible_command (_("remove marker"));
1969 XMLNode &before = _session->locations()->get_state();
1970 bool removed = false;
1972 //find location(s) at this time
1973 Locations::LocationList locs;
1974 _session->locations()->find_all_between (_session->audible_frame(), _session->audible_frame()+1, locs, Location::Flags(0));
1975 for (Locations::LocationList::iterator i = locs.begin(); i != locs.end(); ++i) {
1976 if ((*i)->is_mark()) {
1977 _session->locations()->remove (*i);
1984 XMLNode &after = _session->locations()->get_state();
1985 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
1986 _session->commit_reversible_command ();
1991 /** Add a range marker around each selected region */
1993 Editor::add_locations_from_region ()
1995 RegionSelection rs = get_regions_from_selection_and_entered ();
2001 _session->begin_reversible_command (selection->regions.size () > 1 ? _("add markers") : _("add marker"));
2002 XMLNode &before = _session->locations()->get_state();
2004 for (RegionSelection::iterator i = rs.begin (); i != rs.end (); ++i) {
2006 boost::shared_ptr<Region> region = (*i)->region ();
2008 Location *location = new Location (*_session, region->position(), region->last_frame(), region->name(), Location::IsRangeMarker);
2010 _session->locations()->add (location, true);
2013 XMLNode &after = _session->locations()->get_state();
2014 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2015 _session->commit_reversible_command ();
2018 /** Add a single range marker around all selected regions */
2020 Editor::add_location_from_region ()
2022 RegionSelection rs = get_regions_from_selection_and_entered ();
2028 _session->begin_reversible_command (_("add marker"));
2029 XMLNode &before = _session->locations()->get_state();
2033 if (rs.size() > 1) {
2034 _session->locations()->next_available_name(markername, "regions");
2036 RegionView* rv = *(rs.begin());
2037 boost::shared_ptr<Region> region = rv->region();
2038 markername = region->name();
2041 if (!choose_new_marker_name(markername)) {
2045 // single range spanning all selected
2046 Location *location = new Location (*_session, selection->regions.start(), selection->regions.end_frame(), markername, Location::IsRangeMarker);
2047 _session->locations()->add (location, true);
2049 XMLNode &after = _session->locations()->get_state();
2050 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2051 _session->commit_reversible_command ();
2057 Editor::jump_forward_to_mark ()
2063 framepos_t pos = _session->locations()->first_mark_after (playhead_cursor->current_frame());
2069 _session->request_locate (pos, _session->transport_rolling());
2073 Editor::jump_backward_to_mark ()
2079 framepos_t pos = _session->locations()->first_mark_before (playhead_cursor->current_frame());
2085 _session->request_locate (pos, _session->transport_rolling());
2091 framepos_t const pos = _session->audible_frame ();
2094 _session->locations()->next_available_name (markername, "mark");
2096 if (!choose_new_marker_name (markername)) {
2100 _session->locations()->add (new Location (*_session, pos, 0, markername, Location::IsMark), true);
2104 Editor::clear_markers ()
2107 _session->begin_reversible_command (_("clear markers"));
2108 XMLNode &before = _session->locations()->get_state();
2109 _session->locations()->clear_markers ();
2110 XMLNode &after = _session->locations()->get_state();
2111 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2112 _session->commit_reversible_command ();
2117 Editor::clear_ranges ()
2120 _session->begin_reversible_command (_("clear ranges"));
2121 XMLNode &before = _session->locations()->get_state();
2123 _session->locations()->clear_ranges ();
2125 XMLNode &after = _session->locations()->get_state();
2126 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2127 _session->commit_reversible_command ();
2132 Editor::clear_locations ()
2134 _session->begin_reversible_command (_("clear locations"));
2135 XMLNode &before = _session->locations()->get_state();
2136 _session->locations()->clear ();
2137 XMLNode &after = _session->locations()->get_state();
2138 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2139 _session->commit_reversible_command ();
2140 _session->locations()->clear ();
2144 Editor::unhide_markers ()
2146 for (LocationMarkerMap::iterator i = location_markers.begin(); i != location_markers.end(); ++i) {
2147 Location *l = (*i).first;
2148 if (l->is_hidden() && l->is_mark()) {
2149 l->set_hidden(false, this);
2155 Editor::unhide_ranges ()
2157 for (LocationMarkerMap::iterator i = location_markers.begin(); i != location_markers.end(); ++i) {
2158 Location *l = (*i).first;
2159 if (l->is_hidden() && l->is_range_marker()) {
2160 l->set_hidden(false, this);
2165 /* INSERT/REPLACE */
2168 Editor::insert_region_list_selection (float times)
2170 RouteTimeAxisView *tv = 0;
2171 boost::shared_ptr<Playlist> playlist;
2173 if (clicked_routeview != 0) {
2174 tv = clicked_routeview;
2175 } else if (!selection->tracks.empty()) {
2176 if ((tv = dynamic_cast<RouteTimeAxisView*>(selection->tracks.front())) == 0) {
2179 } else if (entered_track != 0) {
2180 if ((tv = dynamic_cast<RouteTimeAxisView*>(entered_track)) == 0) {
2187 if ((playlist = tv->playlist()) == 0) {
2191 boost::shared_ptr<Region> region = _regions->get_single_selection ();
2196 begin_reversible_command (_("insert region"));
2197 playlist->clear_changes ();
2198 playlist->add_region ((RegionFactory::create (region, true)), get_preferred_edit_position(), times);
2199 if (Config->get_edit_mode() == Ripple)
2200 playlist->ripple (get_preferred_edit_position(), region->length() * times, boost::shared_ptr<Region>());
2202 _session->add_command(new StatefulDiffCommand (playlist));
2203 commit_reversible_command ();
2206 /* BUILT-IN EFFECTS */
2209 Editor::reverse_selection ()
2214 /* GAIN ENVELOPE EDITING */
2217 Editor::edit_envelope ()
2224 Editor::transition_to_rolling (bool fwd)
2230 if (_session->config.get_external_sync()) {
2231 switch (Config->get_sync_source()) {
2235 /* transport controlled by the master */
2240 if (_session->is_auditioning()) {
2241 _session->cancel_audition ();
2245 _session->request_transport_speed (fwd ? 1.0f : -1.0f);
2249 Editor::play_from_start ()
2251 _session->request_locate (_session->current_start_frame(), true);
2255 Editor::play_from_edit_point ()
2257 _session->request_locate (get_preferred_edit_position(), true);
2261 Editor::play_from_edit_point_and_return ()
2263 framepos_t start_frame;
2264 framepos_t return_frame;
2266 start_frame = get_preferred_edit_position (true);
2268 if (_session->transport_rolling()) {
2269 _session->request_locate (start_frame, false);
2273 /* don't reset the return frame if its already set */
2275 if ((return_frame = _session->requested_return_frame()) < 0) {
2276 return_frame = _session->audible_frame();
2279 if (start_frame >= 0) {
2280 _session->request_roll_at_and_return (start_frame, return_frame);
2285 Editor::play_selection ()
2287 if (selection->time.empty()) {
2291 _session->request_play_range (&selection->time, true);
2295 Editor::get_preroll ()
2297 return 1.0 /*Config->get_edit_preroll_seconds()*/ * _session->frame_rate();
2302 Editor::maybe_locate_with_edit_preroll ( framepos_t location )
2304 if ( _session->transport_rolling() || !Config->get_follow_edits() || _ignore_follow_edits )
2307 location -= get_preroll();
2309 //don't try to locate before the beginning of time
2313 //if follow_playhead is on, keep the playhead on the screen
2314 if ( _follow_playhead )
2315 if ( location < leftmost_frame )
2316 location = leftmost_frame;
2318 _session->request_locate( location );
2322 Editor::play_with_preroll ()
2324 if (selection->time.empty()) {
2327 framepos_t preroll = get_preroll();
2329 framepos_t start = 0;
2330 if (selection->time[clicked_selection].start > preroll)
2331 start = selection->time[clicked_selection].start - preroll;
2333 framepos_t end = selection->time[clicked_selection].end + preroll;
2335 AudioRange ar (start, end, 0);
2336 list<AudioRange> lar;
2339 _session->request_play_range (&lar, true);
2344 Editor::play_location (Location& location)
2346 if (location.start() <= location.end()) {
2350 _session->request_bounded_roll (location.start(), location.end());
2354 Editor::loop_location (Location& location)
2356 if (location.start() <= location.end()) {
2362 if ((tll = transport_loop_location()) != 0) {
2363 tll->set (location.start(), location.end());
2365 // enable looping, reposition and start rolling
2366 _session->request_locate (tll->start(), true);
2367 _session->request_play_loop (true);
2372 Editor::do_layer_operation (LayerOperation op)
2374 if (selection->regions.empty ()) {
2378 bool const multiple = selection->regions.size() > 1;
2382 begin_reversible_command (_("raise regions"));
2384 begin_reversible_command (_("raise region"));
2390 begin_reversible_command (_("raise regions to top"));
2392 begin_reversible_command (_("raise region to top"));
2398 begin_reversible_command (_("lower regions"));
2400 begin_reversible_command (_("lower region"));
2406 begin_reversible_command (_("lower regions to bottom"));
2408 begin_reversible_command (_("lower region"));
2413 set<boost::shared_ptr<Playlist> > playlists = selection->regions.playlists ();
2414 for (set<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
2415 (*i)->clear_owned_changes ();
2418 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
2419 boost::shared_ptr<Region> r = (*i)->region ();
2431 r->lower_to_bottom ();
2435 for (set<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
2436 vector<Command*> cmds;
2438 _session->add_commands (cmds);
2441 commit_reversible_command ();
2445 Editor::raise_region ()
2447 do_layer_operation (Raise);
2451 Editor::raise_region_to_top ()
2453 do_layer_operation (RaiseToTop);
2457 Editor::lower_region ()
2459 do_layer_operation (Lower);
2463 Editor::lower_region_to_bottom ()
2465 do_layer_operation (LowerToBottom);
2468 /** Show the region editor for the selected regions */
2470 Editor::show_region_properties ()
2472 selection->foreach_regionview (&RegionView::show_region_editor);
2475 /** Show the midi list editor for the selected MIDI regions */
2477 Editor::show_midi_list_editor ()
2479 selection->foreach_midi_regionview (&MidiRegionView::show_list_editor);
2483 Editor::rename_region ()
2485 RegionSelection rs = get_regions_from_selection_and_entered ();
2491 ArdourDialog d (*this, _("Rename Region"), true, false);
2493 Label label (_("New name:"));
2496 hbox.set_spacing (6);
2497 hbox.pack_start (label, false, false);
2498 hbox.pack_start (entry, true, true);
2500 d.get_vbox()->set_border_width (12);
2501 d.get_vbox()->pack_start (hbox, false, false);
2503 d.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
2504 d.add_button(Gtk::Stock::OK, Gtk::RESPONSE_OK);
2506 d.set_size_request (300, -1);
2508 entry.set_text (rs.front()->region()->name());
2509 entry.select_region (0, -1);
2511 entry.signal_activate().connect (sigc::bind (sigc::mem_fun (d, &Dialog::response), RESPONSE_OK));
2517 int const ret = d.run();
2521 if (ret != RESPONSE_OK) {
2525 std::string str = entry.get_text();
2526 strip_whitespace_edges (str);
2528 rs.front()->region()->set_name (str);
2529 _regions->redisplay ();
2534 Editor::audition_playlist_region_via_route (boost::shared_ptr<Region> region, Route& route)
2536 if (_session->is_auditioning()) {
2537 _session->cancel_audition ();
2540 // note: some potential for creativity here, because region doesn't
2541 // have to belong to the playlist that Route is handling
2543 // bool was_soloed = route.soloed();
2545 route.set_solo (true, this);
2547 _session->request_bounded_roll (region->position(), region->position() + region->length());
2549 /* XXX how to unset the solo state ? */
2552 /** Start an audition of the first selected region */
2554 Editor::play_edit_range ()
2556 framepos_t start, end;
2558 if (get_edit_op_range (start, end)) {
2559 _session->request_bounded_roll (start, end);
2564 Editor::play_selected_region ()
2566 framepos_t start = max_framepos;
2569 RegionSelection rs = get_regions_from_selection_and_entered ();
2575 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
2576 if ((*i)->region()->position() < start) {
2577 start = (*i)->region()->position();
2579 if ((*i)->region()->last_frame() + 1 > end) {
2580 end = (*i)->region()->last_frame() + 1;
2584 _session->request_bounded_roll (start, end);
2588 Editor::audition_playlist_region_standalone (boost::shared_ptr<Region> region)
2590 _session->audition_region (region);
2594 Editor::region_from_selection ()
2596 if (clicked_axisview == 0) {
2600 if (selection->time.empty()) {
2604 framepos_t start = selection->time[clicked_selection].start;
2605 framepos_t end = selection->time[clicked_selection].end;
2607 TrackViewList tracks = get_tracks_for_range_action ();
2609 framepos_t selection_cnt = end - start + 1;
2611 for (TrackSelection::iterator i = tracks.begin(); i != tracks.end(); ++i) {
2612 boost::shared_ptr<Region> current;
2613 boost::shared_ptr<Playlist> pl;
2614 framepos_t internal_start;
2617 if ((pl = (*i)->playlist()) == 0) {
2621 if ((current = pl->top_region_at (start)) == 0) {
2625 internal_start = start - current->position();
2626 RegionFactory::region_name (new_name, current->name(), true);
2630 plist.add (ARDOUR::Properties::start, current->start() + internal_start);
2631 plist.add (ARDOUR::Properties::length, selection_cnt);
2632 plist.add (ARDOUR::Properties::name, new_name);
2633 plist.add (ARDOUR::Properties::layer, 0);
2635 boost::shared_ptr<Region> region (RegionFactory::create (current, plist));
2640 Editor::create_region_from_selection (vector<boost::shared_ptr<Region> >& new_regions)
2642 if (selection->time.empty() || selection->tracks.empty()) {
2646 framepos_t start = selection->time[clicked_selection].start;
2647 framepos_t end = selection->time[clicked_selection].end;
2649 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
2650 sort_track_selection (ts);
2652 for (TrackSelection::iterator i = ts.begin(); i != ts.end(); ++i) {
2653 boost::shared_ptr<Region> current;
2654 boost::shared_ptr<Playlist> playlist;
2655 framepos_t internal_start;
2658 if ((playlist = (*i)->playlist()) == 0) {
2662 if ((current = playlist->top_region_at(start)) == 0) {
2666 internal_start = start - current->position();
2667 RegionFactory::region_name (new_name, current->name(), true);
2671 plist.add (ARDOUR::Properties::start, current->start() + internal_start);
2672 plist.add (ARDOUR::Properties::length, end - start + 1);
2673 plist.add (ARDOUR::Properties::name, new_name);
2675 new_regions.push_back (RegionFactory::create (current, plist));
2680 Editor::split_multichannel_region ()
2682 RegionSelection rs = get_regions_from_selection_and_entered ();
2688 vector< boost::shared_ptr<Region> > v;
2690 for (list<RegionView*>::iterator x = rs.begin(); x != rs.end(); ++x) {
2691 (*x)->region()->separate_by_channel (*_session, v);
2696 Editor::new_region_from_selection ()
2698 region_from_selection ();
2699 cancel_selection ();
2703 add_if_covered (RegionView* rv, const AudioRange* ar, RegionSelection* rs)
2705 switch (rv->region()->coverage (ar->start, ar->end - 1)) {
2706 case Evoral::OverlapNone:
2714 * - selected tracks, or if there are none...
2715 * - tracks containing selected regions, or if there are none...
2720 Editor::get_tracks_for_range_action () const
2724 if (selection->tracks.empty()) {
2726 /* use tracks with selected regions */
2728 RegionSelection rs = selection->regions;
2730 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
2731 TimeAxisView* tv = &(*i)->get_time_axis_view();
2733 if (!t.contains (tv)) {
2739 /* no regions and no tracks: use all tracks */
2745 t = selection->tracks;
2748 return t.filter_to_unique_playlists();
2752 Editor::separate_regions_between (const TimeSelection& ts)
2754 bool in_command = false;
2755 boost::shared_ptr<Playlist> playlist;
2756 RegionSelection new_selection;
2758 TrackViewList tmptracks = get_tracks_for_range_action ();
2759 sort_track_selection (tmptracks);
2761 for (TrackSelection::iterator i = tmptracks.begin(); i != tmptracks.end(); ++i) {
2763 RouteTimeAxisView* rtv;
2765 if ((rtv = dynamic_cast<RouteTimeAxisView*> ((*i))) != 0) {
2767 if (rtv->is_track()) {
2769 /* no edits to destructive tracks */
2771 if (rtv->track()->destructive()) {
2775 if ((playlist = rtv->playlist()) != 0) {
2777 playlist->clear_changes ();
2779 /* XXX need to consider musical time selections here at some point */
2781 double speed = rtv->track()->speed();
2784 for (list<AudioRange>::const_iterator t = ts.begin(); t != ts.end(); ++t) {
2786 sigc::connection c = rtv->view()->RegionViewAdded.connect (
2787 sigc::mem_fun(*this, &Editor::collect_new_region_view));
2789 latest_regionviews.clear ();
2791 playlist->partition ((framepos_t)((*t).start * speed),
2792 (framepos_t)((*t).end * speed), false);
2796 if (!latest_regionviews.empty()) {
2798 rtv->view()->foreach_regionview (sigc::bind (
2799 sigc::ptr_fun (add_if_covered),
2800 &(*t), &new_selection));
2803 begin_reversible_command (_("separate"));
2807 /* pick up changes to existing regions */
2809 vector<Command*> cmds;
2810 playlist->rdiff (cmds);
2811 _session->add_commands (cmds);
2813 /* pick up changes to the playlist itself (adds/removes)
2816 _session->add_command(new StatefulDiffCommand (playlist));
2825 // selection->set (new_selection);
2827 commit_reversible_command ();
2831 struct PlaylistState {
2832 boost::shared_ptr<Playlist> playlist;
2836 /** Take tracks from get_tracks_for_range_action and cut any regions
2837 * on those tracks so that the tracks are empty over the time
2841 Editor::separate_region_from_selection ()
2843 /* preferentially use *all* ranges in the time selection if we're in range mode
2844 to allow discontiguous operation, since get_edit_op_range() currently
2845 returns a single range.
2848 if (!selection->time.empty()) {
2850 separate_regions_between (selection->time);
2857 if (get_edit_op_range (start, end)) {
2859 AudioRange ar (start, end, 1);
2863 separate_regions_between (ts);
2869 Editor::separate_region_from_punch ()
2871 Location* loc = _session->locations()->auto_punch_location();
2873 separate_regions_using_location (*loc);
2878 Editor::separate_region_from_loop ()
2880 Location* loc = _session->locations()->auto_loop_location();
2882 separate_regions_using_location (*loc);
2887 Editor::separate_regions_using_location (Location& loc)
2889 if (loc.is_mark()) {
2893 AudioRange ar (loc.start(), loc.end(), 1);
2898 separate_regions_between (ts);
2901 /** Separate regions under the selected region */
2903 Editor::separate_under_selected_regions ()
2905 vector<PlaylistState> playlists;
2909 rs = get_regions_from_selection_and_entered();
2911 if (!_session || rs.empty()) {
2915 begin_reversible_command (_("separate region under"));
2917 list<boost::shared_ptr<Region> > regions_to_remove;
2919 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
2920 // we can't just remove the region(s) in this loop because
2921 // this removes them from the RegionSelection, and they thus
2922 // disappear from underneath the iterator, and the ++i above
2923 // SEGVs in a puzzling fashion.
2925 // so, first iterate over the regions to be removed from rs and
2926 // add them to the regions_to_remove list, and then
2927 // iterate over the list to actually remove them.
2929 regions_to_remove.push_back ((*i)->region());
2932 for (list<boost::shared_ptr<Region> >::iterator rl = regions_to_remove.begin(); rl != regions_to_remove.end(); ++rl) {
2934 boost::shared_ptr<Playlist> playlist = (*rl)->playlist();
2937 // is this check necessary?
2941 vector<PlaylistState>::iterator i;
2943 //only take state if this is a new playlist.
2944 for (i = playlists.begin(); i != playlists.end(); ++i) {
2945 if ((*i).playlist == playlist) {
2950 if (i == playlists.end()) {
2952 PlaylistState before;
2953 before.playlist = playlist;
2954 before.before = &playlist->get_state();
2956 playlist->freeze ();
2957 playlists.push_back(before);
2960 //Partition on the region bounds
2961 playlist->partition ((*rl)->first_frame() - 1, (*rl)->last_frame() + 1, true);
2963 //Re-add region that was just removed due to the partition operation
2964 playlist->add_region( (*rl), (*rl)->first_frame() );
2967 vector<PlaylistState>::iterator pl;
2969 for (pl = playlists.begin(); pl != playlists.end(); ++pl) {
2970 (*pl).playlist->thaw ();
2971 _session->add_command(new MementoCommand<Playlist>(*(*pl).playlist, (*pl).before, &(*pl).playlist->get_state()));
2974 commit_reversible_command ();
2978 Editor::crop_region_to_selection ()
2980 if (!selection->time.empty()) {
2982 crop_region_to (selection->time.start(), selection->time.end_frame());
2989 if (get_edit_op_range (start, end)) {
2990 crop_region_to (start, end);
2997 Editor::crop_region_to (framepos_t start, framepos_t end)
2999 vector<boost::shared_ptr<Playlist> > playlists;
3000 boost::shared_ptr<Playlist> playlist;
3003 if (selection->tracks.empty()) {
3004 ts = track_views.filter_to_unique_playlists();
3006 ts = selection->tracks.filter_to_unique_playlists ();
3009 sort_track_selection (ts);
3011 for (TrackSelection::iterator i = ts.begin(); i != ts.end(); ++i) {
3013 RouteTimeAxisView* rtv;
3015 if ((rtv = dynamic_cast<RouteTimeAxisView*> ((*i))) != 0) {
3017 boost::shared_ptr<Track> t = rtv->track();
3019 if (t != 0 && ! t->destructive()) {
3021 if ((playlist = rtv->playlist()) != 0) {
3022 playlists.push_back (playlist);
3028 if (playlists.empty()) {
3032 framepos_t the_start;
3036 begin_reversible_command (_("trim to selection"));
3038 for (vector<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
3040 boost::shared_ptr<Region> region;
3044 if ((region = (*i)->top_region_at(the_start)) == 0) {
3048 /* now adjust lengths to that we do the right thing
3049 if the selection extends beyond the region
3052 the_start = max (the_start, (framepos_t) region->position());
3053 if (max_framepos - the_start < region->length()) {
3054 the_end = the_start + region->length() - 1;
3056 the_end = max_framepos;
3058 the_end = min (end, the_end);
3059 cnt = the_end - the_start + 1;
3061 region->clear_changes ();
3062 region->trim_to (the_start, cnt);
3063 _session->add_command (new StatefulDiffCommand (region));
3066 commit_reversible_command ();
3070 Editor::region_fill_track ()
3072 RegionSelection rs = get_regions_from_selection_and_entered ();
3074 if (!_session || rs.empty()) {
3078 framepos_t const end = _session->current_end_frame ();
3080 begin_reversible_command (Operations::region_fill);
3082 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3084 boost::shared_ptr<Region> region ((*i)->region());
3086 boost::shared_ptr<Playlist> pl = region->playlist();
3088 if (end <= region->last_frame()) {
3092 double times = (double) (end - region->last_frame()) / (double) region->length();
3098 pl->clear_changes ();
3099 pl->add_region (RegionFactory::create (region, true), region->last_frame(), times);
3100 _session->add_command (new StatefulDiffCommand (pl));
3103 commit_reversible_command ();
3107 Editor::region_fill_selection ()
3109 if (clicked_routeview == 0 || !clicked_routeview->is_audio_track()) {
3113 if (selection->time.empty()) {
3117 boost::shared_ptr<Region> region = _regions->get_single_selection ();
3122 framepos_t start = selection->time[clicked_selection].start;
3123 framepos_t end = selection->time[clicked_selection].end;
3125 boost::shared_ptr<Playlist> playlist;
3127 if (selection->tracks.empty()) {
3131 framepos_t selection_length = end - start;
3132 float times = (float)selection_length / region->length();
3134 begin_reversible_command (Operations::fill_selection);
3136 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
3138 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
3140 if ((playlist = (*i)->playlist()) == 0) {
3144 playlist->clear_changes ();
3145 playlist->add_region (RegionFactory::create (region, true), start, times);
3146 _session->add_command (new StatefulDiffCommand (playlist));
3149 commit_reversible_command ();
3153 Editor::set_region_sync_position ()
3155 set_sync_point (get_preferred_edit_position (), get_regions_from_selection_and_edit_point ());
3159 Editor::set_sync_point (framepos_t where, const RegionSelection& rs)
3161 bool in_command = false;
3163 for (RegionSelection::const_iterator r = rs.begin(); r != rs.end(); ++r) {
3165 if (!(*r)->region()->covers (where)) {
3169 boost::shared_ptr<Region> region ((*r)->region());
3172 begin_reversible_command (_("set sync point"));
3176 region->clear_changes ();
3177 region->set_sync_position (where);
3178 _session->add_command(new StatefulDiffCommand (region));
3182 commit_reversible_command ();
3186 /** Remove the sync positions of the selection */
3188 Editor::remove_region_sync ()
3190 RegionSelection rs = get_regions_from_selection_and_entered ();
3196 begin_reversible_command (_("remove region sync"));
3198 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3200 (*i)->region()->clear_changes ();
3201 (*i)->region()->clear_sync_position ();
3202 _session->add_command(new StatefulDiffCommand ((*i)->region()));
3205 commit_reversible_command ();
3209 Editor::naturalize_region ()
3211 RegionSelection rs = get_regions_from_selection_and_entered ();
3217 if (rs.size() > 1) {
3218 begin_reversible_command (_("move regions to original position"));
3220 begin_reversible_command (_("move region to original position"));
3223 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3224 (*i)->region()->clear_changes ();
3225 (*i)->region()->move_to_natural_position ();
3226 _session->add_command (new StatefulDiffCommand ((*i)->region()));
3229 commit_reversible_command ();
3233 Editor::align_regions (RegionPoint what)
3235 RegionSelection const rs = get_regions_from_selection_and_edit_point ();
3241 begin_reversible_command (_("align selection"));
3243 framepos_t const position = get_preferred_edit_position ();
3245 for (RegionSelection::const_iterator i = rs.begin(); i != rs.end(); ++i) {
3246 align_region_internal ((*i)->region(), what, position);
3249 commit_reversible_command ();
3252 struct RegionSortByTime {
3253 bool operator() (const RegionView* a, const RegionView* b) {
3254 return a->region()->position() < b->region()->position();
3259 Editor::align_regions_relative (RegionPoint point)
3261 RegionSelection const rs = get_regions_from_selection_and_edit_point ();
3267 framepos_t const position = get_preferred_edit_position ();
3269 framepos_t distance = 0;
3273 list<RegionView*> sorted;
3274 rs.by_position (sorted);
3276 boost::shared_ptr<Region> r ((*sorted.begin())->region());
3281 if (position > r->position()) {
3282 distance = position - r->position();
3284 distance = r->position() - position;
3290 if (position > r->last_frame()) {
3291 distance = position - r->last_frame();
3292 pos = r->position() + distance;
3294 distance = r->last_frame() - position;
3295 pos = r->position() - distance;
3301 pos = r->adjust_to_sync (position);
3302 if (pos > r->position()) {
3303 distance = pos - r->position();
3305 distance = r->position() - pos;
3311 if (pos == r->position()) {
3315 begin_reversible_command (_("align selection (relative)"));
3317 /* move first one specially */
3319 r->clear_changes ();
3320 r->set_position (pos);
3321 _session->add_command(new StatefulDiffCommand (r));
3323 /* move rest by the same amount */
3327 for (list<RegionView*>::iterator i = sorted.begin(); i != sorted.end(); ++i) {
3329 boost::shared_ptr<Region> region ((*i)->region());
3331 region->clear_changes ();
3334 region->set_position (region->position() + distance);
3336 region->set_position (region->position() - distance);
3339 _session->add_command(new StatefulDiffCommand (region));
3343 commit_reversible_command ();
3347 Editor::align_region (boost::shared_ptr<Region> region, RegionPoint point, framepos_t position)
3349 begin_reversible_command (_("align region"));
3350 align_region_internal (region, point, position);
3351 commit_reversible_command ();
3355 Editor::align_region_internal (boost::shared_ptr<Region> region, RegionPoint point, framepos_t position)
3357 region->clear_changes ();
3361 region->set_position (region->adjust_to_sync (position));
3365 if (position > region->length()) {
3366 region->set_position (position - region->length());
3371 region->set_position (position);
3375 _session->add_command(new StatefulDiffCommand (region));
3379 Editor::trim_region_front ()
3385 Editor::trim_region_back ()
3387 trim_region (false);
3391 Editor::trim_region (bool front)
3393 framepos_t where = get_preferred_edit_position();
3394 RegionSelection rs = get_regions_from_selection_and_edit_point ();
3400 begin_reversible_command (front ? _("trim front") : _("trim back"));
3402 for (list<RegionView*>::const_iterator i = rs.by_layer().begin(); i != rs.by_layer().end(); ++i) {
3403 if (!(*i)->region()->locked()) {
3405 (*i)->region()->clear_changes ();
3408 (*i)->region()->trim_front (where);
3409 maybe_locate_with_edit_preroll ( where );
3411 (*i)->region()->trim_end (where);
3412 maybe_locate_with_edit_preroll ( where );
3415 _session->add_command (new StatefulDiffCommand ((*i)->region()));
3419 commit_reversible_command ();
3422 /** Trim the end of the selected regions to the position of the edit cursor */
3424 Editor::trim_region_to_loop ()
3426 Location* loc = _session->locations()->auto_loop_location();
3430 trim_region_to_location (*loc, _("trim to loop"));
3434 Editor::trim_region_to_punch ()
3436 Location* loc = _session->locations()->auto_punch_location();
3440 trim_region_to_location (*loc, _("trim to punch"));
3444 Editor::trim_region_to_location (const Location& loc, const char* str)
3446 RegionSelection rs = get_regions_from_selection_and_entered ();
3448 begin_reversible_command (str);
3450 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
3451 RegionView* rv = (*x);
3453 /* require region to span proposed trim */
3454 switch (rv->region()->coverage (loc.start(), loc.end())) {
3455 case Evoral::OverlapInternal:
3461 RouteTimeAxisView* tav = dynamic_cast<RouteTimeAxisView*> (&rv->get_time_axis_view());
3470 if (tav->track() != 0) {
3471 speed = tav->track()->speed();
3474 start = session_frame_to_track_frame (loc.start(), speed);
3475 end = session_frame_to_track_frame (loc.end(), speed);
3477 rv->region()->clear_changes ();
3478 rv->region()->trim_to (start, (end - start));
3479 _session->add_command(new StatefulDiffCommand (rv->region()));
3482 commit_reversible_command ();
3486 Editor::trim_region_to_previous_region_end ()
3488 return trim_to_region(false);
3492 Editor::trim_region_to_next_region_start ()
3494 return trim_to_region(true);
3498 Editor::trim_to_region(bool forward)
3500 RegionSelection rs = get_regions_from_selection_and_entered ();
3502 begin_reversible_command (_("trim to region"));
3504 boost::shared_ptr<Region> next_region;
3506 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
3508 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*x);
3514 AudioTimeAxisView* atav = dynamic_cast<AudioTimeAxisView*> (&arv->get_time_axis_view());
3522 if (atav->track() != 0) {
3523 speed = atav->track()->speed();
3527 boost::shared_ptr<Region> region = arv->region();
3528 boost::shared_ptr<Playlist> playlist (region->playlist());
3530 region->clear_changes ();
3534 next_region = playlist->find_next_region (region->first_frame(), Start, 1);
3540 region->trim_end((framepos_t) ( (next_region->first_frame() - 1) * speed));
3541 arv->region_changed (PropertyChange (ARDOUR::Properties::length));
3545 next_region = playlist->find_next_region (region->first_frame(), Start, 0);
3551 region->trim_front((framepos_t) ((next_region->last_frame() + 1) * speed));
3553 arv->region_changed (ARDOUR::bounds_change);
3556 _session->add_command(new StatefulDiffCommand (region));
3559 commit_reversible_command ();
3563 Editor::unfreeze_route ()
3565 if (clicked_routeview == 0 || !clicked_routeview->is_track()) {
3569 clicked_routeview->track()->unfreeze ();
3573 Editor::_freeze_thread (void* arg)
3575 return static_cast<Editor*>(arg)->freeze_thread ();
3579 Editor::freeze_thread ()
3581 /* create event pool because we may need to talk to the session */
3582 SessionEvent::create_per_thread_pool ("freeze events", 64);
3583 /* create per-thread buffers for process() tree to use */
3584 clicked_routeview->audio_track()->freeze_me (*current_interthread_info);
3585 current_interthread_info->done = true;
3590 Editor::freeze_route ()
3596 /* stop transport before we start. this is important */
3598 _session->request_transport_speed (0.0);
3600 /* wait for just a little while, because the above call is asynchronous */
3602 Glib::usleep (250000);
3604 if (clicked_routeview == 0 || !clicked_routeview->is_audio_track()) {
3608 if (!clicked_routeview->track()->bounceable (clicked_routeview->track()->main_outs(), true)) {
3610 _("This track/bus cannot be frozen because the signal adds or loses channels before reaching the outputs.\n"
3611 "This is typically caused by plugins that generate stereo output from mono input or vice versa.")
3613 d.set_title (_("Cannot freeze"));
3618 if (clicked_routeview->track()->has_external_redirects()) {
3619 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"
3620 "Freezing will only process the signal as far as the first send/insert/return."),
3621 clicked_routeview->track()->name()), true, MESSAGE_INFO, BUTTONS_NONE, true);
3623 d.add_button (_("Freeze anyway"), Gtk::RESPONSE_OK);
3624 d.add_button (_("Don't freeze"), Gtk::RESPONSE_CANCEL);
3625 d.set_title (_("Freeze Limits"));
3627 int response = d.run ();
3630 case Gtk::RESPONSE_CANCEL:
3637 InterThreadInfo itt;
3638 current_interthread_info = &itt;
3640 InterthreadProgressWindow ipw (current_interthread_info, _("Freeze"), _("Cancel Freeze"));
3642 pthread_create_and_store (X_("freezer"), &itt.thread, _freeze_thread, this);
3644 set_canvas_cursor (_cursors->wait);
3646 while (!itt.done && !itt.cancel) {
3647 gtk_main_iteration ();
3650 current_interthread_info = 0;
3651 set_canvas_cursor (current_canvas_cursor);
3655 Editor::bounce_range_selection (bool replace, bool enable_processing)
3657 if (selection->time.empty()) {
3661 TrackSelection views = selection->tracks;
3663 for (TrackViewList::iterator i = views.begin(); i != views.end(); ++i) {
3665 if (enable_processing) {
3667 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*i);
3669 if (rtv && rtv->track() && replace && enable_processing && !rtv->track()->bounceable (rtv->track()->main_outs(), false)) {
3671 _("You can't perform this operation because the processing of the signal "
3672 "will cause one or more of the tracks to end up with a region with more channels than this track has inputs.\n\n"
3673 "You can do this without processing, which is a different operation.")
3675 d.set_title (_("Cannot bounce"));
3682 framepos_t start = selection->time[clicked_selection].start;
3683 framepos_t end = selection->time[clicked_selection].end;
3684 framepos_t cnt = end - start + 1;
3686 begin_reversible_command (_("bounce range"));
3688 for (TrackViewList::iterator i = views.begin(); i != views.end(); ++i) {
3690 RouteTimeAxisView* rtv;
3692 if ((rtv = dynamic_cast<RouteTimeAxisView*> (*i)) == 0) {
3696 boost::shared_ptr<Playlist> playlist;
3698 if ((playlist = rtv->playlist()) == 0) {
3702 InterThreadInfo itt;
3704 playlist->clear_changes ();
3705 playlist->clear_owned_changes ();
3707 boost::shared_ptr<Region> r;
3709 if (enable_processing) {
3710 r = rtv->track()->bounce_range (start, start+cnt, itt, rtv->track()->main_outs(), false);
3712 r = rtv->track()->bounce_range (start, start+cnt, itt, boost::shared_ptr<Processor>(), false);
3720 list<AudioRange> ranges;
3721 ranges.push_back (AudioRange (start, start+cnt, 0));
3722 playlist->cut (ranges); // discard result
3723 playlist->add_region (r, start);
3726 vector<Command*> cmds;
3727 playlist->rdiff (cmds);
3728 _session->add_commands (cmds);
3730 _session->add_command (new StatefulDiffCommand (playlist));
3733 commit_reversible_command ();
3736 /** Delete selected regions, automation points or a time range */
3740 //special case: if the user is pointing in the editor/mixer strip, they may be trying to delete a plugin.
3741 //we need this because the editor-mixer strip is in the editor window, so it doesn't get the bindings from the mix window
3742 bool deleted = false;
3743 if ( current_mixer_strip && current_mixer_strip == MixerStrip::entered_mixer_strip() )
3744 deleted = current_mixer_strip->delete_processors ();
3750 /** Cut selected regions, automation points or a time range */
3757 /** Copy selected regions, automation points or a time range */
3765 /** @return true if a Cut, Copy or Clear is possible */
3767 Editor::can_cut_copy () const
3769 if (!selection->time.empty() || !selection->regions.empty() || !selection->points.empty())
3776 /** Cut, copy or clear selected regions, automation points or a time range.
3777 * @param op Operation (Delete, Cut, Copy or Clear)
3780 Editor::cut_copy (CutCopyOp op)
3782 /* only cancel selection if cut/copy is successful.*/
3788 opname = _("delete");
3797 opname = _("clear");
3801 /* if we're deleting something, and the mouse is still pressed,
3802 the thing we started a drag for will be gone when we release
3803 the mouse button(s). avoid this. see part 2 at the end of
3807 if (op == Delete || op == Cut || op == Clear) {
3808 if (_drags->active ()) {
3813 if ( op != Delete ) //"Delete" doesn't change copy/paste buf
3814 cut_buffer->clear ();
3816 if (entered_marker) {
3818 /* cut/delete op while pointing at a marker */
3821 Location* loc = find_location_from_marker (entered_marker, ignored);
3823 if (_session && loc) {
3824 Glib::signal_idle().connect (sigc::bind (sigc::mem_fun(*this, &Editor::really_remove_marker), loc));
3831 if (internal_editing()) {
3833 switch (effective_mouse_mode()) {
3836 begin_reversible_command (opname + ' ' + X_("MIDI"));
3838 commit_reversible_command ();
3847 bool did_edit = false;
3849 if (!selection->regions.empty() || !selection->points.empty()) {
3850 begin_reversible_command (opname + ' ' + _("objects"));
3853 if (!selection->regions.empty()) {
3854 cut_copy_regions (op, selection->regions);
3856 if (op == Cut || op == Delete) {
3857 selection->clear_regions ();
3861 if (!selection->points.empty()) {
3862 cut_copy_points (op);
3864 if (op == Cut || op == Delete) {
3865 selection->clear_points ();
3868 } else if (selection->time.empty()) {
3869 framepos_t start, end;
3870 /* no time selection, see if we can get an edit range
3873 if (get_edit_op_range (start, end)) {
3874 selection->set (start, end);
3876 } else if (!selection->time.empty()) {
3877 begin_reversible_command (opname + ' ' + _("range"));
3880 cut_copy_ranges (op);
3882 if (op == Cut || op == Delete) {
3883 selection->clear_time ();
3888 /* reset repeated paste state */
3891 commit_reversible_command ();
3894 if (op == Delete || op == Cut || op == Clear) {
3899 struct AutomationRecord {
3900 AutomationRecord () : state (0) , line(NULL) {}
3901 AutomationRecord (XMLNode* s, const AutomationLine* l) : state (s) , line (l) {}
3903 XMLNode* state; ///< state before any operation
3904 const AutomationLine* line; ///< line this came from
3905 boost::shared_ptr<Evoral::ControlList> copy; ///< copied events for the cut buffer
3908 /** Cut, copy or clear selected automation points.
3909 * @param op Operation (Cut, Copy or Clear)
3912 Editor::cut_copy_points (CutCopyOp op)
3914 if (selection->points.empty ()) {
3918 /* XXX: not ideal, as there may be more than one track involved in the point selection */
3919 _last_cut_copy_source_track = &selection->points.front()->line().trackview;
3921 /* Keep a record of the AutomationLists that we end up using in this operation */
3922 typedef std::map<boost::shared_ptr<AutomationList>, AutomationRecord> Lists;
3925 /* Go through all selected points, making an AutomationRecord for each distinct AutomationList */
3926 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
3927 const AutomationLine& line = (*i)->line();
3928 const boost::shared_ptr<AutomationList> al = line.the_list();
3929 if (lists.find (al) == lists.end ()) {
3930 /* We haven't seen this list yet, so make a record for it. This includes
3931 taking a copy of its current state, in case this is needed for undo later.
3933 lists[al] = AutomationRecord (&al->get_state (), &line);
3937 if (op == Cut || op == Copy) {
3938 /* This operation will involve putting things in the cut buffer, so create an empty
3939 ControlList for each of our source lists to put the cut buffer data in.
3941 framepos_t start = std::numeric_limits<framepos_t>::max();
3942 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
3943 i->second.copy = i->first->create (i->first->parameter ());
3945 /* Calculate earliest start position of any point in selection. */
3946 start = std::min(start, i->second.line->session_position(i->first->begin()));
3949 /* Add all selected points to the relevant copy ControlLists */
3950 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
3951 boost::shared_ptr<AutomationList> al = (*i)->line().the_list();
3952 AutomationList::const_iterator j = (*i)->model ();
3953 lists[al].copy->fast_simple_add ((*j)->when, (*j)->value);
3956 /* Snap start time backwards, so copy/paste is snap aligned. */
3957 snap_to(start, RoundDownMaybe);
3959 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
3960 /* Correct this copy list so that it is relative to the earliest
3961 start time, so relative ordering between points is preserved
3962 when copying from several lists. */
3963 const AutomationLine* line = i->second.line;
3964 const double line_offset = line->time_converter().from(start);
3966 for (AutomationList::iterator j = i->second.copy->begin(); j != i->second.copy->end(); ++j) {
3967 (*j)->when -= line_offset;
3970 /* And add it to the cut buffer */
3971 cut_buffer->add (i->second.copy);
3975 if (op == Delete || op == Cut) {
3976 /* This operation needs to remove things from the main AutomationList, so do that now */
3978 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
3979 i->first->freeze ();
3982 /* Remove each selected point from its AutomationList */
3983 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
3984 boost::shared_ptr<AutomationList> al = (*i)->line().the_list();
3985 al->erase ((*i)->model ());
3988 /* Thaw the lists and add undo records for them */
3989 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
3990 boost::shared_ptr<AutomationList> al = i->first;
3992 _session->add_command (new MementoCommand<AutomationList> (*al.get(), i->second.state, &(al->get_state ())));
3997 /** Cut, copy or clear selected automation points.
3998 * @param op Operation (Cut, Copy or Clear)
4001 Editor::cut_copy_midi (CutCopyOp op)
4003 for (MidiRegionSelection::iterator i = selection->midi_regions.begin(); i != selection->midi_regions.end(); ++i) {
4004 MidiRegionView* mrv = dynamic_cast<MidiRegionView*>(*i);
4006 mrv->cut_copy_clear (op);
4008 /* XXX: not ideal, as there may be more than one track involved in the selection */
4009 _last_cut_copy_source_track = &mrv->get_time_axis_view();
4013 if (!selection->points.empty()) {
4014 cut_copy_points (op);
4015 if (op == Cut || op == Delete) {
4016 selection->clear_points ();
4021 struct lt_playlist {
4022 bool operator () (const PlaylistState& a, const PlaylistState& b) {
4023 return a.playlist < b.playlist;
4027 struct PlaylistMapping {
4029 boost::shared_ptr<Playlist> pl;
4031 PlaylistMapping (TimeAxisView* tvp) : tv (tvp) {}
4034 /** Remove `clicked_regionview' */
4036 Editor::remove_clicked_region ()
4038 if (clicked_routeview == 0 || clicked_regionview == 0) {
4042 boost::shared_ptr<Playlist> playlist = clicked_routeview->playlist();
4044 playlist->clear_changes ();
4045 playlist->clear_owned_changes ();
4046 playlist->remove_region (clicked_regionview->region());
4047 if (Config->get_edit_mode() == Ripple)
4048 playlist->ripple (clicked_regionview->region()->position(), -clicked_regionview->region()->length(), boost::shared_ptr<Region>());
4050 /* We might have removed regions, which alters other regions' layering_index,
4051 so we need to do a recursive diff here.
4053 vector<Command*> cmds;
4054 playlist->rdiff (cmds);
4055 _session->add_commands (cmds);
4057 _session->add_command(new StatefulDiffCommand (playlist));
4058 commit_reversible_command ();
4062 /** Remove the selected regions */
4064 Editor::remove_selected_regions ()
4066 RegionSelection rs = get_regions_from_selection_and_entered ();
4068 if (!_session || rs.empty()) {
4072 begin_reversible_command (_("remove region"));
4074 list<boost::shared_ptr<Region> > regions_to_remove;
4076 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
4077 // we can't just remove the region(s) in this loop because
4078 // this removes them from the RegionSelection, and they thus
4079 // disappear from underneath the iterator, and the ++i above
4080 // SEGVs in a puzzling fashion.
4082 // so, first iterate over the regions to be removed from rs and
4083 // add them to the regions_to_remove list, and then
4084 // iterate over the list to actually remove them.
4086 regions_to_remove.push_back ((*i)->region());
4089 vector<boost::shared_ptr<Playlist> > playlists;
4091 for (list<boost::shared_ptr<Region> >::iterator rl = regions_to_remove.begin(); rl != regions_to_remove.end(); ++rl) {
4093 boost::shared_ptr<Playlist> playlist = (*rl)->playlist();
4096 // is this check necessary?
4100 /* get_regions_from_selection_and_entered() guarantees that
4101 the playlists involved are unique, so there is no need
4105 playlists.push_back (playlist);
4107 playlist->clear_changes ();
4108 playlist->clear_owned_changes ();
4109 playlist->freeze ();
4110 playlist->remove_region (*rl);
4111 if (Config->get_edit_mode() == Ripple)
4112 playlist->ripple ((*rl)->position(), -(*rl)->length(), boost::shared_ptr<Region>());
4116 vector<boost::shared_ptr<Playlist> >::iterator pl;
4118 for (pl = playlists.begin(); pl != playlists.end(); ++pl) {
4121 /* We might have removed regions, which alters other regions' layering_index,
4122 so we need to do a recursive diff here.
4124 vector<Command*> cmds;
4125 (*pl)->rdiff (cmds);
4126 _session->add_commands (cmds);
4128 _session->add_command(new StatefulDiffCommand (*pl));
4131 commit_reversible_command ();
4134 /** Cut, copy or clear selected regions.
4135 * @param op Operation (Cut, Copy or Clear)
4138 Editor::cut_copy_regions (CutCopyOp op, RegionSelection& rs)
4140 /* we can't use a std::map here because the ordering is important, and we can't trivially sort
4141 a map when we want ordered access to both elements. i think.
4144 vector<PlaylistMapping> pmap;
4146 framepos_t first_position = max_framepos;
4148 typedef set<boost::shared_ptr<Playlist> > FreezeList;
4149 FreezeList freezelist;
4151 /* get ordering correct before we cut/copy */
4153 rs.sort_by_position_and_track ();
4155 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
4157 first_position = min ((framepos_t) (*x)->region()->position(), first_position);
4159 if (op == Cut || op == Clear || op == Delete) {
4160 boost::shared_ptr<Playlist> pl = (*x)->region()->playlist();
4163 FreezeList::iterator fl;
4165 // only take state if this is a new playlist.
4166 for (fl = freezelist.begin(); fl != freezelist.end(); ++fl) {
4172 if (fl == freezelist.end()) {
4173 pl->clear_changes();
4174 pl->clear_owned_changes ();
4176 freezelist.insert (pl);
4181 TimeAxisView* tv = &(*x)->get_time_axis_view();
4182 vector<PlaylistMapping>::iterator z;
4184 for (z = pmap.begin(); z != pmap.end(); ++z) {
4185 if ((*z).tv == tv) {
4190 if (z == pmap.end()) {
4191 pmap.push_back (PlaylistMapping (tv));
4195 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ) {
4197 boost::shared_ptr<Playlist> pl = (*x)->region()->playlist();
4200 /* region not yet associated with a playlist (e.g. unfinished
4207 TimeAxisView& tv = (*x)->get_time_axis_view();
4208 boost::shared_ptr<Playlist> npl;
4209 RegionSelection::iterator tmp;
4216 vector<PlaylistMapping>::iterator z;
4218 for (z = pmap.begin(); z != pmap.end(); ++z) {
4219 if ((*z).tv == &tv) {
4224 assert (z != pmap.end());
4227 npl = PlaylistFactory::create (pl->data_type(), *_session, "cutlist", true);
4235 boost::shared_ptr<Region> r = (*x)->region();
4236 boost::shared_ptr<Region> _xx;
4242 pl->remove_region (r);
4243 if (Config->get_edit_mode() == Ripple)
4244 pl->ripple (r->position(), -r->length(), boost::shared_ptr<Region>());
4248 _xx = RegionFactory::create (r);
4249 npl->add_region (_xx, r->position() - first_position);
4250 pl->remove_region (r);
4251 if (Config->get_edit_mode() == Ripple)
4252 pl->ripple (r->position(), -r->length(), boost::shared_ptr<Region>());
4256 /* copy region before adding, so we're not putting same object into two different playlists */
4257 npl->add_region (RegionFactory::create (r), r->position() - first_position);
4261 pl->remove_region (r);
4262 if (Config->get_edit_mode() == Ripple)
4263 pl->ripple (r->position(), -r->length(), boost::shared_ptr<Region>());
4272 list<boost::shared_ptr<Playlist> > foo;
4274 /* the pmap is in the same order as the tracks in which selected regions occured */
4276 for (vector<PlaylistMapping>::iterator i = pmap.begin(); i != pmap.end(); ++i) {
4279 foo.push_back ((*i).pl);
4284 cut_buffer->set (foo);
4288 _last_cut_copy_source_track = 0;
4290 _last_cut_copy_source_track = pmap.front().tv;
4294 for (FreezeList::iterator pl = freezelist.begin(); pl != freezelist.end(); ++pl) {
4297 /* We might have removed regions, which alters other regions' layering_index,
4298 so we need to do a recursive diff here.
4300 vector<Command*> cmds;
4301 (*pl)->rdiff (cmds);
4302 _session->add_commands (cmds);
4304 _session->add_command (new StatefulDiffCommand (*pl));
4309 Editor::cut_copy_ranges (CutCopyOp op)
4311 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4313 /* Sort the track selection now, so that it if is used, the playlists
4314 selected by the calls below to cut_copy_clear are in the order that
4315 their tracks appear in the editor. This makes things like paste
4316 of ranges work properly.
4319 sort_track_selection (ts);
4322 if (!entered_track) {
4325 ts.push_back (entered_track);
4328 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4329 (*i)->cut_copy_clear (*selection, op);
4334 Editor::paste (float times, bool from_context)
4336 DEBUG_TRACE (DEBUG::CutNPaste, "paste to preferred edit pos\n");
4338 paste_internal (get_preferred_edit_position (false, from_context), times);
4342 Editor::mouse_paste ()
4347 if (!mouse_frame (where, ignored)) {
4352 paste_internal (where, 1);
4356 Editor::paste_internal (framepos_t position, float times)
4358 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("apparent paste position is %1\n", position));
4360 if (cut_buffer->empty(internal_editing())) {
4364 if (position == max_framepos) {
4365 position = get_preferred_edit_position();
4366 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("preferred edit position is %1\n", position));
4369 if (position == last_paste_pos) {
4370 /* repeated paste in the same position */
4373 /* paste in new location, reset repeated paste state */
4375 last_paste_pos = position;
4378 /* get everything in the correct order */
4381 if (!selection->tracks.empty()) {
4382 /* If there is a track selection, paste into exactly those tracks and
4383 only those tracks. This allows the user to be explicit and override
4384 the below "do the reasonable thing" logic. */
4385 ts = selection->tracks.filter_to_unique_playlists ();
4386 sort_track_selection (ts);
4388 /* Figure out which track to base the paste at. */
4389 TimeAxisView* base_track = NULL;
4390 if (_edit_point == Editing::EditAtMouse && entered_track) {
4391 /* With the mouse edit point, paste onto the track under the mouse. */
4392 base_track = entered_track;
4393 } else if (_edit_point == Editing::EditAtMouse && entered_regionview) {
4394 /* With the mouse edit point, paste onto the track of the region under the mouse. */
4395 base_track = &entered_regionview->get_time_axis_view();
4396 } else if (_last_cut_copy_source_track) {
4397 /* Paste to the track that the cut/copy came from (see mantis #333). */
4398 base_track = _last_cut_copy_source_track;
4400 /* This is "impossible" since we've copied... well, do nothing. */
4404 /* Walk up to parent if necessary, so base track is a route. */
4405 while (base_track->get_parent()) {
4406 base_track = base_track->get_parent();
4409 /* Add base track and all tracks below it. The paste logic will select
4410 the appropriate object types from the cut buffer in relative order. */
4411 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4412 if ((*i)->order() >= base_track->order()) {
4417 /* Sort tracks so the nth track of type T will pick the nth object of type T. */
4418 sort_track_selection (ts);
4420 /* Add automation children of each track in order, for pasting several lines. */
4421 for (TrackViewList::iterator i = ts.begin(); i != ts.end();) {
4422 /* Add any automation children for pasting several lines */
4423 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*i++);
4428 typedef RouteTimeAxisView::AutomationTracks ATracks;
4429 const ATracks& atracks = rtv->automation_tracks();
4430 for (ATracks::const_iterator a = atracks.begin(); a != atracks.end(); ++a) {
4431 i = ts.insert(i, a->second.get());
4436 /* We now have a list of trackviews starting at base_track, including
4437 automation children, in the order shown in the editor, e.g. R1,
4438 R1.A1, R1.A2, R2, R2.A1, ... */
4441 if (internal_editing ()) {
4443 /* undo/redo is handled by individual tracks/regions */
4446 get_regions_at (rs, position, ts);
4449 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
4450 MidiRegionView* mrv = dynamic_cast<MidiRegionView*> (*r);
4452 mrv->paste (position, paste_count, times, *cut_buffer, counts);
4458 /* we do redo (do you do voodoo?) */
4460 begin_reversible_command (Operations::paste);
4463 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4464 (*i)->paste (position, paste_count, times, *cut_buffer, counts);
4467 commit_reversible_command ();
4472 Editor::duplicate_some_regions (RegionSelection& regions, float times)
4474 boost::shared_ptr<Playlist> playlist;
4475 RegionSelection sel = regions; // clear (below) may clear the argument list if its the current region selection
4476 RegionSelection foo;
4478 framepos_t const start_frame = regions.start ();
4479 framepos_t const end_frame = regions.end_frame ();
4481 begin_reversible_command (Operations::duplicate_region);
4483 selection->clear_regions ();
4485 for (RegionSelection::iterator i = sel.begin(); i != sel.end(); ++i) {
4487 boost::shared_ptr<Region> r ((*i)->region());
4489 TimeAxisView& tv = (*i)->get_time_axis_view();
4490 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (&tv);
4491 latest_regionviews.clear ();
4492 sigc::connection c = rtv->view()->RegionViewAdded.connect (sigc::mem_fun(*this, &Editor::collect_new_region_view));
4494 playlist = (*i)->region()->playlist();
4495 playlist->clear_changes ();
4496 playlist->duplicate (r, end_frame + (r->first_frame() - start_frame), times);
4497 _session->add_command(new StatefulDiffCommand (playlist));
4501 foo.insert (foo.end(), latest_regionviews.begin(), latest_regionviews.end());
4504 commit_reversible_command ();
4507 selection->set (foo);
4512 Editor::duplicate_selection (float times)
4514 if (selection->time.empty() || selection->tracks.empty()) {
4518 boost::shared_ptr<Playlist> playlist;
4519 vector<boost::shared_ptr<Region> > new_regions;
4520 vector<boost::shared_ptr<Region> >::iterator ri;
4522 create_region_from_selection (new_regions);
4524 if (new_regions.empty()) {
4528 begin_reversible_command (_("duplicate selection"));
4530 ri = new_regions.begin();
4532 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4534 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4535 if ((playlist = (*i)->playlist()) == 0) {
4538 playlist->clear_changes ();
4539 playlist->duplicate (*ri, selection->time[clicked_selection].end, times);
4540 _session->add_command (new StatefulDiffCommand (playlist));
4543 if (ri == new_regions.end()) {
4548 commit_reversible_command ();
4551 /** Reset all selected points to the relevant default value */
4553 Editor::reset_point_selection ()
4555 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
4556 ARDOUR::AutomationList::iterator j = (*i)->model ();
4557 (*j)->value = (*i)->line().the_list()->default_value ();
4562 Editor::center_playhead ()
4564 float const page = _visible_canvas_width * samples_per_pixel;
4565 center_screen_internal (playhead_cursor->current_frame (), page);
4569 Editor::center_edit_point ()
4571 float const page = _visible_canvas_width * samples_per_pixel;
4572 center_screen_internal (get_preferred_edit_position(), page);
4575 /** Caller must begin and commit a reversible command */
4577 Editor::clear_playlist (boost::shared_ptr<Playlist> playlist)
4579 playlist->clear_changes ();
4581 _session->add_command (new StatefulDiffCommand (playlist));
4585 Editor::nudge_track (bool use_edit, bool forwards)
4587 boost::shared_ptr<Playlist> playlist;
4588 framepos_t distance;
4589 framepos_t next_distance;
4593 start = get_preferred_edit_position();
4598 if ((distance = get_nudge_distance (start, next_distance)) == 0) {
4602 if (selection->tracks.empty()) {
4606 begin_reversible_command (_("nudge track"));
4608 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4610 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4612 if ((playlist = (*i)->playlist()) == 0) {
4616 playlist->clear_changes ();
4617 playlist->clear_owned_changes ();
4619 playlist->nudge_after (start, distance, forwards);
4621 vector<Command*> cmds;
4623 playlist->rdiff (cmds);
4624 _session->add_commands (cmds);
4626 _session->add_command (new StatefulDiffCommand (playlist));
4629 commit_reversible_command ();
4633 Editor::remove_last_capture ()
4635 vector<string> choices;
4642 if (Config->get_verify_remove_last_capture()) {
4643 prompt = _("Do you really want to destroy the last capture?"
4644 "\n(This is destructive and cannot be undone)");
4646 choices.push_back (_("No, do nothing."));
4647 choices.push_back (_("Yes, destroy it."));
4649 Gtkmm2ext::Choice prompter (_("Destroy last capture"), prompt, choices);
4651 if (prompter.run () == 1) {
4652 _session->remove_last_capture ();
4653 _regions->redisplay ();
4657 _session->remove_last_capture();
4658 _regions->redisplay ();
4663 Editor::normalize_region ()
4669 RegionSelection rs = get_regions_from_selection_and_entered ();
4675 NormalizeDialog dialog (rs.size() > 1);
4677 if (dialog.run () == RESPONSE_CANCEL) {
4681 set_canvas_cursor (_cursors->wait);
4684 /* XXX: should really only count audio regions here */
4685 int const regions = rs.size ();
4687 /* Make a list of the selected audio regions' maximum amplitudes, and also
4688 obtain the maximum amplitude of them all.
4690 list<double> max_amps;
4692 for (RegionSelection::const_iterator i = rs.begin(); i != rs.end(); ++i) {
4693 AudioRegionView const * arv = dynamic_cast<AudioRegionView const *> (*i);
4695 dialog.descend (1.0 / regions);
4696 double const a = arv->audio_region()->maximum_amplitude (&dialog);
4699 /* the user cancelled the operation */
4700 set_canvas_cursor (current_canvas_cursor);
4704 max_amps.push_back (a);
4705 max_amp = max (max_amp, a);
4710 begin_reversible_command (_("normalize"));
4712 list<double>::const_iterator a = max_amps.begin ();
4714 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
4715 AudioRegionView* const arv = dynamic_cast<AudioRegionView*> (*r);
4720 arv->region()->clear_changes ();
4722 double const amp = dialog.normalize_individually() ? *a : max_amp;
4724 arv->audio_region()->normalize (amp, dialog.target ());
4725 _session->add_command (new StatefulDiffCommand (arv->region()));
4730 commit_reversible_command ();
4731 set_canvas_cursor (current_canvas_cursor);
4736 Editor::reset_region_scale_amplitude ()
4742 RegionSelection rs = get_regions_from_selection_and_entered ();
4748 begin_reversible_command ("reset gain");
4750 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
4751 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
4754 arv->region()->clear_changes ();
4755 arv->audio_region()->set_scale_amplitude (1.0f);
4756 _session->add_command (new StatefulDiffCommand (arv->region()));
4759 commit_reversible_command ();
4763 Editor::adjust_region_gain (bool up)
4765 RegionSelection rs = get_regions_from_selection_and_entered ();
4767 if (!_session || rs.empty()) {
4771 begin_reversible_command ("adjust region gain");
4773 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
4774 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
4779 arv->region()->clear_changes ();
4781 double dB = accurate_coefficient_to_dB (arv->audio_region()->scale_amplitude ());
4789 arv->audio_region()->set_scale_amplitude (dB_to_coefficient (dB));
4790 _session->add_command (new StatefulDiffCommand (arv->region()));
4793 commit_reversible_command ();
4798 Editor::reverse_region ()
4804 Reverse rev (*_session);
4805 apply_filter (rev, _("reverse regions"));
4809 Editor::strip_region_silence ()
4815 RegionSelection rs = get_regions_from_selection_and_entered ();
4821 std::list<RegionView*> audio_only;
4823 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
4824 AudioRegionView* const arv = dynamic_cast<AudioRegionView*> (*i);
4826 audio_only.push_back (arv);
4830 StripSilenceDialog d (_session, audio_only);
4831 int const r = d.run ();
4835 if (r == Gtk::RESPONSE_OK) {
4836 ARDOUR::AudioIntervalMap silences;
4837 d.silences (silences);
4838 StripSilence s (*_session, silences, d.fade_length());
4839 apply_filter (s, _("strip silence"), &d);
4844 Editor::apply_midi_note_edit_op_to_region (MidiOperator& op, MidiRegionView& mrv)
4846 Evoral::Sequence<Evoral::MusicalTime>::Notes selected;
4847 mrv.selection_as_notelist (selected, true);
4849 vector<Evoral::Sequence<Evoral::MusicalTime>::Notes> v;
4850 v.push_back (selected);
4852 framepos_t pos_frames = mrv.midi_region()->position() - mrv.midi_region()->start();
4853 double pos_beats = _session->tempo_map().framewalk_to_beats(0, pos_frames);
4855 return op (mrv.midi_region()->model(), pos_beats, v);
4859 Editor::apply_midi_note_edit_op (MidiOperator& op)
4863 RegionSelection rs = get_regions_from_selection_and_entered ();
4869 begin_reversible_command (op.name ());
4871 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
4872 RegionSelection::iterator tmp = r;
4875 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*r);
4878 cmd = apply_midi_note_edit_op_to_region (op, *mrv);
4881 _session->add_command (cmd);
4888 commit_reversible_command ();
4892 Editor::fork_region ()
4894 RegionSelection rs = get_regions_from_selection_and_entered ();
4900 begin_reversible_command (_("Fork Region(s)"));
4902 set_canvas_cursor (_cursors->wait);
4905 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
4906 RegionSelection::iterator tmp = r;
4909 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*>(*r);
4913 boost::shared_ptr<Playlist> playlist = mrv->region()->playlist();
4914 boost::shared_ptr<MidiSource> new_source = _session->create_midi_source_by_stealing_name (mrv->midi_view()->track());
4915 boost::shared_ptr<MidiRegion> newregion = mrv->midi_region()->clone (new_source);
4917 playlist->clear_changes ();
4918 playlist->replace_region (mrv->region(), newregion, mrv->region()->position());
4919 _session->add_command(new StatefulDiffCommand (playlist));
4921 error << string_compose (_("Could not unlink %1"), mrv->region()->name()) << endmsg;
4928 commit_reversible_command ();
4930 set_canvas_cursor (current_canvas_cursor);
4934 Editor::quantize_region ()
4936 int selected_midi_region_cnt = 0;
4942 RegionSelection rs = get_regions_from_selection_and_entered ();
4948 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
4949 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*r);
4951 selected_midi_region_cnt++;
4955 if (selected_midi_region_cnt == 0) {
4959 QuantizeDialog* qd = new QuantizeDialog (*this);
4962 const int r = qd->run ();
4965 if (r == Gtk::RESPONSE_OK) {
4966 Quantize quant (*_session, qd->snap_start(), qd->snap_end(),
4967 qd->start_grid_size(), qd->end_grid_size(),
4968 qd->strength(), qd->swing(), qd->threshold());
4970 apply_midi_note_edit_op (quant);
4975 Editor::insert_patch_change (bool from_context)
4977 RegionSelection rs = get_regions_from_selection_and_entered ();
4983 const framepos_t p = get_preferred_edit_position (false, from_context);
4985 /* XXX: bit of a hack; use the MIDNAM from the first selected region;
4986 there may be more than one, but the PatchChangeDialog can only offer
4987 one set of patch menus.
4989 MidiRegionView* first = dynamic_cast<MidiRegionView*> (rs.front ());
4991 Evoral::PatchChange<Evoral::MusicalTime> empty (0, 0, 0, 0);
4992 PatchChangeDialog d (0, _session, empty, first->instrument_info(), Gtk::Stock::ADD);
4994 if (d.run() == RESPONSE_CANCEL) {
4998 for (RegionSelection::iterator i = rs.begin (); i != rs.end(); ++i) {
4999 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*i);
5001 if (p >= mrv->region()->first_frame() && p <= mrv->region()->last_frame()) {
5002 mrv->add_patch_change (p - mrv->region()->position(), d.patch ());
5009 Editor::apply_filter (Filter& filter, string command, ProgressReporter* progress)
5011 RegionSelection rs = get_regions_from_selection_and_entered ();
5017 begin_reversible_command (command);
5019 set_canvas_cursor (_cursors->wait);
5023 int const N = rs.size ();
5025 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
5026 RegionSelection::iterator tmp = r;
5029 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
5031 boost::shared_ptr<Playlist> playlist = arv->region()->playlist();
5034 progress->descend (1.0 / N);
5037 if (arv->audio_region()->apply (filter, progress) == 0) {
5039 playlist->clear_changes ();
5040 playlist->clear_owned_changes ();
5042 if (filter.results.empty ()) {
5044 /* no regions returned; remove the old one */
5045 playlist->remove_region (arv->region ());
5049 std::vector<boost::shared_ptr<Region> >::iterator res = filter.results.begin ();
5051 /* first region replaces the old one */
5052 playlist->replace_region (arv->region(), *res, (*res)->position());
5056 while (res != filter.results.end()) {
5057 playlist->add_region (*res, (*res)->position());
5063 /* We might have removed regions, which alters other regions' layering_index,
5064 so we need to do a recursive diff here.
5066 vector<Command*> cmds;
5067 playlist->rdiff (cmds);
5068 _session->add_commands (cmds);
5070 _session->add_command(new StatefulDiffCommand (playlist));
5076 progress->ascend ();
5084 commit_reversible_command ();
5087 set_canvas_cursor (current_canvas_cursor);
5091 Editor::external_edit_region ()
5097 Editor::reset_region_gain_envelopes ()
5099 RegionSelection rs = get_regions_from_selection_and_entered ();
5101 if (!_session || rs.empty()) {
5105 _session->begin_reversible_command (_("reset region gain"));
5107 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5108 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
5110 boost::shared_ptr<AutomationList> alist (arv->audio_region()->envelope());
5111 XMLNode& before (alist->get_state());
5113 arv->audio_region()->set_default_envelope ();
5114 _session->add_command (new MementoCommand<AutomationList>(*arv->audio_region()->envelope().get(), &before, &alist->get_state()));
5118 _session->commit_reversible_command ();
5122 Editor::set_region_gain_visibility (RegionView* rv)
5124 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (rv);
5126 arv->update_envelope_visibility();
5131 Editor::set_gain_envelope_visibility ()
5137 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5138 AudioTimeAxisView* v = dynamic_cast<AudioTimeAxisView*>(*i);
5140 v->audio_view()->foreach_regionview (sigc::mem_fun (this, &Editor::set_region_gain_visibility));
5146 Editor::toggle_gain_envelope_active ()
5148 if (_ignore_region_action) {
5152 RegionSelection rs = get_regions_from_selection_and_entered ();
5154 if (!_session || rs.empty()) {
5158 _session->begin_reversible_command (_("region gain envelope active"));
5160 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5161 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
5163 arv->region()->clear_changes ();
5164 arv->audio_region()->set_envelope_active (!arv->audio_region()->envelope_active());
5165 _session->add_command (new StatefulDiffCommand (arv->region()));
5169 _session->commit_reversible_command ();
5173 Editor::toggle_region_lock ()
5175 if (_ignore_region_action) {
5179 RegionSelection rs = get_regions_from_selection_and_entered ();
5181 if (!_session || rs.empty()) {
5185 _session->begin_reversible_command (_("toggle region lock"));
5187 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5188 (*i)->region()->clear_changes ();
5189 (*i)->region()->set_locked (!(*i)->region()->locked());
5190 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5193 _session->commit_reversible_command ();
5197 Editor::toggle_region_video_lock ()
5199 if (_ignore_region_action) {
5203 RegionSelection rs = get_regions_from_selection_and_entered ();
5205 if (!_session || rs.empty()) {
5209 _session->begin_reversible_command (_("Toggle Video Lock"));
5211 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5212 (*i)->region()->clear_changes ();
5213 (*i)->region()->set_video_locked (!(*i)->region()->video_locked());
5214 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5217 _session->commit_reversible_command ();
5221 Editor::toggle_region_lock_style ()
5223 if (_ignore_region_action) {
5227 RegionSelection rs = get_regions_from_selection_and_entered ();
5229 if (!_session || rs.empty()) {
5233 _session->begin_reversible_command (_("region lock style"));
5235 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5236 (*i)->region()->clear_changes ();
5237 PositionLockStyle const ns = (*i)->region()->position_lock_style() == AudioTime ? MusicTime : AudioTime;
5238 (*i)->region()->set_position_lock_style (ns);
5239 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5242 _session->commit_reversible_command ();
5246 Editor::toggle_opaque_region ()
5248 if (_ignore_region_action) {
5252 RegionSelection rs = get_regions_from_selection_and_entered ();
5254 if (!_session || rs.empty()) {
5258 _session->begin_reversible_command (_("change region opacity"));
5260 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5261 (*i)->region()->clear_changes ();
5262 (*i)->region()->set_opaque (!(*i)->region()->opaque());
5263 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5266 _session->commit_reversible_command ();
5270 Editor::toggle_record_enable ()
5272 bool new_state = false;
5274 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5275 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5278 if (!rtav->is_track())
5282 new_state = !rtav->track()->record_enabled();
5286 rtav->track()->set_record_enabled (new_state, this);
5291 Editor::toggle_solo ()
5293 bool new_state = false;
5295 boost::shared_ptr<RouteList> rl (new RouteList);
5297 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5298 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5305 new_state = !rtav->route()->soloed ();
5309 rl->push_back (rtav->route());
5312 _session->set_solo (rl, new_state, Session::rt_cleanup, true);
5316 Editor::toggle_mute ()
5318 bool new_state = false;
5320 boost::shared_ptr<RouteList> rl (new RouteList);
5322 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5323 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5330 new_state = !rtav->route()->muted();
5334 rl->push_back (rtav->route());
5337 _session->set_mute (rl, new_state, Session::rt_cleanup, true);
5341 Editor::toggle_solo_isolate ()
5347 Editor::fade_range ()
5349 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
5351 begin_reversible_command (_("fade range"));
5353 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
5354 (*i)->fade_range (selection->time);
5357 commit_reversible_command ();
5362 Editor::set_fade_length (bool in)
5364 RegionSelection rs = get_regions_from_selection_and_entered ();
5370 /* we need a region to measure the offset from the start */
5372 RegionView* rv = rs.front ();
5374 framepos_t pos = get_preferred_edit_position();
5378 if (pos > rv->region()->last_frame() || pos < rv->region()->first_frame()) {
5379 /* edit point is outside the relevant region */
5384 if (pos <= rv->region()->position()) {
5388 len = pos - rv->region()->position();
5389 cmd = _("set fade in length");
5391 if (pos >= rv->region()->last_frame()) {
5395 len = rv->region()->last_frame() - pos;
5396 cmd = _("set fade out length");
5399 begin_reversible_command (cmd);
5401 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5402 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5408 boost::shared_ptr<AutomationList> alist;
5410 alist = tmp->audio_region()->fade_in();
5412 alist = tmp->audio_region()->fade_out();
5415 XMLNode &before = alist->get_state();
5418 tmp->audio_region()->set_fade_in_length (len);
5419 tmp->audio_region()->set_fade_in_active (true);
5421 tmp->audio_region()->set_fade_out_length (len);
5422 tmp->audio_region()->set_fade_out_active (true);
5425 XMLNode &after = alist->get_state();
5426 _session->add_command(new MementoCommand<AutomationList>(*alist, &before, &after));
5429 commit_reversible_command ();
5433 Editor::set_fade_in_shape (FadeShape shape)
5435 RegionSelection rs = get_regions_from_selection_and_entered ();
5441 begin_reversible_command (_("set fade in shape"));
5443 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5444 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5450 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_in();
5451 XMLNode &before = alist->get_state();
5453 tmp->audio_region()->set_fade_in_shape (shape);
5455 XMLNode &after = alist->get_state();
5456 _session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
5459 commit_reversible_command ();
5464 Editor::set_fade_out_shape (FadeShape shape)
5466 RegionSelection rs = get_regions_from_selection_and_entered ();
5472 begin_reversible_command (_("set fade out shape"));
5474 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5475 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5481 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_out();
5482 XMLNode &before = alist->get_state();
5484 tmp->audio_region()->set_fade_out_shape (shape);
5486 XMLNode &after = alist->get_state();
5487 _session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
5490 commit_reversible_command ();
5494 Editor::set_fade_in_active (bool yn)
5496 RegionSelection rs = get_regions_from_selection_and_entered ();
5502 begin_reversible_command (_("set fade in active"));
5504 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5505 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5512 boost::shared_ptr<AudioRegion> ar (tmp->audio_region());
5514 ar->clear_changes ();
5515 ar->set_fade_in_active (yn);
5516 _session->add_command (new StatefulDiffCommand (ar));
5519 commit_reversible_command ();
5523 Editor::set_fade_out_active (bool yn)
5525 RegionSelection rs = get_regions_from_selection_and_entered ();
5531 begin_reversible_command (_("set fade out active"));
5533 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5534 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5540 boost::shared_ptr<AudioRegion> ar (tmp->audio_region());
5542 ar->clear_changes ();
5543 ar->set_fade_out_active (yn);
5544 _session->add_command(new StatefulDiffCommand (ar));
5547 commit_reversible_command ();
5551 Editor::toggle_region_fades (int dir)
5553 if (_ignore_region_action) {
5557 boost::shared_ptr<AudioRegion> ar;
5560 RegionSelection rs = get_regions_from_selection_and_entered ();
5566 RegionSelection::iterator i;
5567 for (i = rs.begin(); i != rs.end(); ++i) {
5568 if ((ar = boost::dynamic_pointer_cast<AudioRegion>((*i)->region())) != 0) {
5570 yn = ar->fade_out_active ();
5572 yn = ar->fade_in_active ();
5578 if (i == rs.end()) {
5582 /* XXX should this undo-able? */
5584 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5585 if ((ar = boost::dynamic_pointer_cast<AudioRegion>((*i)->region())) == 0) {
5588 if (dir == 1 || dir == 0) {
5589 ar->set_fade_in_active (!yn);
5592 if (dir == -1 || dir == 0) {
5593 ar->set_fade_out_active (!yn);
5599 /** Update region fade visibility after its configuration has been changed */
5601 Editor::update_region_fade_visibility ()
5603 bool _fade_visibility = _session->config.get_show_region_fades ();
5605 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5606 AudioTimeAxisView* v = dynamic_cast<AudioTimeAxisView*>(*i);
5608 if (_fade_visibility) {
5609 v->audio_view()->show_all_fades ();
5611 v->audio_view()->hide_all_fades ();
5618 Editor::set_edit_point ()
5623 if (!mouse_frame (where, ignored)) {
5629 if (selection->markers.empty()) {
5631 mouse_add_new_marker (where);
5636 Location* loc = find_location_from_marker (selection->markers.front(), ignored);
5639 loc->move_to (where);
5645 Editor::set_playhead_cursor ()
5647 if (entered_marker) {
5648 _session->request_locate (entered_marker->position(), _session->transport_rolling());
5653 if (!mouse_frame (where, ignored)) {
5660 _session->request_locate (where, _session->transport_rolling());
5664 if ( Config->get_follow_edits() )
5665 cancel_time_selection();
5669 Editor::split_region ()
5671 if ( !selection->time.empty()) {
5672 separate_regions_between (selection->time);
5676 RegionSelection rs = get_regions_from_selection_and_edit_point ();
5678 framepos_t where = get_preferred_edit_position ();
5684 split_regions_at (where, rs);
5687 struct EditorOrderRouteSorter {
5688 bool operator() (boost::shared_ptr<Route> a, boost::shared_ptr<Route> b) {
5689 return a->order_key () < b->order_key ();
5694 Editor::select_next_route()
5696 if (selection->tracks.empty()) {
5697 selection->set (track_views.front());
5701 TimeAxisView* current = selection->tracks.front();
5705 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5706 if (*i == current) {
5708 if (i != track_views.end()) {
5711 current = (*(track_views.begin()));
5712 //selection->set (*(track_views.begin()));
5717 rui = dynamic_cast<RouteUI *>(current);
5718 } while ( current->hidden() || (rui != NULL && !rui->route()->active()));
5720 selection->set(current);
5722 ensure_time_axis_view_is_visible (*current, false);
5726 Editor::select_prev_route()
5728 if (selection->tracks.empty()) {
5729 selection->set (track_views.front());
5733 TimeAxisView* current = selection->tracks.front();
5737 for (TrackViewList::reverse_iterator i = track_views.rbegin(); i != track_views.rend(); ++i) {
5738 if (*i == current) {
5740 if (i != track_views.rend()) {
5743 current = *(track_views.rbegin());
5748 rui = dynamic_cast<RouteUI *>(current);
5749 } while ( current->hidden() || (rui != NULL && !rui->route()->active()));
5751 selection->set (current);
5753 ensure_time_axis_view_is_visible (*current, false);
5757 Editor::set_loop_from_selection (bool play)
5759 if (_session == 0 || selection->time.empty()) {
5763 framepos_t start = selection->time[clicked_selection].start;
5764 framepos_t end = selection->time[clicked_selection].end;
5766 set_loop_range (start, end, _("set loop range from selection"));
5769 _session->request_locate (start, true);
5770 _session->request_play_loop (true);
5775 Editor::set_loop_from_edit_range (bool play)
5777 if (_session == 0) {
5784 if (!get_edit_op_range (start, end)) {
5788 set_loop_range (start, end, _("set loop range from edit range"));
5791 _session->request_locate (start, true);
5792 _session->request_play_loop (true);
5797 Editor::set_loop_from_region (bool play)
5799 framepos_t start = max_framepos;
5802 RegionSelection rs = get_regions_from_selection_and_entered ();
5808 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5809 if ((*i)->region()->position() < start) {
5810 start = (*i)->region()->position();
5812 if ((*i)->region()->last_frame() + 1 > end) {
5813 end = (*i)->region()->last_frame() + 1;
5817 set_loop_range (start, end, _("set loop range from region"));
5820 _session->request_locate (start, true);
5821 _session->request_play_loop (true);
5826 Editor::set_punch_from_selection ()
5828 if (_session == 0 || selection->time.empty()) {
5832 framepos_t start = selection->time[clicked_selection].start;
5833 framepos_t end = selection->time[clicked_selection].end;
5835 set_punch_range (start, end, _("set punch range from selection"));
5839 Editor::set_punch_from_edit_range ()
5841 if (_session == 0) {
5848 if (!get_edit_op_range (start, end)) {
5852 set_punch_range (start, end, _("set punch range from edit range"));
5856 Editor::set_punch_from_region ()
5858 framepos_t start = max_framepos;
5861 RegionSelection rs = get_regions_from_selection_and_entered ();
5867 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5868 if ((*i)->region()->position() < start) {
5869 start = (*i)->region()->position();
5871 if ((*i)->region()->last_frame() + 1 > end) {
5872 end = (*i)->region()->last_frame() + 1;
5876 set_punch_range (start, end, _("set punch range from region"));
5880 Editor::pitch_shift_region ()
5882 RegionSelection rs = get_regions_from_selection_and_entered ();
5884 RegionSelection audio_rs;
5885 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5886 if (dynamic_cast<AudioRegionView*> (*i)) {
5887 audio_rs.push_back (*i);
5891 if (audio_rs.empty()) {
5895 pitch_shift (audio_rs, 1.2);
5899 Editor::transpose_region ()
5901 RegionSelection rs = get_regions_from_selection_and_entered ();
5903 list<MidiRegionView*> midi_region_views;
5904 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5905 MidiRegionView* mrv = dynamic_cast<MidiRegionView*> (*i);
5907 midi_region_views.push_back (mrv);
5912 int const r = d.run ();
5913 if (r != RESPONSE_ACCEPT) {
5917 for (list<MidiRegionView*>::iterator i = midi_region_views.begin(); i != midi_region_views.end(); ++i) {
5918 (*i)->midi_region()->transpose (d.semitones ());
5923 Editor::set_tempo_from_region ()
5925 RegionSelection rs = get_regions_from_selection_and_entered ();
5927 if (!_session || rs.empty()) {
5931 RegionView* rv = rs.front();
5933 define_one_bar (rv->region()->position(), rv->region()->last_frame() + 1);
5937 Editor::use_range_as_bar ()
5939 framepos_t start, end;
5940 if (get_edit_op_range (start, end)) {
5941 define_one_bar (start, end);
5946 Editor::define_one_bar (framepos_t start, framepos_t end)
5948 framepos_t length = end - start;
5950 const Meter& m (_session->tempo_map().meter_at (start));
5952 /* length = 1 bar */
5954 /* now we want frames per beat.
5955 we have frames per bar, and beats per bar, so ...
5958 /* XXXX METER MATH */
5960 double frames_per_beat = length / m.divisions_per_bar();
5962 /* beats per minute = */
5964 double beats_per_minute = (_session->frame_rate() * 60.0) / frames_per_beat;
5966 /* now decide whether to:
5968 (a) set global tempo
5969 (b) add a new tempo marker
5973 const TempoSection& t (_session->tempo_map().tempo_section_at (start));
5975 bool do_global = false;
5977 if ((_session->tempo_map().n_tempos() == 1) && (_session->tempo_map().n_meters() == 1)) {
5979 /* only 1 tempo & 1 meter: ask if the user wants to set the tempo
5980 at the start, or create a new marker
5983 vector<string> options;
5984 options.push_back (_("Cancel"));
5985 options.push_back (_("Add new marker"));
5986 options.push_back (_("Set global tempo"));
5989 _("Define one bar"),
5990 _("Do you want to set the global tempo or add a new tempo marker?"),
5994 c.set_default_response (2);
6010 /* more than 1 tempo and/or meter section already, go ahead do the "usual":
6011 if the marker is at the region starter, change it, otherwise add
6016 begin_reversible_command (_("set tempo from region"));
6017 XMLNode& before (_session->tempo_map().get_state());
6020 _session->tempo_map().change_initial_tempo (beats_per_minute, t.note_type());
6021 } else if (t.frame() == start) {
6022 _session->tempo_map().change_existing_tempo_at (start, beats_per_minute, t.note_type());
6024 Timecode::BBT_Time bbt;
6025 _session->tempo_map().bbt_time (start, bbt);
6026 _session->tempo_map().add_tempo (Tempo (beats_per_minute, t.note_type()), bbt);
6029 XMLNode& after (_session->tempo_map().get_state());
6031 _session->add_command (new MementoCommand<TempoMap>(_session->tempo_map(), &before, &after));
6032 commit_reversible_command ();
6036 Editor::split_region_at_transients ()
6038 AnalysisFeatureList positions;
6040 RegionSelection rs = get_regions_from_selection_and_entered ();
6042 if (!_session || rs.empty()) {
6046 _session->begin_reversible_command (_("split regions"));
6048 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ) {
6050 RegionSelection::iterator tmp;
6055 boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion> ((*i)->region());
6057 if (ar && (ar->get_transients (positions) == 0)) {
6058 split_region_at_points ((*i)->region(), positions, true);
6065 _session->commit_reversible_command ();
6070 Editor::split_region_at_points (boost::shared_ptr<Region> r, AnalysisFeatureList& positions, bool can_ferret, bool select_new)
6072 bool use_rhythmic_rodent = false;
6074 boost::shared_ptr<Playlist> pl = r->playlist();
6076 list<boost::shared_ptr<Region> > new_regions;
6082 if (positions.empty()) {
6087 if (positions.size() > 20 && can_ferret) {
6088 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);
6089 MessageDialog msg (msgstr,
6092 Gtk::BUTTONS_OK_CANCEL);
6095 msg.add_button (_("Call for the Ferret!"), RESPONSE_APPLY);
6096 msg.set_secondary_text (_("Press OK to continue with this split operation\nor ask the Ferret dialog to tune the analysis"));
6098 msg.set_secondary_text (_("Press OK to continue with this split operation"));
6101 msg.set_title (_("Excessive split?"));
6104 int response = msg.run();
6110 case RESPONSE_APPLY:
6111 use_rhythmic_rodent = true;
6118 if (use_rhythmic_rodent) {
6119 show_rhythm_ferret ();
6123 AnalysisFeatureList::const_iterator x;
6125 pl->clear_changes ();
6126 pl->clear_owned_changes ();
6128 x = positions.begin();
6130 if (x == positions.end()) {
6135 pl->remove_region (r);
6139 while (x != positions.end()) {
6141 /* deal with positons that are out of scope of present region bounds */
6142 if (*x <= 0 || *x > r->length()) {
6147 /* file start = original start + how far we from the initial position ?
6150 framepos_t file_start = r->start() + pos;
6152 /* length = next position - current position
6155 framepos_t len = (*x) - pos;
6157 /* XXX we do we really want to allow even single-sample regions?
6158 shouldn't we have some kind of lower limit on region size?
6167 if (RegionFactory::region_name (new_name, r->name())) {
6171 /* do NOT announce new regions 1 by one, just wait till they are all done */
6175 plist.add (ARDOUR::Properties::start, file_start);
6176 plist.add (ARDOUR::Properties::length, len);
6177 plist.add (ARDOUR::Properties::name, new_name);
6178 plist.add (ARDOUR::Properties::layer, 0);
6180 boost::shared_ptr<Region> nr = RegionFactory::create (r->sources(), plist, false);
6181 /* because we set annouce to false, manually add the new region to the
6184 RegionFactory::map_add (nr);
6186 pl->add_region (nr, r->position() + pos);
6189 new_regions.push_front(nr);
6198 RegionFactory::region_name (new_name, r->name());
6200 /* Add the final region */
6203 plist.add (ARDOUR::Properties::start, r->start() + pos);
6204 plist.add (ARDOUR::Properties::length, r->last_frame() - (r->position() + pos) + 1);
6205 plist.add (ARDOUR::Properties::name, new_name);
6206 plist.add (ARDOUR::Properties::layer, 0);
6208 boost::shared_ptr<Region> nr = RegionFactory::create (r->sources(), plist, false);
6209 /* because we set annouce to false, manually add the new region to the
6212 RegionFactory::map_add (nr);
6213 pl->add_region (nr, r->position() + pos);
6216 new_regions.push_front(nr);
6221 /* We might have removed regions, which alters other regions' layering_index,
6222 so we need to do a recursive diff here.
6224 vector<Command*> cmds;
6226 _session->add_commands (cmds);
6228 _session->add_command (new StatefulDiffCommand (pl));
6232 for (list<boost::shared_ptr<Region> >::iterator i = new_regions.begin(); i != new_regions.end(); ++i){
6233 set_selected_regionview_from_region_list ((*i), Selection::Add);
6239 Editor::place_transient()
6245 RegionSelection rs = get_regions_from_selection_and_edit_point ();
6251 framepos_t where = get_preferred_edit_position();
6253 _session->begin_reversible_command (_("place transient"));
6255 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6256 framepos_t position = (*r)->region()->position();
6257 (*r)->region()->add_transient(where - position);
6260 _session->commit_reversible_command ();
6264 Editor::remove_transient(ArdourCanvas::Item* item)
6270 ArdourCanvas::Line* _line = reinterpret_cast<ArdourCanvas::Line*> (item);
6273 AudioRegionView* _arv = reinterpret_cast<AudioRegionView*> (item->get_data ("regionview"));
6274 _arv->remove_transient (*(float*) _line->get_data ("position"));
6278 Editor::snap_regions_to_grid ()
6280 list <boost::shared_ptr<Playlist > > used_playlists;
6282 RegionSelection rs = get_regions_from_selection_and_entered ();
6284 if (!_session || rs.empty()) {
6288 _session->begin_reversible_command (_("snap regions to grid"));
6290 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6292 boost::shared_ptr<Playlist> pl = (*r)->region()->playlist();
6294 if (!pl->frozen()) {
6295 /* we haven't seen this playlist before */
6297 /* remember used playlists so we can thaw them later */
6298 used_playlists.push_back(pl);
6302 framepos_t start_frame = (*r)->region()->first_frame ();
6303 snap_to (start_frame);
6304 (*r)->region()->set_position (start_frame);
6307 while (used_playlists.size() > 0) {
6308 list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
6310 used_playlists.pop_front();
6313 _session->commit_reversible_command ();
6317 Editor::close_region_gaps ()
6319 list <boost::shared_ptr<Playlist > > used_playlists;
6321 RegionSelection rs = get_regions_from_selection_and_entered ();
6323 if (!_session || rs.empty()) {
6327 Dialog dialog (_("Close Region Gaps"));
6330 table.set_spacings (12);
6331 table.set_border_width (12);
6332 Label* l = manage (left_aligned_label (_("Crossfade length")));
6333 table.attach (*l, 0, 1, 0, 1);
6335 SpinButton spin_crossfade (1, 0);
6336 spin_crossfade.set_range (0, 15);
6337 spin_crossfade.set_increments (1, 1);
6338 spin_crossfade.set_value (5);
6339 table.attach (spin_crossfade, 1, 2, 0, 1);
6341 table.attach (*manage (new Label (_("ms"))), 2, 3, 0, 1);
6343 l = manage (left_aligned_label (_("Pull-back length")));
6344 table.attach (*l, 0, 1, 1, 2);
6346 SpinButton spin_pullback (1, 0);
6347 spin_pullback.set_range (0, 100);
6348 spin_pullback.set_increments (1, 1);
6349 spin_pullback.set_value(30);
6350 table.attach (spin_pullback, 1, 2, 1, 2);
6352 table.attach (*manage (new Label (_("ms"))), 2, 3, 1, 2);
6354 dialog.get_vbox()->pack_start (table);
6355 dialog.add_button (Stock::CANCEL, RESPONSE_CANCEL);
6356 dialog.add_button (_("Ok"), RESPONSE_ACCEPT);
6359 if (dialog.run () == RESPONSE_CANCEL) {
6363 framepos_t crossfade_len = spin_crossfade.get_value();
6364 framepos_t pull_back_frames = spin_pullback.get_value();
6366 crossfade_len = lrintf (crossfade_len * _session->frame_rate()/1000);
6367 pull_back_frames = lrintf (pull_back_frames * _session->frame_rate()/1000);
6369 /* Iterate over the region list and make adjacent regions overlap by crossfade_len_ms */
6371 _session->begin_reversible_command (_("close region gaps"));
6374 boost::shared_ptr<Region> last_region;
6376 rs.sort_by_position_and_track();
6378 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6380 boost::shared_ptr<Playlist> pl = (*r)->region()->playlist();
6382 if (!pl->frozen()) {
6383 /* we haven't seen this playlist before */
6385 /* remember used playlists so we can thaw them later */
6386 used_playlists.push_back(pl);
6390 framepos_t position = (*r)->region()->position();
6392 if (idx == 0 || position < last_region->position()){
6393 last_region = (*r)->region();
6398 (*r)->region()->trim_front( (position - pull_back_frames));
6399 last_region->trim_end( (position - pull_back_frames + crossfade_len));
6401 last_region = (*r)->region();
6406 while (used_playlists.size() > 0) {
6407 list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
6409 used_playlists.pop_front();
6412 _session->commit_reversible_command ();
6416 Editor::tab_to_transient (bool forward)
6418 AnalysisFeatureList positions;
6420 RegionSelection rs = get_regions_from_selection_and_entered ();
6426 framepos_t pos = _session->audible_frame ();
6428 if (!selection->tracks.empty()) {
6430 /* don't waste time searching for transients in duplicate playlists.
6433 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
6435 for (TrackViewList::iterator t = ts.begin(); t != ts.end(); ++t) {
6437 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*t);
6440 boost::shared_ptr<Track> tr = rtv->track();
6442 boost::shared_ptr<Playlist> pl = tr->playlist ();
6444 framepos_t result = pl->find_next_transient (pos, forward ? 1 : -1);
6447 positions.push_back (result);
6460 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6461 (*r)->region()->get_transients (positions);
6465 TransientDetector::cleanup_transients (positions, _session->frame_rate(), 3.0);
6468 AnalysisFeatureList::iterator x;
6470 for (x = positions.begin(); x != positions.end(); ++x) {
6476 if (x != positions.end ()) {
6477 _session->request_locate (*x);
6481 AnalysisFeatureList::reverse_iterator x;
6483 for (x = positions.rbegin(); x != positions.rend(); ++x) {
6489 if (x != positions.rend ()) {
6490 _session->request_locate (*x);
6496 Editor::playhead_forward_to_grid ()
6502 framepos_t pos = playhead_cursor->current_frame ();
6503 if (pos < max_framepos - 1) {
6505 snap_to_internal (pos, RoundUpAlways, false);
6506 _session->request_locate (pos);
6512 Editor::playhead_backward_to_grid ()
6518 framepos_t pos = playhead_cursor->current_frame ();
6521 snap_to_internal (pos, RoundDownAlways, false);
6522 _session->request_locate (pos);
6527 Editor::set_track_height (Height h)
6529 TrackSelection& ts (selection->tracks);
6531 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
6532 (*x)->set_height_enum (h);
6537 Editor::toggle_tracks_active ()
6539 TrackSelection& ts (selection->tracks);
6541 bool target = false;
6547 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
6548 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*x);
6552 target = !rtv->_route->active();
6555 rtv->_route->set_active (target, this);
6561 Editor::remove_tracks ()
6563 TrackSelection& ts (selection->tracks);
6569 vector<string> choices;
6573 const char* trackstr;
6575 vector<boost::shared_ptr<Route> > routes;
6576 bool special_bus = false;
6578 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
6579 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*x);
6583 if (rtv->is_track()) {
6588 routes.push_back (rtv->_route);
6590 if (rtv->route()->is_master() || rtv->route()->is_monitor()) {
6595 if (special_bus && !Config->get_allow_special_bus_removal()) {
6596 MessageDialog msg (_("That would be bad news ...."),
6600 msg.set_secondary_text (string_compose (_(
6601 "Removing the master or monitor bus is such a bad idea\n\
6602 that %1 is not going to allow it.\n\
6604 If you really want to do this sort of thing\n\
6605 edit your ardour.rc file to set the\n\
6606 \"allow-special-bus-removal\" option to be \"yes\""), PROGRAM_NAME));
6613 if (ntracks + nbusses == 0) {
6617 // XXX should be using gettext plural forms, maybe?
6619 trackstr = _("tracks");
6621 trackstr = _("track");
6625 busstr = _("busses");
6632 prompt = string_compose (_("Do you really want to remove %1 %2 and %3 %4?\n"
6633 "(You may also lose the playlists associated with the %2)\n\n"
6634 "This action cannot be undone, and the session file will be overwritten!"),
6635 ntracks, trackstr, nbusses, busstr);
6637 prompt = string_compose (_("Do you really want to remove %1 %2?\n"
6638 "(You may also lose the playlists associated with the %2)\n\n"
6639 "This action cannot be undone, and the session file will be overwritten!"),
6642 } else if (nbusses) {
6643 prompt = string_compose (_("Do you really want to remove %1 %2?\n\n"
6644 "This action cannot be undone, and the session file will be overwritten"),
6648 choices.push_back (_("No, do nothing."));
6649 if (ntracks + nbusses > 1) {
6650 choices.push_back (_("Yes, remove them."));
6652 choices.push_back (_("Yes, remove it."));
6657 title = string_compose (_("Remove %1"), trackstr);
6659 title = string_compose (_("Remove %1"), busstr);
6662 Choice prompter (title, prompt, choices);
6664 if (prompter.run () != 1) {
6669 Session::StateProtector sp (_session);
6670 DisplaySuspender ds;
6671 for (vector<boost::shared_ptr<Route> >::iterator x = routes.begin(); x != routes.end(); ++x) {
6672 _session->remove_route (*x);
6678 Editor::do_insert_time ()
6680 if (selection->tracks.empty()) {
6684 InsertTimeDialog d (*this);
6685 int response = d.run ();
6687 if (response != RESPONSE_OK) {
6691 if (d.distance() == 0) {
6695 InsertTimeOption opt = d.intersected_region_action ();
6698 get_preferred_edit_position(),
6704 d.move_glued_markers(),
6705 d.move_locked_markers(),
6711 Editor::insert_time (
6712 framepos_t pos, framecnt_t frames, InsertTimeOption opt,
6713 bool all_playlists, bool ignore_music_glue, bool markers_too, bool glued_markers_too, bool locked_markers_too, bool tempo_too
6716 bool commit = false;
6718 if (Config->get_edit_mode() == Lock) {
6722 begin_reversible_command (_("insert time"));
6724 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
6726 for (TrackViewList::iterator x = ts.begin(); x != ts.end(); ++x) {
6730 /* don't operate on any playlist more than once, which could
6731 * happen if "all playlists" is enabled, but there is more
6732 * than 1 track using playlists "from" a given track.
6735 set<boost::shared_ptr<Playlist> > pl;
6737 if (all_playlists) {
6738 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*x);
6740 vector<boost::shared_ptr<Playlist> > all = _session->playlists->playlists_for_track (rtav->track ());
6741 for (vector<boost::shared_ptr<Playlist> >::iterator p = all.begin(); p != all.end(); ++p) {
6746 if ((*x)->playlist ()) {
6747 pl.insert ((*x)->playlist ());
6751 for (set<boost::shared_ptr<Playlist> >::iterator i = pl.begin(); i != pl.end(); ++i) {
6753 (*i)->clear_changes ();
6754 (*i)->clear_owned_changes ();
6756 if (opt == SplitIntersected) {
6760 (*i)->shift (pos, frames, (opt == MoveIntersected), ignore_music_glue);
6762 vector<Command*> cmds;
6764 _session->add_commands (cmds);
6766 _session->add_command (new StatefulDiffCommand (*i));
6771 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*x);
6773 rtav->route ()->shift (pos, frames);
6781 XMLNode& before (_session->locations()->get_state());
6782 Locations::LocationList copy (_session->locations()->list());
6784 for (Locations::LocationList::iterator i = copy.begin(); i != copy.end(); ++i) {
6786 Locations::LocationList::const_iterator tmp;
6788 bool const was_locked = (*i)->locked ();
6789 if (locked_markers_too) {
6793 if ((*i)->position_lock_style() == AudioTime || glued_markers_too) {
6795 if ((*i)->start() >= pos) {
6796 (*i)->set_start ((*i)->start() + frames);
6797 if (!(*i)->is_mark()) {
6798 (*i)->set_end ((*i)->end() + frames);
6811 XMLNode& after (_session->locations()->get_state());
6812 _session->add_command (new MementoCommand<Locations>(*_session->locations(), &before, &after));
6817 _session->tempo_map().insert_time (pos, frames);
6821 commit_reversible_command ();
6826 Editor::fit_selected_tracks ()
6828 if (!selection->tracks.empty()) {
6829 fit_tracks (selection->tracks);
6833 /* no selected tracks - use tracks with selected regions */
6835 if (!selection->regions.empty()) {
6836 for (RegionSelection::iterator r = selection->regions.begin(); r != selection->regions.end(); ++r) {
6837 tvl.push_back (&(*r)->get_time_axis_view ());
6843 } else if (internal_editing()) {
6844 /* no selected tracks, or regions, but in internal edit mode, so follow the mouse and use
6847 if (entered_track) {
6848 tvl.push_back (entered_track);
6857 Editor::fit_tracks (TrackViewList & tracks)
6859 if (tracks.empty()) {
6863 uint32_t child_heights = 0;
6864 int visible_tracks = 0;
6866 for (TrackSelection::iterator t = tracks.begin(); t != tracks.end(); ++t) {
6868 if (!(*t)->marked_for_display()) {
6872 child_heights += (*t)->effective_height() - (*t)->current_height();
6876 /* compute the per-track height from:
6878 total canvas visible height -
6879 height that will be taken by visible children of selected
6880 tracks - height of the ruler/hscroll area
6882 uint32_t h = (uint32_t) floor ((trackviews_height() - child_heights) / visible_tracks);
6883 double first_y_pos = DBL_MAX;
6885 if (h < TimeAxisView::preset_height (HeightSmall)) {
6886 MessageDialog msg (*this, _("There are too many tracks to fit in the current window"));
6887 /* too small to be displayed */
6891 undo_visual_stack.push_back (current_visual_state (true));
6892 no_save_visual = true;
6894 /* build a list of all tracks, including children */
6897 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
6899 TimeAxisView::Children c = (*i)->get_child_list ();
6900 for (TimeAxisView::Children::iterator j = c.begin(); j != c.end(); ++j) {
6901 all.push_back (j->get());
6905 bool prev_was_selected = false;
6906 bool is_selected = tracks.contains (all.front());
6907 bool next_is_selected;
6909 for (TrackViewList::iterator t = all.begin(); t != all.end(); ++t) {
6911 TrackViewList::iterator next;
6916 if (next != all.end()) {
6917 next_is_selected = tracks.contains (*next);
6919 next_is_selected = false;
6922 if ((*t)->marked_for_display ()) {
6924 (*t)->set_height (h);
6925 first_y_pos = std::min ((*t)->y_position (), first_y_pos);
6927 if (prev_was_selected && next_is_selected) {
6928 hide_track_in_display (*t);
6933 prev_was_selected = is_selected;
6934 is_selected = next_is_selected;
6938 set the controls_layout height now, because waiting for its size
6939 request signal handler will cause the vertical adjustment setting to fail
6942 controls_layout.property_height () = _full_canvas_height;
6943 vertical_adjustment.set_value (first_y_pos);
6945 redo_visual_stack.push_back (current_visual_state (true));
6947 visible_tracks_selector.set_text (_("Sel"));
6951 Editor::save_visual_state (uint32_t n)
6953 while (visual_states.size() <= n) {
6954 visual_states.push_back (0);
6957 if (visual_states[n] != 0) {
6958 delete visual_states[n];
6961 visual_states[n] = current_visual_state (true);
6966 Editor::goto_visual_state (uint32_t n)
6968 if (visual_states.size() <= n) {
6972 if (visual_states[n] == 0) {
6976 use_visual_state (*visual_states[n]);
6980 Editor::start_visual_state_op (uint32_t n)
6982 save_visual_state (n);
6984 PopUp* pup = new PopUp (WIN_POS_MOUSE, 1000, true);
6986 snprintf (buf, sizeof (buf), _("Saved view %u"), n+1);
6987 pup->set_text (buf);
6992 Editor::cancel_visual_state_op (uint32_t n)
6994 goto_visual_state (n);
6998 Editor::toggle_region_mute ()
7000 if (_ignore_region_action) {
7004 RegionSelection rs = get_regions_from_selection_and_entered ();
7010 if (rs.size() > 1) {
7011 begin_reversible_command (_("mute regions"));
7013 begin_reversible_command (_("mute region"));
7016 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
7018 (*i)->region()->playlist()->clear_changes ();
7019 (*i)->region()->set_muted (!(*i)->region()->muted ());
7020 _session->add_command (new StatefulDiffCommand ((*i)->region()->playlist()));
7024 commit_reversible_command ();
7028 Editor::combine_regions ()
7030 /* foreach track with selected regions, take all selected regions
7031 and join them into a new region containing the subregions (as a
7035 typedef set<RouteTimeAxisView*> RTVS;
7038 if (selection->regions.empty()) {
7042 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
7043 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(&(*i)->get_time_axis_view());
7046 tracks.insert (rtv);
7050 begin_reversible_command (_("combine regions"));
7052 vector<RegionView*> new_selection;
7054 for (RTVS::iterator i = tracks.begin(); i != tracks.end(); ++i) {
7057 if ((rv = (*i)->combine_regions ()) != 0) {
7058 new_selection.push_back (rv);
7062 selection->clear_regions ();
7063 for (vector<RegionView*>::iterator i = new_selection.begin(); i != new_selection.end(); ++i) {
7064 selection->add (*i);
7067 commit_reversible_command ();
7071 Editor::uncombine_regions ()
7073 typedef set<RouteTimeAxisView*> RTVS;
7076 if (selection->regions.empty()) {
7080 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
7081 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(&(*i)->get_time_axis_view());
7084 tracks.insert (rtv);
7088 begin_reversible_command (_("uncombine regions"));
7090 for (RTVS::iterator i = tracks.begin(); i != tracks.end(); ++i) {
7091 (*i)->uncombine_regions ();
7094 commit_reversible_command ();
7098 Editor::toggle_midi_input_active (bool flip_others)
7101 boost::shared_ptr<RouteList> rl (new RouteList);
7103 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
7104 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
7110 boost::shared_ptr<MidiTrack> mt = rtav->midi_track();
7113 rl->push_back (rtav->route());
7114 onoff = !mt->input_active();
7118 _session->set_exclusive_input_active (rl, onoff, flip_others);
7125 lock_dialog = new Gtk::Dialog (string_compose (_("%1: Locked"), PROGRAM_NAME), true);
7127 Gtk::Image* padlock = manage (new Gtk::Image (ARDOUR_UI_UTILS::get_icon ("padlock_closed")));
7128 lock_dialog->get_vbox()->pack_start (*padlock);
7130 ArdourButton* b = manage (new ArdourButton);
7131 b->set_name ("lock button");
7132 b->set_text (_("Click to unlock"));
7133 b->signal_clicked.connect (sigc::mem_fun (*this, &Editor::unlock));
7134 lock_dialog->get_vbox()->pack_start (*b);
7136 lock_dialog->get_vbox()->show_all ();
7137 lock_dialog->set_size_request (200, 200);
7141 /* The global menu bar continues to be accessible to applications
7142 with modal dialogs, which means that we need to desensitize
7143 all items in the menu bar. Since those items are really just
7144 proxies for actions, that means disabling all actions.
7146 ActionManager::disable_all_actions ();
7148 lock_dialog->present ();
7154 lock_dialog->hide ();
7157 ActionManager::pop_action_state ();
7160 if (ARDOUR_UI::config()->get_lock_gui_after_seconds()) {
7161 start_lock_event_timing ();
7166 Editor::bring_in_callback (Gtk::Label* label, uint32_t n, uint32_t total, string name)
7168 Gtkmm2ext::UI::instance()->call_slot (invalidator (*this), boost::bind (&Editor::update_bring_in_message, this, label, n, total, name));
7172 Editor::update_bring_in_message (Gtk::Label* label, uint32_t n, uint32_t total, string name)
7174 label->set_text (string_compose ("Copying %1, %2 of %3", name, n, total));
7175 Gtkmm2ext::UI::instance()->flush_pending ();
7179 Editor::bring_all_sources_into_session ()
7186 ArdourDialog w (_("Moving embedded files into session folder"));
7187 w.get_vbox()->pack_start (msg);
7190 /* flush all pending GUI events because we're about to start copying
7194 Gtkmm2ext::UI::instance()->flush_pending ();
7198 _session->bring_all_sources_into_session (boost::bind (&Editor::bring_in_callback, this, &msg, _1, _2, _3));