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/legatize.h"
54 #include "ardour/region_factory.h"
55 #include "ardour/reverse.h"
56 #include "ardour/session.h"
57 #include "ardour/session_playlists.h"
58 #include "ardour/strip_silence.h"
59 #include "ardour/transient_detector.h"
61 #include "canvas/canvas.h"
64 #include "ardour_ui.h"
65 #include "audio_region_view.h"
66 #include "audio_streamview.h"
67 #include "audio_time_axis.h"
68 #include "automation_region_view.h"
69 #include "automation_time_axis.h"
70 #include "control_point.h"
74 #include "editor_cursors.h"
75 #include "editor_drag.h"
76 #include "editor_regions.h"
77 #include "editor_routes.h"
78 #include "gui_thread.h"
79 #include "insert_time_dialog.h"
80 #include "interthread_progress_window.h"
81 #include "item_counts.h"
83 #include "midi_region_view.h"
84 #include "mixer_strip.h"
85 #include "mouse_cursors.h"
86 #include "normalize_dialog.h"
87 #include "paste_context.h"
88 #include "patch_change_dialog.h"
89 #include "quantize_dialog.h"
90 #include "region_gain_line.h"
91 #include "rgb_macros.h"
92 #include "route_time_axis.h"
93 #include "selection.h"
94 #include "selection_templates.h"
95 #include "streamview.h"
96 #include "strip_silence_dialog.h"
97 #include "time_axis_view.h"
98 #include "transpose_dialog.h"
103 using namespace ARDOUR;
106 using namespace Gtkmm2ext;
107 using namespace Editing;
108 using Gtkmm2ext::Keyboard;
110 /***********************************************************************
112 ***********************************************************************/
115 Editor::undo (uint32_t n)
117 if (_drags->active ()) {
127 Editor::redo (uint32_t n)
129 if (_drags->active ()) {
139 Editor::split_regions_at (framepos_t where, RegionSelection& regions)
143 RegionSelection pre_selected_regions = selection->regions;
144 bool working_on_selection = !pre_selected_regions.empty();
146 list<boost::shared_ptr<Playlist> > used_playlists;
147 list<RouteTimeAxisView*> used_trackviews;
149 if (regions.empty()) {
153 begin_reversible_command (_("split"));
155 // if splitting a single region, and snap-to is using
156 // region boundaries, don't pay attention to them
158 if (regions.size() == 1) {
159 switch (_snap_type) {
160 case SnapToRegionStart:
161 case SnapToRegionSync:
162 case SnapToRegionEnd:
171 EditorFreeze(); /* Emit Signal */
174 for (RegionSelection::iterator a = regions.begin(); a != regions.end(); ) {
176 RegionSelection::iterator tmp;
178 /* XXX this test needs to be more complicated, to make sure we really
179 have something to split.
182 if (!(*a)->region()->covers (where)) {
190 boost::shared_ptr<Playlist> pl = (*a)->region()->playlist();
198 /* we haven't seen this playlist before */
200 /* remember used playlists so we can thaw them later */
201 used_playlists.push_back(pl);
203 TimeAxisView& tv = (*a)->get_time_axis_view();
204 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (&tv);
206 used_trackviews.push_back (rtv);
213 pl->clear_changes ();
214 pl->split_region ((*a)->region(), where);
215 _session->add_command (new StatefulDiffCommand (pl));
221 vector<sigc::connection> region_added_connections;
223 for (list<RouteTimeAxisView*>::iterator i = used_trackviews.begin(); i != used_trackviews.end(); ++i) {
224 region_added_connections.push_back ((*i)->view()->RegionViewAdded.connect (sigc::mem_fun(*this, &Editor::collect_new_region_view)));
227 latest_regionviews.clear ();
229 while (used_playlists.size() > 0) {
230 list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
232 used_playlists.pop_front();
235 for (vector<sigc::connection>::iterator c = region_added_connections.begin(); c != region_added_connections.end(); ++c) {
239 commit_reversible_command ();
242 EditorThaw(); /* Emit Signal */
245 if (ARDOUR::Profile->get_mixbus()) {
246 //IFF we were working on selected regions, try to reinstate the other region selections that existed before the freeze/thaw.
247 _ignore_follow_edits = true; //a split will change the region selection in mysterious ways; its not practical or wanted to follow this edit
248 if( working_on_selection ) {
249 selection->add ( pre_selected_regions );
250 selection->add (latest_regionviews); //these are the new regions created after the split
252 _ignore_follow_edits = false;
256 /** Move one extreme of the current range selection. If more than one range is selected,
257 * the start of the earliest range or the end of the latest range is moved.
259 * @param move_end true to move the end of the current range selection, false to move
261 * @param next true to move the extreme to the next region boundary, false to move to
265 Editor::move_range_selection_start_or_end_to_region_boundary (bool move_end, bool next)
267 if (selection->time.start() == selection->time.end_frame()) {
271 framepos_t start = selection->time.start ();
272 framepos_t end = selection->time.end_frame ();
274 /* the position of the thing we may move */
275 framepos_t pos = move_end ? end : start;
276 int dir = next ? 1 : -1;
278 /* so we don't find the current region again */
279 if (dir > 0 || pos > 0) {
283 framepos_t const target = get_region_boundary (pos, dir, true, false);
298 begin_reversible_command (_("alter selection"));
299 selection->set_preserving_all_ranges (start, end);
300 commit_reversible_command ();
304 Editor::nudge_forward_release (GdkEventButton* ev)
306 if (ev->state & Keyboard::PrimaryModifier) {
307 nudge_forward (false, true);
309 nudge_forward (false, false);
315 Editor::nudge_backward_release (GdkEventButton* ev)
317 if (ev->state & Keyboard::PrimaryModifier) {
318 nudge_backward (false, true);
320 nudge_backward (false, false);
327 Editor::nudge_forward (bool next, bool force_playhead)
330 framepos_t next_distance;
336 RegionSelection rs = get_regions_from_selection_and_entered ();
338 if (!force_playhead && !rs.empty()) {
340 begin_reversible_command (_("nudge regions forward"));
342 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
343 boost::shared_ptr<Region> r ((*i)->region());
345 distance = get_nudge_distance (r->position(), next_distance);
348 distance = next_distance;
352 r->set_position (r->position() + distance);
353 _session->add_command (new StatefulDiffCommand (r));
356 commit_reversible_command ();
359 } else if (!force_playhead && !selection->markers.empty()) {
363 begin_reversible_command (_("nudge location forward"));
365 for (MarkerSelection::iterator i = selection->markers.begin(); i != selection->markers.end(); ++i) {
367 Location* loc = find_location_from_marker ((*i), is_start);
371 XMLNode& before (loc->get_state());
374 distance = get_nudge_distance (loc->start(), next_distance);
376 distance = next_distance;
378 if (max_framepos - distance > loc->start() + loc->length()) {
379 loc->set_start (loc->start() + distance);
381 loc->set_start (max_framepos - loc->length());
384 distance = get_nudge_distance (loc->end(), next_distance);
386 distance = next_distance;
388 if (max_framepos - distance > loc->end()) {
389 loc->set_end (loc->end() + distance);
391 loc->set_end (max_framepos);
394 XMLNode& after (loc->get_state());
395 _session->add_command (new MementoCommand<Location>(*loc, &before, &after));
399 commit_reversible_command ();
402 distance = get_nudge_distance (playhead_cursor->current_frame (), next_distance);
403 _session->request_locate (playhead_cursor->current_frame () + distance);
408 Editor::nudge_backward (bool next, bool force_playhead)
411 framepos_t next_distance;
417 RegionSelection rs = get_regions_from_selection_and_entered ();
419 if (!force_playhead && !rs.empty()) {
421 begin_reversible_command (_("nudge regions backward"));
423 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
424 boost::shared_ptr<Region> r ((*i)->region());
426 distance = get_nudge_distance (r->position(), next_distance);
429 distance = next_distance;
434 if (r->position() > distance) {
435 r->set_position (r->position() - distance);
439 _session->add_command (new StatefulDiffCommand (r));
442 commit_reversible_command ();
444 } else if (!force_playhead && !selection->markers.empty()) {
448 begin_reversible_command (_("nudge location forward"));
450 for (MarkerSelection::iterator i = selection->markers.begin(); i != selection->markers.end(); ++i) {
452 Location* loc = find_location_from_marker ((*i), is_start);
456 XMLNode& before (loc->get_state());
459 distance = get_nudge_distance (loc->start(), next_distance);
461 distance = next_distance;
463 if (distance < loc->start()) {
464 loc->set_start (loc->start() - distance);
469 distance = get_nudge_distance (loc->end(), next_distance);
472 distance = next_distance;
475 if (distance < loc->end() - loc->length()) {
476 loc->set_end (loc->end() - distance);
478 loc->set_end (loc->length());
482 XMLNode& after (loc->get_state());
483 _session->add_command (new MementoCommand<Location>(*loc, &before, &after));
487 commit_reversible_command ();
491 distance = get_nudge_distance (playhead_cursor->current_frame (), next_distance);
493 if (playhead_cursor->current_frame () > distance) {
494 _session->request_locate (playhead_cursor->current_frame () - distance);
496 _session->goto_start();
502 Editor::nudge_forward_capture_offset ()
504 RegionSelection rs = get_regions_from_selection_and_entered ();
506 if (!_session || rs.empty()) {
510 begin_reversible_command (_("nudge forward"));
512 framepos_t const distance = _session->worst_output_latency();
514 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
515 boost::shared_ptr<Region> r ((*i)->region());
518 r->set_position (r->position() + distance);
519 _session->add_command(new StatefulDiffCommand (r));
522 commit_reversible_command ();
526 Editor::nudge_backward_capture_offset ()
528 RegionSelection rs = get_regions_from_selection_and_entered ();
530 if (!_session || rs.empty()) {
534 begin_reversible_command (_("nudge backward"));
536 framepos_t const distance = _session->worst_output_latency();
538 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
539 boost::shared_ptr<Region> r ((*i)->region());
543 if (r->position() > distance) {
544 r->set_position (r->position() - distance);
548 _session->add_command(new StatefulDiffCommand (r));
551 commit_reversible_command ();
554 struct RegionSelectionPositionSorter {
555 bool operator() (RegionView* a, RegionView* b) {
556 return a->region()->position() < b->region()->position();
561 Editor::sequence_regions ()
564 framepos_t r_end_prev;
572 RegionSelection rs = get_regions_from_selection_and_entered ();
573 rs.sort(RegionSelectionPositionSorter());
577 begin_reversible_command (_("sequence regions"));
578 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
579 boost::shared_ptr<Region> r ((*i)->region());
587 if(r->position_locked())
594 r->set_position(r_end_prev);
597 _session->add_command (new StatefulDiffCommand (r));
599 r_end=r->position() + r->length();
603 commit_reversible_command ();
611 Editor::move_to_start ()
613 _session->goto_start ();
617 Editor::move_to_end ()
620 _session->request_locate (_session->current_end_frame());
624 Editor::build_region_boundary_cache ()
627 vector<RegionPoint> interesting_points;
628 boost::shared_ptr<Region> r;
629 TrackViewList tracks;
632 region_boundary_cache.clear ();
638 switch (_snap_type) {
639 case SnapToRegionStart:
640 interesting_points.push_back (Start);
642 case SnapToRegionEnd:
643 interesting_points.push_back (End);
645 case SnapToRegionSync:
646 interesting_points.push_back (SyncPoint);
648 case SnapToRegionBoundary:
649 interesting_points.push_back (Start);
650 interesting_points.push_back (End);
653 fatal << string_compose (_("build_region_boundary_cache called with snap_type = %1"), _snap_type) << endmsg;
654 abort(); /*NOTREACHED*/
658 TimeAxisView *ontrack = 0;
661 if (!selection->tracks.empty()) {
662 tlist = selection->tracks.filter_to_unique_playlists ();
664 tlist = track_views.filter_to_unique_playlists ();
667 while (pos < _session->current_end_frame() && !at_end) {
670 framepos_t lpos = max_framepos;
672 for (vector<RegionPoint>::iterator p = interesting_points.begin(); p != interesting_points.end(); ++p) {
674 if ((r = find_next_region (pos, *p, 1, tlist, &ontrack)) == 0) {
675 if (*p == interesting_points.back()) {
678 /* move to next point type */
684 rpos = r->first_frame();
688 rpos = r->last_frame();
692 rpos = r->sync_position ();
700 RouteTimeAxisView *rtav;
702 if (ontrack != 0 && (rtav = dynamic_cast<RouteTimeAxisView*>(ontrack)) != 0 ) {
703 if (rtav->track() != 0) {
704 speed = rtav->track()->speed();
708 rpos = track_frame_to_session_frame (rpos, speed);
714 /* prevent duplicates, but we don't use set<> because we want to be able
718 vector<framepos_t>::iterator ri;
720 for (ri = region_boundary_cache.begin(); ri != region_boundary_cache.end(); ++ri) {
726 if (ri == region_boundary_cache.end()) {
727 region_boundary_cache.push_back (rpos);
734 /* finally sort to be sure that the order is correct */
736 sort (region_boundary_cache.begin(), region_boundary_cache.end());
739 boost::shared_ptr<Region>
740 Editor::find_next_region (framepos_t frame, RegionPoint point, int32_t dir, TrackViewList& tracks, TimeAxisView **ontrack)
742 TrackViewList::iterator i;
743 framepos_t closest = max_framepos;
744 boost::shared_ptr<Region> ret;
748 framepos_t track_frame;
749 RouteTimeAxisView *rtav;
751 for (i = tracks.begin(); i != tracks.end(); ++i) {
754 boost::shared_ptr<Region> r;
757 if ( (rtav = dynamic_cast<RouteTimeAxisView*>(*i)) != 0 ) {
758 if (rtav->track()!=0)
759 track_speed = rtav->track()->speed();
762 track_frame = session_frame_to_track_frame(frame, track_speed);
764 if ((r = (*i)->find_next_region (track_frame, point, dir)) == 0) {
770 rpos = r->first_frame ();
774 rpos = r->last_frame ();
778 rpos = r->sync_position ();
782 // rpos is a "track frame", converting it to "_session frame"
783 rpos = track_frame_to_session_frame(rpos, track_speed);
786 distance = rpos - frame;
788 distance = frame - rpos;
791 if (distance < closest) {
803 Editor::find_next_region_boundary (framepos_t pos, int32_t dir, const TrackViewList& tracks)
805 framecnt_t distance = max_framepos;
806 framepos_t current_nearest = -1;
808 for (TrackViewList::const_iterator i = tracks.begin(); i != tracks.end(); ++i) {
809 framepos_t contender;
812 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*i);
818 if ((contender = rtv->find_next_region_boundary (pos, dir)) < 0) {
822 d = ::llabs (pos - contender);
825 current_nearest = contender;
830 return current_nearest;
834 Editor::get_region_boundary (framepos_t pos, int32_t dir, bool with_selection, bool only_onscreen)
839 if (with_selection && Config->get_region_boundaries_from_selected_tracks()) {
841 if (!selection->tracks.empty()) {
843 target = find_next_region_boundary (pos, dir, selection->tracks);
847 if (only_onscreen || Config->get_region_boundaries_from_onscreen_tracks()) {
848 get_onscreen_tracks (tvl);
849 target = find_next_region_boundary (pos, dir, tvl);
851 target = find_next_region_boundary (pos, dir, track_views);
857 if (only_onscreen || Config->get_region_boundaries_from_onscreen_tracks()) {
858 get_onscreen_tracks (tvl);
859 target = find_next_region_boundary (pos, dir, tvl);
861 target = find_next_region_boundary (pos, dir, track_views);
869 Editor::cursor_to_region_boundary (bool with_selection, int32_t dir)
871 framepos_t pos = playhead_cursor->current_frame ();
878 // so we don't find the current region again..
879 if (dir > 0 || pos > 0) {
883 if ((target = get_region_boundary (pos, dir, with_selection, false)) < 0) {
887 _session->request_locate (target);
891 Editor::cursor_to_next_region_boundary (bool with_selection)
893 cursor_to_region_boundary (with_selection, 1);
897 Editor::cursor_to_previous_region_boundary (bool with_selection)
899 cursor_to_region_boundary (with_selection, -1);
903 Editor::cursor_to_region_point (EditorCursor* cursor, RegionPoint point, int32_t dir)
905 boost::shared_ptr<Region> r;
906 framepos_t pos = cursor->current_frame ();
912 TimeAxisView *ontrack = 0;
914 // so we don't find the current region again..
918 if (!selection->tracks.empty()) {
920 r = find_next_region (pos, point, dir, selection->tracks, &ontrack);
922 } else if (clicked_axisview) {
925 t.push_back (clicked_axisview);
927 r = find_next_region (pos, point, dir, t, &ontrack);
931 r = find_next_region (pos, point, dir, track_views, &ontrack);
940 pos = r->first_frame ();
944 pos = r->last_frame ();
948 pos = r->sync_position ();
953 RouteTimeAxisView *rtav;
955 if ( ontrack != 0 && (rtav = dynamic_cast<RouteTimeAxisView*>(ontrack)) != 0 ) {
956 if (rtav->track() != 0) {
957 speed = rtav->track()->speed();
961 pos = track_frame_to_session_frame(pos, speed);
963 if (cursor == playhead_cursor) {
964 _session->request_locate (pos);
966 cursor->set_position (pos);
971 Editor::cursor_to_next_region_point (EditorCursor* cursor, RegionPoint point)
973 cursor_to_region_point (cursor, point, 1);
977 Editor::cursor_to_previous_region_point (EditorCursor* cursor, RegionPoint point)
979 cursor_to_region_point (cursor, point, -1);
983 Editor::cursor_to_selection_start (EditorCursor *cursor)
987 switch (mouse_mode) {
989 if (!selection->regions.empty()) {
990 pos = selection->regions.start();
995 if (!selection->time.empty()) {
996 pos = selection->time.start ();
1004 if (cursor == playhead_cursor) {
1005 _session->request_locate (pos);
1007 cursor->set_position (pos);
1012 Editor::cursor_to_selection_end (EditorCursor *cursor)
1016 switch (mouse_mode) {
1018 if (!selection->regions.empty()) {
1019 pos = selection->regions.end_frame();
1024 if (!selection->time.empty()) {
1025 pos = selection->time.end_frame ();
1033 if (cursor == playhead_cursor) {
1034 _session->request_locate (pos);
1036 cursor->set_position (pos);
1041 Editor::selected_marker_to_region_boundary (bool with_selection, int32_t dir)
1051 if (selection->markers.empty()) {
1055 if (!mouse_frame (mouse, ignored)) {
1059 add_location_mark (mouse);
1062 if ((loc = find_location_from_marker (selection->markers.front(), ignored)) == 0) {
1066 framepos_t pos = loc->start();
1068 // so we don't find the current region again..
1069 if (dir > 0 || pos > 0) {
1073 if ((target = get_region_boundary (pos, dir, with_selection, false)) < 0) {
1077 loc->move_to (target);
1081 Editor::selected_marker_to_next_region_boundary (bool with_selection)
1083 selected_marker_to_region_boundary (with_selection, 1);
1087 Editor::selected_marker_to_previous_region_boundary (bool with_selection)
1089 selected_marker_to_region_boundary (with_selection, -1);
1093 Editor::selected_marker_to_region_point (RegionPoint point, int32_t dir)
1095 boost::shared_ptr<Region> r;
1100 if (!_session || selection->markers.empty()) {
1104 if ((loc = find_location_from_marker (selection->markers.front(), ignored)) == 0) {
1108 TimeAxisView *ontrack = 0;
1112 // so we don't find the current region again..
1116 if (!selection->tracks.empty()) {
1118 r = find_next_region (pos, point, dir, selection->tracks, &ontrack);
1122 r = find_next_region (pos, point, dir, track_views, &ontrack);
1131 pos = r->first_frame ();
1135 pos = r->last_frame ();
1139 pos = r->adjust_to_sync (r->first_frame());
1144 RouteTimeAxisView *rtav;
1146 if (ontrack != 0 && (rtav = dynamic_cast<RouteTimeAxisView*>(ontrack)) != 0) {
1147 if (rtav->track() != 0) {
1148 speed = rtav->track()->speed();
1152 pos = track_frame_to_session_frame(pos, speed);
1158 Editor::selected_marker_to_next_region_point (RegionPoint point)
1160 selected_marker_to_region_point (point, 1);
1164 Editor::selected_marker_to_previous_region_point (RegionPoint point)
1166 selected_marker_to_region_point (point, -1);
1170 Editor::selected_marker_to_selection_start ()
1176 if (!_session || selection->markers.empty()) {
1180 if ((loc = find_location_from_marker (selection->markers.front(), ignored)) == 0) {
1184 switch (mouse_mode) {
1186 if (!selection->regions.empty()) {
1187 pos = selection->regions.start();
1192 if (!selection->time.empty()) {
1193 pos = selection->time.start ();
1205 Editor::selected_marker_to_selection_end ()
1211 if (!_session || selection->markers.empty()) {
1215 if ((loc = find_location_from_marker (selection->markers.front(), ignored)) == 0) {
1219 switch (mouse_mode) {
1221 if (!selection->regions.empty()) {
1222 pos = selection->regions.end_frame();
1227 if (!selection->time.empty()) {
1228 pos = selection->time.end_frame ();
1240 Editor::scroll_playhead (bool forward)
1242 framepos_t pos = playhead_cursor->current_frame ();
1243 framecnt_t delta = (framecnt_t) floor (current_page_samples() / 0.8);
1246 if (pos == max_framepos) {
1250 if (pos < max_framepos - delta) {
1269 _session->request_locate (pos);
1273 Editor::cursor_align (bool playhead_to_edit)
1279 if (playhead_to_edit) {
1281 if (selection->markers.empty()) {
1285 _session->request_locate (selection->markers.front()->position(), _session->transport_rolling());
1288 /* move selected markers to playhead */
1290 for (MarkerSelection::iterator i = selection->markers.begin(); i != selection->markers.end(); ++i) {
1293 Location* loc = find_location_from_marker (*i, ignored);
1295 if (loc->is_mark()) {
1296 loc->set_start (playhead_cursor->current_frame ());
1298 loc->set (playhead_cursor->current_frame (),
1299 playhead_cursor->current_frame () + loc->length());
1306 Editor::scroll_backward (float pages)
1308 framepos_t const one_page = (framepos_t) rint (_visible_canvas_width * samples_per_pixel);
1309 framepos_t const cnt = (framepos_t) floor (pages * one_page);
1312 if (leftmost_frame < cnt) {
1315 frame = leftmost_frame - cnt;
1318 reset_x_origin (frame);
1322 Editor::scroll_forward (float pages)
1324 framepos_t const one_page = (framepos_t) rint (_visible_canvas_width * samples_per_pixel);
1325 framepos_t const cnt = (framepos_t) floor (pages * one_page);
1328 if (max_framepos - cnt < leftmost_frame) {
1329 frame = max_framepos - cnt;
1331 frame = leftmost_frame + cnt;
1334 reset_x_origin (frame);
1338 Editor::scroll_tracks_down ()
1340 double vert_value = vertical_adjustment.get_value() + vertical_adjustment.get_page_size();
1341 if (vert_value > vertical_adjustment.get_upper() - _visible_canvas_height) {
1342 vert_value = vertical_adjustment.get_upper() - _visible_canvas_height;
1345 vertical_adjustment.set_value (vert_value);
1349 Editor::scroll_tracks_up ()
1351 vertical_adjustment.set_value (vertical_adjustment.get_value() - vertical_adjustment.get_page_size());
1355 Editor::scroll_tracks_down_line ()
1357 double vert_value = vertical_adjustment.get_value() + 60;
1359 if (vert_value > vertical_adjustment.get_upper() - _visible_canvas_height) {
1360 vert_value = vertical_adjustment.get_upper() - _visible_canvas_height;
1363 vertical_adjustment.set_value (vert_value);
1367 Editor::scroll_tracks_up_line ()
1369 reset_y_origin (vertical_adjustment.get_value() - 60);
1373 Editor::scroll_down_one_track ()
1375 TrackViewList::reverse_iterator next = track_views.rend();
1376 std::pair<TimeAxisView*,double> res;
1377 const double top_of_trackviews = vertical_adjustment.get_value();
1379 for (TrackViewList::reverse_iterator t = track_views.rbegin(); t != track_views.rend(); ++t) {
1380 if ((*t)->hidden()) {
1385 /* If this is the upper-most visible trackview, we want to display
1386 the one above it (next)
1389 res = (*t)->covers_y_position (top_of_trackviews);
1397 /* move to the track below the first one that covers the */
1399 if (next != track_views.rend()) {
1400 ensure_time_axis_view_is_visible (**next, true);
1408 Editor::scroll_up_one_track ()
1410 TrackViewList::iterator prev = track_views.end();
1411 std::pair<TimeAxisView*,double> res;
1412 double top_of_trackviews = vertical_adjustment.get_value ();
1414 for (TrackViewList::iterator t = track_views.begin(); t != track_views.end(); ++t) {
1416 if ((*t)->hidden()) {
1420 /* find the trackview at the top of the trackview group */
1421 res = (*t)->covers_y_position (top_of_trackviews);
1430 if (prev != track_views.end()) {
1431 ensure_time_axis_view_is_visible (**prev, true);
1441 Editor::tav_zoom_step (bool coarser)
1443 DisplaySuspender ds;
1447 if (selection->tracks.empty()) {
1450 ts = &selection->tracks;
1453 for (TrackViewList::iterator i = ts->begin(); i != ts->end(); ++i) {
1454 TimeAxisView *tv = (static_cast<TimeAxisView*>(*i));
1455 tv->step_height (coarser);
1460 Editor::tav_zoom_smooth (bool coarser, bool force_all)
1462 DisplaySuspender ds;
1466 if (selection->tracks.empty() || force_all) {
1469 ts = &selection->tracks;
1472 for (TrackViewList::iterator i = ts->begin(); i != ts->end(); ++i) {
1473 TimeAxisView *tv = (static_cast<TimeAxisView*>(*i));
1474 uint32_t h = tv->current_height ();
1479 if (h >= TimeAxisView::preset_height (HeightSmall)) {
1484 tv->set_height (h + 5);
1491 Editor::temporal_zoom_step (bool coarser)
1493 ENSURE_GUI_THREAD (*this, &Editor::temporal_zoom_step, coarser)
1495 framecnt_t nspp = samples_per_pixel;
1503 temporal_zoom (nspp);
1507 Editor::temporal_zoom (framecnt_t fpp)
1513 framepos_t current_page = current_page_samples();
1514 framepos_t current_leftmost = leftmost_frame;
1515 framepos_t current_rightmost;
1516 framepos_t current_center;
1517 framepos_t new_page_size;
1518 framepos_t half_page_size;
1519 framepos_t leftmost_after_zoom = 0;
1521 bool in_track_canvas;
1525 if (fpp == samples_per_pixel) {
1529 // Imposing an arbitrary limit to zoom out as too much zoom out produces
1530 // segfaults for lack of memory. If somebody decides this is not high enough I
1531 // believe it can be raisen to higher values but some limit must be in place.
1533 // This constant represents 1 day @ 48kHz on a 1600 pixel wide display
1534 // all of which is used for the editor track displays. The whole day
1535 // would be 4147200000 samples, so 2592000 samples per pixel.
1537 nfpp = min (fpp, (framecnt_t) 2592000);
1538 nfpp = max ((framecnt_t) 1, nfpp);
1540 new_page_size = (framepos_t) floor (_visible_canvas_width * nfpp);
1541 half_page_size = new_page_size / 2;
1543 switch (zoom_focus) {
1545 leftmost_after_zoom = current_leftmost;
1548 case ZoomFocusRight:
1549 current_rightmost = leftmost_frame + current_page;
1550 if (current_rightmost < new_page_size) {
1551 leftmost_after_zoom = 0;
1553 leftmost_after_zoom = current_rightmost - new_page_size;
1557 case ZoomFocusCenter:
1558 current_center = current_leftmost + (current_page/2);
1559 if (current_center < half_page_size) {
1560 leftmost_after_zoom = 0;
1562 leftmost_after_zoom = current_center - half_page_size;
1566 case ZoomFocusPlayhead:
1567 /* centre playhead */
1568 l = playhead_cursor->current_frame () - (new_page_size * 0.5);
1571 leftmost_after_zoom = 0;
1572 } else if (l > max_framepos) {
1573 leftmost_after_zoom = max_framepos - new_page_size;
1575 leftmost_after_zoom = (framepos_t) l;
1579 case ZoomFocusMouse:
1580 /* try to keep the mouse over the same point in the display */
1582 if (!mouse_frame (where, in_track_canvas)) {
1583 /* use playhead instead */
1584 where = playhead_cursor->current_frame ();
1586 if (where < half_page_size) {
1587 leftmost_after_zoom = 0;
1589 leftmost_after_zoom = where - half_page_size;
1594 l = - ((new_page_size * ((where - current_leftmost)/(double)current_page)) - where);
1597 leftmost_after_zoom = 0;
1598 } else if (l > max_framepos) {
1599 leftmost_after_zoom = max_framepos - new_page_size;
1601 leftmost_after_zoom = (framepos_t) l;
1608 /* try to keep the edit point in the same place */
1609 where = get_preferred_edit_position ();
1613 double l = - ((new_page_size * ((where - current_leftmost)/(double)current_page)) - where);
1616 leftmost_after_zoom = 0;
1617 } else if (l > max_framepos) {
1618 leftmost_after_zoom = max_framepos - new_page_size;
1620 leftmost_after_zoom = (framepos_t) l;
1624 /* edit point not defined */
1631 // leftmost_after_zoom = min (leftmost_after_zoom, _session->current_end_frame());
1633 reposition_and_zoom (leftmost_after_zoom, nfpp);
1637 Editor::calc_extra_zoom_edges(framepos_t &start, framepos_t &end)
1639 /* this func helps make sure we leave a little space
1640 at each end of the editor so that the zoom doesn't fit the region
1641 precisely to the screen.
1644 GdkScreen* screen = gdk_screen_get_default ();
1645 const gint pixwidth = gdk_screen_get_width (screen);
1646 const gint mmwidth = gdk_screen_get_width_mm (screen);
1647 const double pix_per_mm = (double) pixwidth/ (double) mmwidth;
1648 const double one_centimeter_in_pixels = pix_per_mm * 10.0;
1650 const framepos_t range = end - start;
1651 const framecnt_t new_fpp = (framecnt_t) ceil ((double) range / (double) _visible_canvas_width);
1652 const framepos_t extra_samples = (framepos_t) floor (one_centimeter_in_pixels * new_fpp);
1654 if (start > extra_samples) {
1655 start -= extra_samples;
1660 if (max_framepos - extra_samples > end) {
1661 end += extra_samples;
1668 Editor::temporal_zoom_region (bool both_axes)
1670 framepos_t start = max_framepos;
1672 set<TimeAxisView*> tracks;
1674 RegionSelection rs = get_regions_from_selection_and_entered ();
1680 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
1682 if ((*i)->region()->position() < start) {
1683 start = (*i)->region()->position();
1686 if ((*i)->region()->last_frame() + 1 > end) {
1687 end = (*i)->region()->last_frame() + 1;
1690 tracks.insert (&((*i)->get_time_axis_view()));
1693 if ((start == 0 && end == 0) || end < start) {
1697 calc_extra_zoom_edges (start, end);
1699 /* if we're zooming on both axes we need to save track heights etc.
1702 undo_visual_stack.push_back (current_visual_state (both_axes));
1704 PBD::Unwinder<bool> nsv (no_save_visual, true);
1706 temporal_zoom_by_frame (start, end);
1709 uint32_t per_track_height = (uint32_t) floor ((_visible_canvas_height - 10.0) / tracks.size());
1711 /* set visible track heights appropriately */
1713 for (set<TimeAxisView*>::iterator t = tracks.begin(); t != tracks.end(); ++t) {
1714 (*t)->set_height (per_track_height);
1717 /* hide irrelevant tracks */
1719 DisplaySuspender ds;
1721 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1722 if (find (tracks.begin(), tracks.end(), (*i)) == tracks.end()) {
1723 hide_track_in_display (*i);
1727 vertical_adjustment.set_value (0.0);
1730 redo_visual_stack.push_back (current_visual_state (both_axes));
1734 Editor::zoom_to_region (bool both_axes)
1736 temporal_zoom_region (both_axes);
1740 Editor::temporal_zoom_selection (bool both_axes)
1742 if (!selection) return;
1744 //if a range is selected, zoom to that
1745 if (!selection->time.empty()) {
1747 framepos_t start = selection->time.start();
1748 framepos_t end = selection->time.end_frame();
1750 calc_extra_zoom_edges(start, end);
1752 temporal_zoom_by_frame (start, end);
1755 fit_selected_tracks();
1758 temporal_zoom_region (both_axes);
1765 Editor::temporal_zoom_session ()
1767 ENSURE_GUI_THREAD (*this, &Editor::temporal_zoom_session)
1770 framecnt_t start = _session->current_start_frame();
1771 framecnt_t end = _session->current_end_frame();
1773 if (_session->actively_recording () ) {
1774 framepos_t cur = playhead_cursor->current_frame ();
1776 /* recording beyond the end marker; zoom out
1777 * by 5 seconds more so that if 'follow
1778 * playhead' is active we don't immediately
1781 end = cur + _session->frame_rate() * 5;
1785 if ((start == 0 && end == 0) || end < start) {
1789 calc_extra_zoom_edges(start, end);
1791 temporal_zoom_by_frame (start, end);
1796 Editor::temporal_zoom_by_frame (framepos_t start, framepos_t end)
1798 if (!_session) return;
1800 if ((start == 0 && end == 0) || end < start) {
1804 framepos_t range = end - start;
1806 const framecnt_t new_fpp = (framecnt_t) ceil ((double) range / (double) _visible_canvas_width);
1808 framepos_t new_page = range;
1809 framepos_t middle = (framepos_t) floor ((double) start + ((double) range / 2.0f));
1810 framepos_t new_leftmost = (framepos_t) floor ((double) middle - ((double) new_page / 2.0f));
1812 if (new_leftmost > middle) {
1816 if (new_leftmost < 0) {
1820 reposition_and_zoom (new_leftmost, new_fpp);
1824 Editor::temporal_zoom_to_frame (bool coarser, framepos_t frame)
1830 framecnt_t range_before = frame - leftmost_frame;
1834 if (samples_per_pixel <= 1) {
1837 new_spp = samples_per_pixel + (samples_per_pixel/2);
1839 range_before += range_before/2;
1841 if (samples_per_pixel >= 1) {
1842 new_spp = samples_per_pixel - (samples_per_pixel/2);
1844 /* could bail out here since we cannot zoom any finer,
1845 but leave that to the equality test below
1847 new_spp = samples_per_pixel;
1850 range_before -= range_before/2;
1853 if (new_spp == samples_per_pixel) {
1857 /* zoom focus is automatically taken as @param frame when this
1861 framepos_t new_leftmost = frame - (framepos_t)range_before;
1863 if (new_leftmost > frame) {
1867 if (new_leftmost < 0) {
1871 reposition_and_zoom (new_leftmost, new_spp);
1876 Editor::choose_new_marker_name(string &name) {
1878 if (!Config->get_name_new_markers()) {
1879 /* don't prompt user for a new name */
1883 ArdourPrompter dialog (true);
1885 dialog.set_prompt (_("New Name:"));
1887 dialog.set_title (_("New Location Marker"));
1889 dialog.set_name ("MarkNameWindow");
1890 dialog.set_size_request (250, -1);
1891 dialog.set_position (Gtk::WIN_POS_MOUSE);
1893 dialog.add_button (Stock::OK, RESPONSE_ACCEPT);
1894 dialog.set_initial_text (name);
1898 switch (dialog.run ()) {
1899 case RESPONSE_ACCEPT:
1905 dialog.get_result(name);
1912 Editor::add_location_from_selection ()
1916 if (selection->time.empty()) {
1920 if (_session == 0 || clicked_axisview == 0) {
1924 framepos_t start = selection->time[clicked_selection].start;
1925 framepos_t end = selection->time[clicked_selection].end;
1927 _session->locations()->next_available_name(rangename,"selection");
1928 Location *location = new Location (*_session, start, end, rangename, Location::IsRangeMarker);
1930 _session->begin_reversible_command (_("add marker"));
1931 XMLNode &before = _session->locations()->get_state();
1932 _session->locations()->add (location, true);
1933 XMLNode &after = _session->locations()->get_state();
1934 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
1935 _session->commit_reversible_command ();
1939 Editor::add_location_mark (framepos_t where)
1943 select_new_marker = true;
1945 _session->locations()->next_available_name(markername,"mark");
1946 if (!choose_new_marker_name(markername)) {
1949 Location *location = new Location (*_session, where, where, markername, Location::IsMark);
1950 _session->begin_reversible_command (_("add marker"));
1951 XMLNode &before = _session->locations()->get_state();
1952 _session->locations()->add (location, true);
1953 XMLNode &after = _session->locations()->get_state();
1954 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
1955 _session->commit_reversible_command ();
1959 Editor::add_location_from_playhead_cursor ()
1961 add_location_mark (_session->audible_frame());
1965 Editor::remove_location_at_playhead_cursor ()
1970 _session->begin_reversible_command (_("remove marker"));
1971 XMLNode &before = _session->locations()->get_state();
1972 bool removed = false;
1974 //find location(s) at this time
1975 Locations::LocationList locs;
1976 _session->locations()->find_all_between (_session->audible_frame(), _session->audible_frame()+1, locs, Location::Flags(0));
1977 for (Locations::LocationList::iterator i = locs.begin(); i != locs.end(); ++i) {
1978 if ((*i)->is_mark()) {
1979 _session->locations()->remove (*i);
1986 XMLNode &after = _session->locations()->get_state();
1987 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
1988 _session->commit_reversible_command ();
1993 /** Add a range marker around each selected region */
1995 Editor::add_locations_from_region ()
1997 RegionSelection rs = get_regions_from_selection_and_entered ();
2003 _session->begin_reversible_command (selection->regions.size () > 1 ? _("add markers") : _("add marker"));
2004 XMLNode &before = _session->locations()->get_state();
2006 for (RegionSelection::iterator i = rs.begin (); i != rs.end (); ++i) {
2008 boost::shared_ptr<Region> region = (*i)->region ();
2010 Location *location = new Location (*_session, region->position(), region->last_frame(), region->name(), Location::IsRangeMarker);
2012 _session->locations()->add (location, true);
2015 XMLNode &after = _session->locations()->get_state();
2016 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2017 _session->commit_reversible_command ();
2020 /** Add a single range marker around all selected regions */
2022 Editor::add_location_from_region ()
2024 RegionSelection rs = get_regions_from_selection_and_entered ();
2030 _session->begin_reversible_command (_("add marker"));
2031 XMLNode &before = _session->locations()->get_state();
2035 if (rs.size() > 1) {
2036 _session->locations()->next_available_name(markername, "regions");
2038 RegionView* rv = *(rs.begin());
2039 boost::shared_ptr<Region> region = rv->region();
2040 markername = region->name();
2043 if (!choose_new_marker_name(markername)) {
2047 // single range spanning all selected
2048 Location *location = new Location (*_session, selection->regions.start(), selection->regions.end_frame(), markername, Location::IsRangeMarker);
2049 _session->locations()->add (location, true);
2051 XMLNode &after = _session->locations()->get_state();
2052 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2053 _session->commit_reversible_command ();
2059 Editor::jump_forward_to_mark ()
2065 framepos_t pos = _session->locations()->first_mark_after (playhead_cursor->current_frame());
2071 _session->request_locate (pos, _session->transport_rolling());
2075 Editor::jump_backward_to_mark ()
2081 framepos_t pos = _session->locations()->first_mark_before (playhead_cursor->current_frame());
2087 _session->request_locate (pos, _session->transport_rolling());
2093 framepos_t const pos = _session->audible_frame ();
2096 _session->locations()->next_available_name (markername, "mark");
2098 if (!choose_new_marker_name (markername)) {
2102 _session->locations()->add (new Location (*_session, pos, 0, markername, Location::IsMark), true);
2106 Editor::clear_markers ()
2109 _session->begin_reversible_command (_("clear markers"));
2110 XMLNode &before = _session->locations()->get_state();
2111 _session->locations()->clear_markers ();
2112 XMLNode &after = _session->locations()->get_state();
2113 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2114 _session->commit_reversible_command ();
2119 Editor::clear_ranges ()
2122 _session->begin_reversible_command (_("clear ranges"));
2123 XMLNode &before = _session->locations()->get_state();
2125 _session->locations()->clear_ranges ();
2127 XMLNode &after = _session->locations()->get_state();
2128 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2129 _session->commit_reversible_command ();
2134 Editor::clear_locations ()
2136 _session->begin_reversible_command (_("clear locations"));
2137 XMLNode &before = _session->locations()->get_state();
2138 _session->locations()->clear ();
2139 XMLNode &after = _session->locations()->get_state();
2140 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2141 _session->commit_reversible_command ();
2142 _session->locations()->clear ();
2146 Editor::unhide_markers ()
2148 for (LocationMarkerMap::iterator i = location_markers.begin(); i != location_markers.end(); ++i) {
2149 Location *l = (*i).first;
2150 if (l->is_hidden() && l->is_mark()) {
2151 l->set_hidden(false, this);
2157 Editor::unhide_ranges ()
2159 for (LocationMarkerMap::iterator i = location_markers.begin(); i != location_markers.end(); ++i) {
2160 Location *l = (*i).first;
2161 if (l->is_hidden() && l->is_range_marker()) {
2162 l->set_hidden(false, this);
2167 /* INSERT/REPLACE */
2170 Editor::insert_region_list_selection (float times)
2172 RouteTimeAxisView *tv = 0;
2173 boost::shared_ptr<Playlist> playlist;
2175 if (clicked_routeview != 0) {
2176 tv = clicked_routeview;
2177 } else if (!selection->tracks.empty()) {
2178 if ((tv = dynamic_cast<RouteTimeAxisView*>(selection->tracks.front())) == 0) {
2181 } else if (entered_track != 0) {
2182 if ((tv = dynamic_cast<RouteTimeAxisView*>(entered_track)) == 0) {
2189 if ((playlist = tv->playlist()) == 0) {
2193 boost::shared_ptr<Region> region = _regions->get_single_selection ();
2198 begin_reversible_command (_("insert region"));
2199 playlist->clear_changes ();
2200 playlist->add_region ((RegionFactory::create (region, true)), get_preferred_edit_position(), times);
2201 if (Config->get_edit_mode() == Ripple)
2202 playlist->ripple (get_preferred_edit_position(), region->length() * times, boost::shared_ptr<Region>());
2204 _session->add_command(new StatefulDiffCommand (playlist));
2205 commit_reversible_command ();
2208 /* BUILT-IN EFFECTS */
2211 Editor::reverse_selection ()
2216 /* GAIN ENVELOPE EDITING */
2219 Editor::edit_envelope ()
2226 Editor::transition_to_rolling (bool fwd)
2232 if (_session->config.get_external_sync()) {
2233 switch (Config->get_sync_source()) {
2237 /* transport controlled by the master */
2242 if (_session->is_auditioning()) {
2243 _session->cancel_audition ();
2247 _session->request_transport_speed (fwd ? 1.0f : -1.0f);
2251 Editor::play_from_start ()
2253 _session->request_locate (_session->current_start_frame(), true);
2257 Editor::play_from_edit_point ()
2259 _session->request_locate (get_preferred_edit_position(), true);
2263 Editor::play_from_edit_point_and_return ()
2265 framepos_t start_frame;
2266 framepos_t return_frame;
2268 start_frame = get_preferred_edit_position (true);
2270 if (_session->transport_rolling()) {
2271 _session->request_locate (start_frame, false);
2275 /* don't reset the return frame if its already set */
2277 if ((return_frame = _session->requested_return_frame()) < 0) {
2278 return_frame = _session->audible_frame();
2281 if (start_frame >= 0) {
2282 _session->request_roll_at_and_return (start_frame, return_frame);
2287 Editor::play_selection ()
2289 if (selection->time.empty()) {
2293 _session->request_play_range (&selection->time, true);
2297 Editor::get_preroll ()
2299 return 1.0 /*Config->get_edit_preroll_seconds()*/ * _session->frame_rate();
2304 Editor::maybe_locate_with_edit_preroll ( framepos_t location )
2306 if ( _session->transport_rolling() || !Config->get_follow_edits() || _ignore_follow_edits )
2309 location -= get_preroll();
2311 //don't try to locate before the beginning of time
2315 //if follow_playhead is on, keep the playhead on the screen
2316 if ( _follow_playhead )
2317 if ( location < leftmost_frame )
2318 location = leftmost_frame;
2320 _session->request_locate( location );
2324 Editor::play_with_preroll ()
2326 if (selection->time.empty()) {
2329 framepos_t preroll = get_preroll();
2331 framepos_t start = 0;
2332 if (selection->time[clicked_selection].start > preroll)
2333 start = selection->time[clicked_selection].start - preroll;
2335 framepos_t end = selection->time[clicked_selection].end + preroll;
2337 AudioRange ar (start, end, 0);
2338 list<AudioRange> lar;
2341 _session->request_play_range (&lar, true);
2346 Editor::play_location (Location& location)
2348 if (location.start() <= location.end()) {
2352 _session->request_bounded_roll (location.start(), location.end());
2356 Editor::loop_location (Location& location)
2358 if (location.start() <= location.end()) {
2364 if ((tll = transport_loop_location()) != 0) {
2365 tll->set (location.start(), location.end());
2367 // enable looping, reposition and start rolling
2368 _session->request_locate (tll->start(), true);
2369 _session->request_play_loop (true);
2374 Editor::do_layer_operation (LayerOperation op)
2376 if (selection->regions.empty ()) {
2380 bool const multiple = selection->regions.size() > 1;
2384 begin_reversible_command (_("raise regions"));
2386 begin_reversible_command (_("raise region"));
2392 begin_reversible_command (_("raise regions to top"));
2394 begin_reversible_command (_("raise region to top"));
2400 begin_reversible_command (_("lower regions"));
2402 begin_reversible_command (_("lower region"));
2408 begin_reversible_command (_("lower regions to bottom"));
2410 begin_reversible_command (_("lower region"));
2415 set<boost::shared_ptr<Playlist> > playlists = selection->regions.playlists ();
2416 for (set<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
2417 (*i)->clear_owned_changes ();
2420 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
2421 boost::shared_ptr<Region> r = (*i)->region ();
2433 r->lower_to_bottom ();
2437 for (set<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
2438 vector<Command*> cmds;
2440 _session->add_commands (cmds);
2443 commit_reversible_command ();
2447 Editor::raise_region ()
2449 do_layer_operation (Raise);
2453 Editor::raise_region_to_top ()
2455 do_layer_operation (RaiseToTop);
2459 Editor::lower_region ()
2461 do_layer_operation (Lower);
2465 Editor::lower_region_to_bottom ()
2467 do_layer_operation (LowerToBottom);
2470 /** Show the region editor for the selected regions */
2472 Editor::show_region_properties ()
2474 selection->foreach_regionview (&RegionView::show_region_editor);
2477 /** Show the midi list editor for the selected MIDI regions */
2479 Editor::show_midi_list_editor ()
2481 selection->foreach_midi_regionview (&MidiRegionView::show_list_editor);
2485 Editor::rename_region ()
2487 RegionSelection rs = get_regions_from_selection_and_entered ();
2493 ArdourDialog d (*this, _("Rename Region"), true, false);
2495 Label label (_("New name:"));
2498 hbox.set_spacing (6);
2499 hbox.pack_start (label, false, false);
2500 hbox.pack_start (entry, true, true);
2502 d.get_vbox()->set_border_width (12);
2503 d.get_vbox()->pack_start (hbox, false, false);
2505 d.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
2506 d.add_button(Gtk::Stock::OK, Gtk::RESPONSE_OK);
2508 d.set_size_request (300, -1);
2510 entry.set_text (rs.front()->region()->name());
2511 entry.select_region (0, -1);
2513 entry.signal_activate().connect (sigc::bind (sigc::mem_fun (d, &Dialog::response), RESPONSE_OK));
2519 int const ret = d.run();
2523 if (ret != RESPONSE_OK) {
2527 std::string str = entry.get_text();
2528 strip_whitespace_edges (str);
2530 rs.front()->region()->set_name (str);
2531 _regions->redisplay ();
2536 Editor::audition_playlist_region_via_route (boost::shared_ptr<Region> region, Route& route)
2538 if (_session->is_auditioning()) {
2539 _session->cancel_audition ();
2542 // note: some potential for creativity here, because region doesn't
2543 // have to belong to the playlist that Route is handling
2545 // bool was_soloed = route.soloed();
2547 route.set_solo (true, this);
2549 _session->request_bounded_roll (region->position(), region->position() + region->length());
2551 /* XXX how to unset the solo state ? */
2554 /** Start an audition of the first selected region */
2556 Editor::play_edit_range ()
2558 framepos_t start, end;
2560 if (get_edit_op_range (start, end)) {
2561 _session->request_bounded_roll (start, end);
2566 Editor::play_selected_region ()
2568 framepos_t start = max_framepos;
2571 RegionSelection rs = get_regions_from_selection_and_entered ();
2577 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
2578 if ((*i)->region()->position() < start) {
2579 start = (*i)->region()->position();
2581 if ((*i)->region()->last_frame() + 1 > end) {
2582 end = (*i)->region()->last_frame() + 1;
2586 _session->request_bounded_roll (start, end);
2590 Editor::audition_playlist_region_standalone (boost::shared_ptr<Region> region)
2592 _session->audition_region (region);
2596 Editor::region_from_selection ()
2598 if (clicked_axisview == 0) {
2602 if (selection->time.empty()) {
2606 framepos_t start = selection->time[clicked_selection].start;
2607 framepos_t end = selection->time[clicked_selection].end;
2609 TrackViewList tracks = get_tracks_for_range_action ();
2611 framepos_t selection_cnt = end - start + 1;
2613 for (TrackSelection::iterator i = tracks.begin(); i != tracks.end(); ++i) {
2614 boost::shared_ptr<Region> current;
2615 boost::shared_ptr<Playlist> pl;
2616 framepos_t internal_start;
2619 if ((pl = (*i)->playlist()) == 0) {
2623 if ((current = pl->top_region_at (start)) == 0) {
2627 internal_start = start - current->position();
2628 RegionFactory::region_name (new_name, current->name(), true);
2632 plist.add (ARDOUR::Properties::start, current->start() + internal_start);
2633 plist.add (ARDOUR::Properties::length, selection_cnt);
2634 plist.add (ARDOUR::Properties::name, new_name);
2635 plist.add (ARDOUR::Properties::layer, 0);
2637 boost::shared_ptr<Region> region (RegionFactory::create (current, plist));
2642 Editor::create_region_from_selection (vector<boost::shared_ptr<Region> >& new_regions)
2644 if (selection->time.empty() || selection->tracks.empty()) {
2648 framepos_t start = selection->time[clicked_selection].start;
2649 framepos_t end = selection->time[clicked_selection].end;
2651 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
2652 sort_track_selection (ts);
2654 for (TrackSelection::iterator i = ts.begin(); i != ts.end(); ++i) {
2655 boost::shared_ptr<Region> current;
2656 boost::shared_ptr<Playlist> playlist;
2657 framepos_t internal_start;
2660 if ((playlist = (*i)->playlist()) == 0) {
2664 if ((current = playlist->top_region_at(start)) == 0) {
2668 internal_start = start - current->position();
2669 RegionFactory::region_name (new_name, current->name(), true);
2673 plist.add (ARDOUR::Properties::start, current->start() + internal_start);
2674 plist.add (ARDOUR::Properties::length, end - start + 1);
2675 plist.add (ARDOUR::Properties::name, new_name);
2677 new_regions.push_back (RegionFactory::create (current, plist));
2682 Editor::split_multichannel_region ()
2684 RegionSelection rs = get_regions_from_selection_and_entered ();
2690 vector< boost::shared_ptr<Region> > v;
2692 for (list<RegionView*>::iterator x = rs.begin(); x != rs.end(); ++x) {
2693 (*x)->region()->separate_by_channel (*_session, v);
2698 Editor::new_region_from_selection ()
2700 region_from_selection ();
2701 cancel_selection ();
2705 add_if_covered (RegionView* rv, const AudioRange* ar, RegionSelection* rs)
2707 switch (rv->region()->coverage (ar->start, ar->end - 1)) {
2708 // n.b. -1 because AudioRange::end is one past the end, but coverage expects inclusive ranges
2709 case Evoral::OverlapNone:
2717 * - selected tracks, or if there are none...
2718 * - tracks containing selected regions, or if there are none...
2723 Editor::get_tracks_for_range_action () const
2727 if (selection->tracks.empty()) {
2729 /* use tracks with selected regions */
2731 RegionSelection rs = selection->regions;
2733 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
2734 TimeAxisView* tv = &(*i)->get_time_axis_view();
2736 if (!t.contains (tv)) {
2742 /* no regions and no tracks: use all tracks */
2748 t = selection->tracks;
2751 return t.filter_to_unique_playlists();
2755 Editor::separate_regions_between (const TimeSelection& ts)
2757 bool in_command = false;
2758 boost::shared_ptr<Playlist> playlist;
2759 RegionSelection new_selection;
2761 TrackViewList tmptracks = get_tracks_for_range_action ();
2762 sort_track_selection (tmptracks);
2764 for (TrackSelection::iterator i = tmptracks.begin(); i != tmptracks.end(); ++i) {
2766 RouteTimeAxisView* rtv;
2768 if ((rtv = dynamic_cast<RouteTimeAxisView*> ((*i))) != 0) {
2770 if (rtv->is_track()) {
2772 /* no edits to destructive tracks */
2774 if (rtv->track()->destructive()) {
2778 if ((playlist = rtv->playlist()) != 0) {
2780 playlist->clear_changes ();
2782 /* XXX need to consider musical time selections here at some point */
2784 double speed = rtv->track()->speed();
2787 for (list<AudioRange>::const_iterator t = ts.begin(); t != ts.end(); ++t) {
2789 sigc::connection c = rtv->view()->RegionViewAdded.connect (
2790 sigc::mem_fun(*this, &Editor::collect_new_region_view));
2792 latest_regionviews.clear ();
2794 playlist->partition ((framepos_t)((*t).start * speed),
2795 (framepos_t)((*t).end * speed), false);
2799 if (!latest_regionviews.empty()) {
2801 rtv->view()->foreach_regionview (sigc::bind (
2802 sigc::ptr_fun (add_if_covered),
2803 &(*t), &new_selection));
2806 begin_reversible_command (_("separate"));
2810 /* pick up changes to existing regions */
2812 vector<Command*> cmds;
2813 playlist->rdiff (cmds);
2814 _session->add_commands (cmds);
2816 /* pick up changes to the playlist itself (adds/removes)
2819 _session->add_command(new StatefulDiffCommand (playlist));
2828 // selection->set (new_selection);
2830 commit_reversible_command ();
2834 struct PlaylistState {
2835 boost::shared_ptr<Playlist> playlist;
2839 /** Take tracks from get_tracks_for_range_action and cut any regions
2840 * on those tracks so that the tracks are empty over the time
2844 Editor::separate_region_from_selection ()
2846 /* preferentially use *all* ranges in the time selection if we're in range mode
2847 to allow discontiguous operation, since get_edit_op_range() currently
2848 returns a single range.
2851 if (!selection->time.empty()) {
2853 separate_regions_between (selection->time);
2860 if (get_edit_op_range (start, end)) {
2862 AudioRange ar (start, end, 1);
2866 separate_regions_between (ts);
2872 Editor::separate_region_from_punch ()
2874 Location* loc = _session->locations()->auto_punch_location();
2876 separate_regions_using_location (*loc);
2881 Editor::separate_region_from_loop ()
2883 Location* loc = _session->locations()->auto_loop_location();
2885 separate_regions_using_location (*loc);
2890 Editor::separate_regions_using_location (Location& loc)
2892 if (loc.is_mark()) {
2896 AudioRange ar (loc.start(), loc.end(), 1);
2901 separate_regions_between (ts);
2904 /** Separate regions under the selected region */
2906 Editor::separate_under_selected_regions ()
2908 vector<PlaylistState> playlists;
2912 rs = get_regions_from_selection_and_entered();
2914 if (!_session || rs.empty()) {
2918 begin_reversible_command (_("separate region under"));
2920 list<boost::shared_ptr<Region> > regions_to_remove;
2922 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
2923 // we can't just remove the region(s) in this loop because
2924 // this removes them from the RegionSelection, and they thus
2925 // disappear from underneath the iterator, and the ++i above
2926 // SEGVs in a puzzling fashion.
2928 // so, first iterate over the regions to be removed from rs and
2929 // add them to the regions_to_remove list, and then
2930 // iterate over the list to actually remove them.
2932 regions_to_remove.push_back ((*i)->region());
2935 for (list<boost::shared_ptr<Region> >::iterator rl = regions_to_remove.begin(); rl != regions_to_remove.end(); ++rl) {
2937 boost::shared_ptr<Playlist> playlist = (*rl)->playlist();
2940 // is this check necessary?
2944 vector<PlaylistState>::iterator i;
2946 //only take state if this is a new playlist.
2947 for (i = playlists.begin(); i != playlists.end(); ++i) {
2948 if ((*i).playlist == playlist) {
2953 if (i == playlists.end()) {
2955 PlaylistState before;
2956 before.playlist = playlist;
2957 before.before = &playlist->get_state();
2959 playlist->freeze ();
2960 playlists.push_back(before);
2963 //Partition on the region bounds
2964 playlist->partition ((*rl)->first_frame() - 1, (*rl)->last_frame() + 1, true);
2966 //Re-add region that was just removed due to the partition operation
2967 playlist->add_region( (*rl), (*rl)->first_frame() );
2970 vector<PlaylistState>::iterator pl;
2972 for (pl = playlists.begin(); pl != playlists.end(); ++pl) {
2973 (*pl).playlist->thaw ();
2974 _session->add_command(new MementoCommand<Playlist>(*(*pl).playlist, (*pl).before, &(*pl).playlist->get_state()));
2977 commit_reversible_command ();
2981 Editor::crop_region_to_selection ()
2983 if (!selection->time.empty()) {
2985 crop_region_to (selection->time.start(), selection->time.end_frame());
2992 if (get_edit_op_range (start, end)) {
2993 crop_region_to (start, end);
3000 Editor::crop_region_to (framepos_t start, framepos_t end)
3002 vector<boost::shared_ptr<Playlist> > playlists;
3003 boost::shared_ptr<Playlist> playlist;
3006 if (selection->tracks.empty()) {
3007 ts = track_views.filter_to_unique_playlists();
3009 ts = selection->tracks.filter_to_unique_playlists ();
3012 sort_track_selection (ts);
3014 for (TrackSelection::iterator i = ts.begin(); i != ts.end(); ++i) {
3016 RouteTimeAxisView* rtv;
3018 if ((rtv = dynamic_cast<RouteTimeAxisView*> ((*i))) != 0) {
3020 boost::shared_ptr<Track> t = rtv->track();
3022 if (t != 0 && ! t->destructive()) {
3024 if ((playlist = rtv->playlist()) != 0) {
3025 playlists.push_back (playlist);
3031 if (playlists.empty()) {
3035 framepos_t the_start;
3039 begin_reversible_command (_("trim to selection"));
3041 for (vector<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
3043 boost::shared_ptr<Region> region;
3047 if ((region = (*i)->top_region_at(the_start)) == 0) {
3051 /* now adjust lengths to that we do the right thing
3052 if the selection extends beyond the region
3055 the_start = max (the_start, (framepos_t) region->position());
3056 if (max_framepos - the_start < region->length()) {
3057 the_end = the_start + region->length() - 1;
3059 the_end = max_framepos;
3061 the_end = min (end, the_end);
3062 cnt = the_end - the_start + 1;
3064 region->clear_changes ();
3065 region->trim_to (the_start, cnt);
3066 _session->add_command (new StatefulDiffCommand (region));
3069 commit_reversible_command ();
3073 Editor::region_fill_track ()
3075 RegionSelection rs = get_regions_from_selection_and_entered ();
3077 if (!_session || rs.empty()) {
3081 framepos_t const end = _session->current_end_frame ();
3083 begin_reversible_command (Operations::region_fill);
3085 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3087 boost::shared_ptr<Region> region ((*i)->region());
3089 boost::shared_ptr<Playlist> pl = region->playlist();
3091 if (end <= region->last_frame()) {
3095 double times = (double) (end - region->last_frame()) / (double) region->length();
3101 pl->clear_changes ();
3102 pl->add_region (RegionFactory::create (region, true), region->last_frame(), times);
3103 _session->add_command (new StatefulDiffCommand (pl));
3106 commit_reversible_command ();
3110 Editor::region_fill_selection ()
3112 if (clicked_routeview == 0 || !clicked_routeview->is_audio_track()) {
3116 if (selection->time.empty()) {
3120 boost::shared_ptr<Region> region = _regions->get_single_selection ();
3125 framepos_t start = selection->time[clicked_selection].start;
3126 framepos_t end = selection->time[clicked_selection].end;
3128 boost::shared_ptr<Playlist> playlist;
3130 if (selection->tracks.empty()) {
3134 framepos_t selection_length = end - start;
3135 float times = (float)selection_length / region->length();
3137 begin_reversible_command (Operations::fill_selection);
3139 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
3141 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
3143 if ((playlist = (*i)->playlist()) == 0) {
3147 playlist->clear_changes ();
3148 playlist->add_region (RegionFactory::create (region, true), start, times);
3149 _session->add_command (new StatefulDiffCommand (playlist));
3152 commit_reversible_command ();
3156 Editor::set_region_sync_position ()
3158 set_sync_point (get_preferred_edit_position (), get_regions_from_selection_and_edit_point ());
3162 Editor::set_sync_point (framepos_t where, const RegionSelection& rs)
3164 bool in_command = false;
3166 for (RegionSelection::const_iterator r = rs.begin(); r != rs.end(); ++r) {
3168 if (!(*r)->region()->covers (where)) {
3172 boost::shared_ptr<Region> region ((*r)->region());
3175 begin_reversible_command (_("set sync point"));
3179 region->clear_changes ();
3180 region->set_sync_position (where);
3181 _session->add_command(new StatefulDiffCommand (region));
3185 commit_reversible_command ();
3189 /** Remove the sync positions of the selection */
3191 Editor::remove_region_sync ()
3193 RegionSelection rs = get_regions_from_selection_and_entered ();
3199 begin_reversible_command (_("remove region sync"));
3201 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3203 (*i)->region()->clear_changes ();
3204 (*i)->region()->clear_sync_position ();
3205 _session->add_command(new StatefulDiffCommand ((*i)->region()));
3208 commit_reversible_command ();
3212 Editor::naturalize_region ()
3214 RegionSelection rs = get_regions_from_selection_and_entered ();
3220 if (rs.size() > 1) {
3221 begin_reversible_command (_("move regions to original position"));
3223 begin_reversible_command (_("move region to original position"));
3226 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3227 (*i)->region()->clear_changes ();
3228 (*i)->region()->move_to_natural_position ();
3229 _session->add_command (new StatefulDiffCommand ((*i)->region()));
3232 commit_reversible_command ();
3236 Editor::align_regions (RegionPoint what)
3238 RegionSelection const rs = get_regions_from_selection_and_edit_point ();
3244 begin_reversible_command (_("align selection"));
3246 framepos_t const position = get_preferred_edit_position ();
3248 for (RegionSelection::const_iterator i = rs.begin(); i != rs.end(); ++i) {
3249 align_region_internal ((*i)->region(), what, position);
3252 commit_reversible_command ();
3255 struct RegionSortByTime {
3256 bool operator() (const RegionView* a, const RegionView* b) {
3257 return a->region()->position() < b->region()->position();
3262 Editor::align_regions_relative (RegionPoint point)
3264 RegionSelection const rs = get_regions_from_selection_and_edit_point ();
3270 framepos_t const position = get_preferred_edit_position ();
3272 framepos_t distance = 0;
3276 list<RegionView*> sorted;
3277 rs.by_position (sorted);
3279 boost::shared_ptr<Region> r ((*sorted.begin())->region());
3284 if (position > r->position()) {
3285 distance = position - r->position();
3287 distance = r->position() - position;
3293 if (position > r->last_frame()) {
3294 distance = position - r->last_frame();
3295 pos = r->position() + distance;
3297 distance = r->last_frame() - position;
3298 pos = r->position() - distance;
3304 pos = r->adjust_to_sync (position);
3305 if (pos > r->position()) {
3306 distance = pos - r->position();
3308 distance = r->position() - pos;
3314 if (pos == r->position()) {
3318 begin_reversible_command (_("align selection (relative)"));
3320 /* move first one specially */
3322 r->clear_changes ();
3323 r->set_position (pos);
3324 _session->add_command(new StatefulDiffCommand (r));
3326 /* move rest by the same amount */
3330 for (list<RegionView*>::iterator i = sorted.begin(); i != sorted.end(); ++i) {
3332 boost::shared_ptr<Region> region ((*i)->region());
3334 region->clear_changes ();
3337 region->set_position (region->position() + distance);
3339 region->set_position (region->position() - distance);
3342 _session->add_command(new StatefulDiffCommand (region));
3346 commit_reversible_command ();
3350 Editor::align_region (boost::shared_ptr<Region> region, RegionPoint point, framepos_t position)
3352 begin_reversible_command (_("align region"));
3353 align_region_internal (region, point, position);
3354 commit_reversible_command ();
3358 Editor::align_region_internal (boost::shared_ptr<Region> region, RegionPoint point, framepos_t position)
3360 region->clear_changes ();
3364 region->set_position (region->adjust_to_sync (position));
3368 if (position > region->length()) {
3369 region->set_position (position - region->length());
3374 region->set_position (position);
3378 _session->add_command(new StatefulDiffCommand (region));
3382 Editor::trim_region_front ()
3388 Editor::trim_region_back ()
3390 trim_region (false);
3394 Editor::trim_region (bool front)
3396 framepos_t where = get_preferred_edit_position();
3397 RegionSelection rs = get_regions_from_selection_and_edit_point ();
3403 begin_reversible_command (front ? _("trim front") : _("trim back"));
3405 for (list<RegionView*>::const_iterator i = rs.by_layer().begin(); i != rs.by_layer().end(); ++i) {
3406 if (!(*i)->region()->locked()) {
3408 (*i)->region()->clear_changes ();
3411 (*i)->region()->trim_front (where);
3412 maybe_locate_with_edit_preroll ( where );
3414 (*i)->region()->trim_end (where);
3415 maybe_locate_with_edit_preroll ( where );
3418 _session->add_command (new StatefulDiffCommand ((*i)->region()));
3422 commit_reversible_command ();
3425 /** Trim the end of the selected regions to the position of the edit cursor */
3427 Editor::trim_region_to_loop ()
3429 Location* loc = _session->locations()->auto_loop_location();
3433 trim_region_to_location (*loc, _("trim to loop"));
3437 Editor::trim_region_to_punch ()
3439 Location* loc = _session->locations()->auto_punch_location();
3443 trim_region_to_location (*loc, _("trim to punch"));
3447 Editor::trim_region_to_location (const Location& loc, const char* str)
3449 RegionSelection rs = get_regions_from_selection_and_entered ();
3451 begin_reversible_command (str);
3453 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
3454 RegionView* rv = (*x);
3456 /* require region to span proposed trim */
3457 switch (rv->region()->coverage (loc.start(), loc.end())) {
3458 case Evoral::OverlapInternal:
3464 RouteTimeAxisView* tav = dynamic_cast<RouteTimeAxisView*> (&rv->get_time_axis_view());
3473 if (tav->track() != 0) {
3474 speed = tav->track()->speed();
3477 start = session_frame_to_track_frame (loc.start(), speed);
3478 end = session_frame_to_track_frame (loc.end(), speed);
3480 rv->region()->clear_changes ();
3481 rv->region()->trim_to (start, (end - start));
3482 _session->add_command(new StatefulDiffCommand (rv->region()));
3485 commit_reversible_command ();
3489 Editor::trim_region_to_previous_region_end ()
3491 return trim_to_region(false);
3495 Editor::trim_region_to_next_region_start ()
3497 return trim_to_region(true);
3501 Editor::trim_to_region(bool forward)
3503 RegionSelection rs = get_regions_from_selection_and_entered ();
3505 begin_reversible_command (_("trim to region"));
3507 boost::shared_ptr<Region> next_region;
3509 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
3511 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*x);
3517 AudioTimeAxisView* atav = dynamic_cast<AudioTimeAxisView*> (&arv->get_time_axis_view());
3525 if (atav->track() != 0) {
3526 speed = atav->track()->speed();
3530 boost::shared_ptr<Region> region = arv->region();
3531 boost::shared_ptr<Playlist> playlist (region->playlist());
3533 region->clear_changes ();
3537 next_region = playlist->find_next_region (region->first_frame(), Start, 1);
3543 region->trim_end((framepos_t) ( (next_region->first_frame() - 1) * speed));
3544 arv->region_changed (PropertyChange (ARDOUR::Properties::length));
3548 next_region = playlist->find_next_region (region->first_frame(), Start, 0);
3554 region->trim_front((framepos_t) ((next_region->last_frame() + 1) * speed));
3556 arv->region_changed (ARDOUR::bounds_change);
3559 _session->add_command(new StatefulDiffCommand (region));
3562 commit_reversible_command ();
3566 Editor::unfreeze_route ()
3568 if (clicked_routeview == 0 || !clicked_routeview->is_track()) {
3572 clicked_routeview->track()->unfreeze ();
3576 Editor::_freeze_thread (void* arg)
3578 return static_cast<Editor*>(arg)->freeze_thread ();
3582 Editor::freeze_thread ()
3584 /* create event pool because we may need to talk to the session */
3585 SessionEvent::create_per_thread_pool ("freeze events", 64);
3586 /* create per-thread buffers for process() tree to use */
3587 clicked_routeview->audio_track()->freeze_me (*current_interthread_info);
3588 current_interthread_info->done = true;
3593 Editor::freeze_route ()
3599 /* stop transport before we start. this is important */
3601 _session->request_transport_speed (0.0);
3603 /* wait for just a little while, because the above call is asynchronous */
3605 Glib::usleep (250000);
3607 if (clicked_routeview == 0 || !clicked_routeview->is_audio_track()) {
3611 if (!clicked_routeview->track()->bounceable (clicked_routeview->track()->main_outs(), true)) {
3613 _("This track/bus cannot be frozen because the signal adds or loses channels before reaching the outputs.\n"
3614 "This is typically caused by plugins that generate stereo output from mono input or vice versa.")
3616 d.set_title (_("Cannot freeze"));
3621 if (clicked_routeview->track()->has_external_redirects()) {
3622 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"
3623 "Freezing will only process the signal as far as the first send/insert/return."),
3624 clicked_routeview->track()->name()), true, MESSAGE_INFO, BUTTONS_NONE, true);
3626 d.add_button (_("Freeze anyway"), Gtk::RESPONSE_OK);
3627 d.add_button (_("Don't freeze"), Gtk::RESPONSE_CANCEL);
3628 d.set_title (_("Freeze Limits"));
3630 int response = d.run ();
3633 case Gtk::RESPONSE_CANCEL:
3640 InterThreadInfo itt;
3641 current_interthread_info = &itt;
3643 InterthreadProgressWindow ipw (current_interthread_info, _("Freeze"), _("Cancel Freeze"));
3645 pthread_create_and_store (X_("freezer"), &itt.thread, _freeze_thread, this);
3647 set_canvas_cursor (_cursors->wait);
3649 while (!itt.done && !itt.cancel) {
3650 gtk_main_iteration ();
3653 current_interthread_info = 0;
3654 set_canvas_cursor (current_canvas_cursor);
3658 Editor::bounce_range_selection (bool replace, bool enable_processing)
3660 if (selection->time.empty()) {
3664 TrackSelection views = selection->tracks;
3666 for (TrackViewList::iterator i = views.begin(); i != views.end(); ++i) {
3668 if (enable_processing) {
3670 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*i);
3672 if (rtv && rtv->track() && replace && enable_processing && !rtv->track()->bounceable (rtv->track()->main_outs(), false)) {
3674 _("You can't perform this operation because the processing of the signal "
3675 "will cause one or more of the tracks to end up with a region with more channels than this track has inputs.\n\n"
3676 "You can do this without processing, which is a different operation.")
3678 d.set_title (_("Cannot bounce"));
3685 framepos_t start = selection->time[clicked_selection].start;
3686 framepos_t end = selection->time[clicked_selection].end;
3687 framepos_t cnt = end - start + 1;
3689 begin_reversible_command (_("bounce range"));
3691 for (TrackViewList::iterator i = views.begin(); i != views.end(); ++i) {
3693 RouteTimeAxisView* rtv;
3695 if ((rtv = dynamic_cast<RouteTimeAxisView*> (*i)) == 0) {
3699 boost::shared_ptr<Playlist> playlist;
3701 if ((playlist = rtv->playlist()) == 0) {
3705 InterThreadInfo itt;
3707 playlist->clear_changes ();
3708 playlist->clear_owned_changes ();
3710 boost::shared_ptr<Region> r;
3712 if (enable_processing) {
3713 r = rtv->track()->bounce_range (start, start+cnt, itt, rtv->track()->main_outs(), false);
3715 r = rtv->track()->bounce_range (start, start+cnt, itt, boost::shared_ptr<Processor>(), false);
3723 list<AudioRange> ranges;
3724 ranges.push_back (AudioRange (start, start+cnt, 0));
3725 playlist->cut (ranges); // discard result
3726 playlist->add_region (r, start);
3729 vector<Command*> cmds;
3730 playlist->rdiff (cmds);
3731 _session->add_commands (cmds);
3733 _session->add_command (new StatefulDiffCommand (playlist));
3736 commit_reversible_command ();
3739 /** Delete selected regions, automation points or a time range */
3743 //special case: if the user is pointing in the editor/mixer strip, they may be trying to delete a plugin.
3744 //we need this because the editor-mixer strip is in the editor window, so it doesn't get the bindings from the mix window
3745 bool deleted = false;
3746 if ( current_mixer_strip && current_mixer_strip == MixerStrip::entered_mixer_strip() )
3747 deleted = current_mixer_strip->delete_processors ();
3753 /** Cut selected regions, automation points or a time range */
3760 /** Copy selected regions, automation points or a time range */
3768 /** @return true if a Cut, Copy or Clear is possible */
3770 Editor::can_cut_copy () const
3772 if (!selection->time.empty() || !selection->regions.empty() || !selection->points.empty())
3779 /** Cut, copy or clear selected regions, automation points or a time range.
3780 * @param op Operation (Delete, Cut, Copy or Clear)
3783 Editor::cut_copy (CutCopyOp op)
3785 /* only cancel selection if cut/copy is successful.*/
3791 opname = _("delete");
3800 opname = _("clear");
3804 /* if we're deleting something, and the mouse is still pressed,
3805 the thing we started a drag for will be gone when we release
3806 the mouse button(s). avoid this. see part 2 at the end of
3810 if (op == Delete || op == Cut || op == Clear) {
3811 if (_drags->active ()) {
3816 if ( op != Delete ) //"Delete" doesn't change copy/paste buf
3817 cut_buffer->clear ();
3819 if (entered_marker) {
3821 /* cut/delete op while pointing at a marker */
3824 Location* loc = find_location_from_marker (entered_marker, ignored);
3826 if (_session && loc) {
3827 Glib::signal_idle().connect (sigc::bind (sigc::mem_fun(*this, &Editor::really_remove_marker), loc));
3834 if (internal_editing()) {
3836 switch (effective_mouse_mode()) {
3839 begin_reversible_command (opname + ' ' + X_("MIDI"));
3841 commit_reversible_command ();
3850 bool did_edit = false;
3852 if (!selection->regions.empty() || !selection->points.empty()) {
3853 begin_reversible_command (opname + ' ' + _("objects"));
3856 if (!selection->regions.empty()) {
3857 cut_copy_regions (op, selection->regions);
3859 if (op == Cut || op == Delete) {
3860 selection->clear_regions ();
3864 if (!selection->points.empty()) {
3865 cut_copy_points (op);
3867 if (op == Cut || op == Delete) {
3868 selection->clear_points ();
3871 } else if (selection->time.empty()) {
3872 framepos_t start, end;
3873 /* no time selection, see if we can get an edit range
3876 if (get_edit_op_range (start, end)) {
3877 selection->set (start, end);
3879 } else if (!selection->time.empty()) {
3880 begin_reversible_command (opname + ' ' + _("range"));
3883 cut_copy_ranges (op);
3885 if (op == Cut || op == Delete) {
3886 selection->clear_time ();
3891 /* reset repeated paste state */
3894 commit_reversible_command ();
3897 if (op == Delete || op == Cut || op == Clear) {
3902 struct AutomationRecord {
3903 AutomationRecord () : state (0) , line(NULL) {}
3904 AutomationRecord (XMLNode* s, const AutomationLine* l) : state (s) , line (l) {}
3906 XMLNode* state; ///< state before any operation
3907 const AutomationLine* line; ///< line this came from
3908 boost::shared_ptr<Evoral::ControlList> copy; ///< copied events for the cut buffer
3911 /** Cut, copy or clear selected automation points.
3912 * @param op Operation (Cut, Copy or Clear)
3915 Editor::cut_copy_points (CutCopyOp op)
3917 if (selection->points.empty ()) {
3921 /* XXX: not ideal, as there may be more than one track involved in the point selection */
3922 _last_cut_copy_source_track = &selection->points.front()->line().trackview;
3924 /* Keep a record of the AutomationLists that we end up using in this operation */
3925 typedef std::map<boost::shared_ptr<AutomationList>, AutomationRecord> Lists;
3928 /* Go through all selected points, making an AutomationRecord for each distinct AutomationList */
3929 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
3930 const AutomationLine& line = (*i)->line();
3931 const boost::shared_ptr<AutomationList> al = line.the_list();
3932 if (lists.find (al) == lists.end ()) {
3933 /* We haven't seen this list yet, so make a record for it. This includes
3934 taking a copy of its current state, in case this is needed for undo later.
3936 lists[al] = AutomationRecord (&al->get_state (), &line);
3940 if (op == Cut || op == Copy) {
3941 /* This operation will involve putting things in the cut buffer, so create an empty
3942 ControlList for each of our source lists to put the cut buffer data in.
3944 framepos_t start = std::numeric_limits<framepos_t>::max();
3945 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
3946 i->second.copy = i->first->create (i->first->parameter (), i->first->descriptor());
3948 /* Calculate earliest start position of any point in selection. */
3949 start = std::min(start, i->second.line->session_position(i->first->begin()));
3952 /* Add all selected points to the relevant copy ControlLists */
3953 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
3954 boost::shared_ptr<AutomationList> al = (*i)->line().the_list();
3955 AutomationList::const_iterator j = (*i)->model ();
3956 lists[al].copy->fast_simple_add ((*j)->when, (*j)->value);
3959 /* Snap start time backwards, so copy/paste is snap aligned. */
3960 snap_to(start, RoundDownMaybe);
3962 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
3963 /* Correct this copy list so that it is relative to the earliest
3964 start time, so relative ordering between points is preserved
3965 when copying from several lists. */
3966 const AutomationLine* line = i->second.line;
3967 const double line_offset = line->time_converter().from(start);
3969 for (AutomationList::iterator j = i->second.copy->begin(); j != i->second.copy->end(); ++j) {
3970 (*j)->when -= line_offset;
3973 /* And add it to the cut buffer */
3974 cut_buffer->add (i->second.copy);
3978 if (op == Delete || op == Cut) {
3979 /* This operation needs to remove things from the main AutomationList, so do that now */
3981 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
3982 i->first->freeze ();
3985 /* Remove each selected point from its AutomationList */
3986 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
3987 boost::shared_ptr<AutomationList> al = (*i)->line().the_list();
3988 al->erase ((*i)->model ());
3991 /* Thaw the lists and add undo records for them */
3992 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
3993 boost::shared_ptr<AutomationList> al = i->first;
3995 _session->add_command (new MementoCommand<AutomationList> (*al.get(), i->second.state, &(al->get_state ())));
4000 /** Cut, copy or clear selected automation points.
4001 * @param op Operation (Cut, Copy or Clear)
4004 Editor::cut_copy_midi (CutCopyOp op)
4006 for (MidiRegionSelection::iterator i = selection->midi_regions.begin(); i != selection->midi_regions.end(); ++i) {
4007 MidiRegionView* mrv = dynamic_cast<MidiRegionView*>(*i);
4009 mrv->cut_copy_clear (op);
4011 /* XXX: not ideal, as there may be more than one track involved in the selection */
4012 _last_cut_copy_source_track = &mrv->get_time_axis_view();
4016 if (!selection->points.empty()) {
4017 cut_copy_points (op);
4018 if (op == Cut || op == Delete) {
4019 selection->clear_points ();
4024 struct lt_playlist {
4025 bool operator () (const PlaylistState& a, const PlaylistState& b) {
4026 return a.playlist < b.playlist;
4030 struct PlaylistMapping {
4032 boost::shared_ptr<Playlist> pl;
4034 PlaylistMapping (TimeAxisView* tvp) : tv (tvp) {}
4037 /** Remove `clicked_regionview' */
4039 Editor::remove_clicked_region ()
4041 if (clicked_routeview == 0 || clicked_regionview == 0) {
4045 begin_reversible_command (_("remove region"));
4047 boost::shared_ptr<Playlist> playlist = clicked_routeview->playlist();
4049 playlist->clear_changes ();
4050 playlist->clear_owned_changes ();
4051 playlist->remove_region (clicked_regionview->region());
4052 if (Config->get_edit_mode() == Ripple)
4053 playlist->ripple (clicked_regionview->region()->position(), -clicked_regionview->region()->length(), boost::shared_ptr<Region>());
4055 /* We might have removed regions, which alters other regions' layering_index,
4056 so we need to do a recursive diff here.
4058 vector<Command*> cmds;
4059 playlist->rdiff (cmds);
4060 _session->add_commands (cmds);
4062 _session->add_command(new StatefulDiffCommand (playlist));
4063 commit_reversible_command ();
4067 /** Remove the selected regions */
4069 Editor::remove_selected_regions ()
4071 RegionSelection rs = get_regions_from_selection_and_entered ();
4073 if (!_session || rs.empty()) {
4077 begin_reversible_command (_("remove region"));
4079 list<boost::shared_ptr<Region> > regions_to_remove;
4081 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
4082 // we can't just remove the region(s) in this loop because
4083 // this removes them from the RegionSelection, and they thus
4084 // disappear from underneath the iterator, and the ++i above
4085 // SEGVs in a puzzling fashion.
4087 // so, first iterate over the regions to be removed from rs and
4088 // add them to the regions_to_remove list, and then
4089 // iterate over the list to actually remove them.
4091 regions_to_remove.push_back ((*i)->region());
4094 vector<boost::shared_ptr<Playlist> > playlists;
4096 for (list<boost::shared_ptr<Region> >::iterator rl = regions_to_remove.begin(); rl != regions_to_remove.end(); ++rl) {
4098 boost::shared_ptr<Playlist> playlist = (*rl)->playlist();
4101 // is this check necessary?
4105 /* get_regions_from_selection_and_entered() guarantees that
4106 the playlists involved are unique, so there is no need
4110 playlists.push_back (playlist);
4112 playlist->clear_changes ();
4113 playlist->clear_owned_changes ();
4114 playlist->freeze ();
4115 playlist->remove_region (*rl);
4116 if (Config->get_edit_mode() == Ripple)
4117 playlist->ripple ((*rl)->position(), -(*rl)->length(), boost::shared_ptr<Region>());
4121 vector<boost::shared_ptr<Playlist> >::iterator pl;
4123 for (pl = playlists.begin(); pl != playlists.end(); ++pl) {
4126 /* We might have removed regions, which alters other regions' layering_index,
4127 so we need to do a recursive diff here.
4129 vector<Command*> cmds;
4130 (*pl)->rdiff (cmds);
4131 _session->add_commands (cmds);
4133 _session->add_command(new StatefulDiffCommand (*pl));
4136 commit_reversible_command ();
4139 /** Cut, copy or clear selected regions.
4140 * @param op Operation (Cut, Copy or Clear)
4143 Editor::cut_copy_regions (CutCopyOp op, RegionSelection& rs)
4145 /* we can't use a std::map here because the ordering is important, and we can't trivially sort
4146 a map when we want ordered access to both elements. i think.
4149 vector<PlaylistMapping> pmap;
4151 framepos_t first_position = max_framepos;
4153 typedef set<boost::shared_ptr<Playlist> > FreezeList;
4154 FreezeList freezelist;
4156 /* get ordering correct before we cut/copy */
4158 rs.sort_by_position_and_track ();
4160 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
4162 first_position = min ((framepos_t) (*x)->region()->position(), first_position);
4164 if (op == Cut || op == Clear || op == Delete) {
4165 boost::shared_ptr<Playlist> pl = (*x)->region()->playlist();
4168 FreezeList::iterator fl;
4170 // only take state if this is a new playlist.
4171 for (fl = freezelist.begin(); fl != freezelist.end(); ++fl) {
4177 if (fl == freezelist.end()) {
4178 pl->clear_changes();
4179 pl->clear_owned_changes ();
4181 freezelist.insert (pl);
4186 TimeAxisView* tv = &(*x)->get_time_axis_view();
4187 vector<PlaylistMapping>::iterator z;
4189 for (z = pmap.begin(); z != pmap.end(); ++z) {
4190 if ((*z).tv == tv) {
4195 if (z == pmap.end()) {
4196 pmap.push_back (PlaylistMapping (tv));
4200 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ) {
4202 boost::shared_ptr<Playlist> pl = (*x)->region()->playlist();
4205 /* region not yet associated with a playlist (e.g. unfinished
4212 TimeAxisView& tv = (*x)->get_time_axis_view();
4213 boost::shared_ptr<Playlist> npl;
4214 RegionSelection::iterator tmp;
4221 vector<PlaylistMapping>::iterator z;
4223 for (z = pmap.begin(); z != pmap.end(); ++z) {
4224 if ((*z).tv == &tv) {
4229 assert (z != pmap.end());
4232 npl = PlaylistFactory::create (pl->data_type(), *_session, "cutlist", true);
4240 boost::shared_ptr<Region> r = (*x)->region();
4241 boost::shared_ptr<Region> _xx;
4247 pl->remove_region (r);
4248 if (Config->get_edit_mode() == Ripple)
4249 pl->ripple (r->position(), -r->length(), boost::shared_ptr<Region>());
4253 _xx = RegionFactory::create (r);
4254 npl->add_region (_xx, r->position() - first_position);
4255 pl->remove_region (r);
4256 if (Config->get_edit_mode() == Ripple)
4257 pl->ripple (r->position(), -r->length(), boost::shared_ptr<Region>());
4261 /* copy region before adding, so we're not putting same object into two different playlists */
4262 npl->add_region (RegionFactory::create (r), r->position() - first_position);
4266 pl->remove_region (r);
4267 if (Config->get_edit_mode() == Ripple)
4268 pl->ripple (r->position(), -r->length(), boost::shared_ptr<Region>());
4277 list<boost::shared_ptr<Playlist> > foo;
4279 /* the pmap is in the same order as the tracks in which selected regions occured */
4281 for (vector<PlaylistMapping>::iterator i = pmap.begin(); i != pmap.end(); ++i) {
4284 foo.push_back ((*i).pl);
4289 cut_buffer->set (foo);
4293 _last_cut_copy_source_track = 0;
4295 _last_cut_copy_source_track = pmap.front().tv;
4299 for (FreezeList::iterator pl = freezelist.begin(); pl != freezelist.end(); ++pl) {
4302 /* We might have removed regions, which alters other regions' layering_index,
4303 so we need to do a recursive diff here.
4305 vector<Command*> cmds;
4306 (*pl)->rdiff (cmds);
4307 _session->add_commands (cmds);
4309 _session->add_command (new StatefulDiffCommand (*pl));
4314 Editor::cut_copy_ranges (CutCopyOp op)
4316 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4318 /* Sort the track selection now, so that it if is used, the playlists
4319 selected by the calls below to cut_copy_clear are in the order that
4320 their tracks appear in the editor. This makes things like paste
4321 of ranges work properly.
4324 sort_track_selection (ts);
4327 if (!entered_track) {
4330 ts.push_back (entered_track);
4333 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4334 (*i)->cut_copy_clear (*selection, op);
4339 Editor::paste (float times, bool from_context)
4341 DEBUG_TRACE (DEBUG::CutNPaste, "paste to preferred edit pos\n");
4343 paste_internal (get_preferred_edit_position (false, from_context), times);
4347 Editor::mouse_paste ()
4352 if (!mouse_frame (where, ignored)) {
4357 paste_internal (where, 1);
4361 Editor::paste_internal (framepos_t position, float times)
4363 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("apparent paste position is %1\n", position));
4365 if (cut_buffer->empty(internal_editing())) {
4369 if (position == max_framepos) {
4370 position = get_preferred_edit_position();
4371 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("preferred edit position is %1\n", position));
4374 if (position == last_paste_pos) {
4375 /* repeated paste in the same position */
4378 /* paste in new location, reset repeated paste state */
4380 last_paste_pos = position;
4383 /* get everything in the correct order */
4386 if (!selection->tracks.empty()) {
4387 /* If there is a track selection, paste into exactly those tracks and
4388 only those tracks. This allows the user to be explicit and override
4389 the below "do the reasonable thing" logic. */
4390 ts = selection->tracks.filter_to_unique_playlists ();
4391 sort_track_selection (ts);
4393 /* Figure out which track to base the paste at. */
4394 TimeAxisView* base_track = NULL;
4395 if (_edit_point == Editing::EditAtMouse && entered_track) {
4396 /* With the mouse edit point, paste onto the track under the mouse. */
4397 base_track = entered_track;
4398 } else if (_edit_point == Editing::EditAtMouse && entered_regionview) {
4399 /* With the mouse edit point, paste onto the track of the region under the mouse. */
4400 base_track = &entered_regionview->get_time_axis_view();
4401 } else if (_last_cut_copy_source_track) {
4402 /* Paste to the track that the cut/copy came from (see mantis #333). */
4403 base_track = _last_cut_copy_source_track;
4405 /* This is "impossible" since we've copied... well, do nothing. */
4409 /* Walk up to parent if necessary, so base track is a route. */
4410 while (base_track->get_parent()) {
4411 base_track = base_track->get_parent();
4414 /* Add base track and all tracks below it. The paste logic will select
4415 the appropriate object types from the cut buffer in relative order. */
4416 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4417 if ((*i)->order() >= base_track->order()) {
4422 /* Sort tracks so the nth track of type T will pick the nth object of type T. */
4423 sort_track_selection (ts);
4425 /* Add automation children of each track in order, for pasting several lines. */
4426 for (TrackViewList::iterator i = ts.begin(); i != ts.end();) {
4427 /* Add any automation children for pasting several lines */
4428 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*i++);
4433 typedef RouteTimeAxisView::AutomationTracks ATracks;
4434 const ATracks& atracks = rtv->automation_tracks();
4435 for (ATracks::const_iterator a = atracks.begin(); a != atracks.end(); ++a) {
4436 i = ts.insert(i, a->second.get());
4441 /* We now have a list of trackviews starting at base_track, including
4442 automation children, in the order shown in the editor, e.g. R1,
4443 R1.A1, R1.A2, R2, R2.A1, ... */
4446 if (ts.size() == 1 && cut_buffer->lines.size() == 1 &&
4447 dynamic_cast<AutomationTimeAxisView*>(ts.front())) {
4448 /* Only one line copied, and one automation track selected. Do a
4449 "greedy" paste from one automation type to another. */
4451 begin_reversible_command (Operations::paste);
4453 PasteContext ctx(paste_count, times, ItemCounts(), true);
4454 ts.front()->paste (position, *cut_buffer, ctx);
4456 commit_reversible_command ();
4458 } else if (internal_editing ()) {
4460 /* undo/redo is handled by individual tracks/regions */
4463 get_regions_at (rs, position, ts);
4465 PasteContext ctx(paste_count, times, ItemCounts(), false);
4466 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
4467 MidiRegionView* mrv = dynamic_cast<MidiRegionView*> (*r);
4469 mrv->paste (position, *cut_buffer, ctx);
4475 /* we do redo (do you do voodoo?) */
4477 begin_reversible_command (Operations::paste);
4479 PasteContext ctx(paste_count, times, ItemCounts(), false);
4480 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4481 (*i)->paste (position, *cut_buffer, ctx);
4484 commit_reversible_command ();
4489 Editor::duplicate_some_regions (RegionSelection& regions, float times)
4491 boost::shared_ptr<Playlist> playlist;
4492 RegionSelection sel = regions; // clear (below) may clear the argument list if its the current region selection
4493 RegionSelection foo;
4495 framepos_t const start_frame = regions.start ();
4496 framepos_t const end_frame = regions.end_frame ();
4498 begin_reversible_command (Operations::duplicate_region);
4500 selection->clear_regions ();
4502 for (RegionSelection::iterator i = sel.begin(); i != sel.end(); ++i) {
4504 boost::shared_ptr<Region> r ((*i)->region());
4506 TimeAxisView& tv = (*i)->get_time_axis_view();
4507 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (&tv);
4508 latest_regionviews.clear ();
4509 sigc::connection c = rtv->view()->RegionViewAdded.connect (sigc::mem_fun(*this, &Editor::collect_new_region_view));
4511 playlist = (*i)->region()->playlist();
4512 playlist->clear_changes ();
4513 playlist->duplicate (r, end_frame + (r->first_frame() - start_frame), times);
4514 _session->add_command(new StatefulDiffCommand (playlist));
4518 foo.insert (foo.end(), latest_regionviews.begin(), latest_regionviews.end());
4521 commit_reversible_command ();
4524 selection->set (foo);
4529 Editor::duplicate_selection (float times)
4531 if (selection->time.empty() || selection->tracks.empty()) {
4535 boost::shared_ptr<Playlist> playlist;
4536 vector<boost::shared_ptr<Region> > new_regions;
4537 vector<boost::shared_ptr<Region> >::iterator ri;
4539 create_region_from_selection (new_regions);
4541 if (new_regions.empty()) {
4545 begin_reversible_command (_("duplicate selection"));
4547 ri = new_regions.begin();
4549 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4551 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4552 if ((playlist = (*i)->playlist()) == 0) {
4555 playlist->clear_changes ();
4556 playlist->duplicate (*ri, selection->time[clicked_selection].end, times);
4557 _session->add_command (new StatefulDiffCommand (playlist));
4560 if (ri == new_regions.end()) {
4565 commit_reversible_command ();
4568 /** Reset all selected points to the relevant default value */
4570 Editor::reset_point_selection ()
4572 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
4573 ARDOUR::AutomationList::iterator j = (*i)->model ();
4574 (*j)->value = (*i)->line().the_list()->default_value ();
4579 Editor::center_playhead ()
4581 float const page = _visible_canvas_width * samples_per_pixel;
4582 center_screen_internal (playhead_cursor->current_frame (), page);
4586 Editor::center_edit_point ()
4588 float const page = _visible_canvas_width * samples_per_pixel;
4589 center_screen_internal (get_preferred_edit_position(), page);
4592 /** Caller must begin and commit a reversible command */
4594 Editor::clear_playlist (boost::shared_ptr<Playlist> playlist)
4596 playlist->clear_changes ();
4598 _session->add_command (new StatefulDiffCommand (playlist));
4602 Editor::nudge_track (bool use_edit, bool forwards)
4604 boost::shared_ptr<Playlist> playlist;
4605 framepos_t distance;
4606 framepos_t next_distance;
4610 start = get_preferred_edit_position();
4615 if ((distance = get_nudge_distance (start, next_distance)) == 0) {
4619 if (selection->tracks.empty()) {
4623 begin_reversible_command (_("nudge track"));
4625 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4627 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4629 if ((playlist = (*i)->playlist()) == 0) {
4633 playlist->clear_changes ();
4634 playlist->clear_owned_changes ();
4636 playlist->nudge_after (start, distance, forwards);
4638 vector<Command*> cmds;
4640 playlist->rdiff (cmds);
4641 _session->add_commands (cmds);
4643 _session->add_command (new StatefulDiffCommand (playlist));
4646 commit_reversible_command ();
4650 Editor::remove_last_capture ()
4652 vector<string> choices;
4659 if (Config->get_verify_remove_last_capture()) {
4660 prompt = _("Do you really want to destroy the last capture?"
4661 "\n(This is destructive and cannot be undone)");
4663 choices.push_back (_("No, do nothing."));
4664 choices.push_back (_("Yes, destroy it."));
4666 Gtkmm2ext::Choice prompter (_("Destroy last capture"), prompt, choices);
4668 if (prompter.run () == 1) {
4669 _session->remove_last_capture ();
4670 _regions->redisplay ();
4674 _session->remove_last_capture();
4675 _regions->redisplay ();
4680 Editor::normalize_region ()
4686 RegionSelection rs = get_regions_from_selection_and_entered ();
4692 NormalizeDialog dialog (rs.size() > 1);
4694 if (dialog.run () == RESPONSE_CANCEL) {
4698 set_canvas_cursor (_cursors->wait);
4701 /* XXX: should really only count audio regions here */
4702 int const regions = rs.size ();
4704 /* Make a list of the selected audio regions' maximum amplitudes, and also
4705 obtain the maximum amplitude of them all.
4707 list<double> max_amps;
4709 for (RegionSelection::const_iterator i = rs.begin(); i != rs.end(); ++i) {
4710 AudioRegionView const * arv = dynamic_cast<AudioRegionView const *> (*i);
4712 dialog.descend (1.0 / regions);
4713 double const a = arv->audio_region()->maximum_amplitude (&dialog);
4716 /* the user cancelled the operation */
4717 set_canvas_cursor (current_canvas_cursor);
4721 max_amps.push_back (a);
4722 max_amp = max (max_amp, a);
4727 begin_reversible_command (_("normalize"));
4729 list<double>::const_iterator a = max_amps.begin ();
4731 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
4732 AudioRegionView* const arv = dynamic_cast<AudioRegionView*> (*r);
4737 arv->region()->clear_changes ();
4739 double const amp = dialog.normalize_individually() ? *a : max_amp;
4741 arv->audio_region()->normalize (amp, dialog.target ());
4742 _session->add_command (new StatefulDiffCommand (arv->region()));
4747 commit_reversible_command ();
4748 set_canvas_cursor (current_canvas_cursor);
4753 Editor::reset_region_scale_amplitude ()
4759 RegionSelection rs = get_regions_from_selection_and_entered ();
4765 begin_reversible_command ("reset gain");
4767 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
4768 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
4771 arv->region()->clear_changes ();
4772 arv->audio_region()->set_scale_amplitude (1.0f);
4773 _session->add_command (new StatefulDiffCommand (arv->region()));
4776 commit_reversible_command ();
4780 Editor::adjust_region_gain (bool up)
4782 RegionSelection rs = get_regions_from_selection_and_entered ();
4784 if (!_session || rs.empty()) {
4788 begin_reversible_command ("adjust region gain");
4790 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
4791 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
4796 arv->region()->clear_changes ();
4798 double dB = accurate_coefficient_to_dB (arv->audio_region()->scale_amplitude ());
4806 arv->audio_region()->set_scale_amplitude (dB_to_coefficient (dB));
4807 _session->add_command (new StatefulDiffCommand (arv->region()));
4810 commit_reversible_command ();
4815 Editor::reverse_region ()
4821 Reverse rev (*_session);
4822 apply_filter (rev, _("reverse regions"));
4826 Editor::strip_region_silence ()
4832 RegionSelection rs = get_regions_from_selection_and_entered ();
4838 std::list<RegionView*> audio_only;
4840 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
4841 AudioRegionView* const arv = dynamic_cast<AudioRegionView*> (*i);
4843 audio_only.push_back (arv);
4847 StripSilenceDialog d (_session, audio_only);
4848 int const r = d.run ();
4852 if (r == Gtk::RESPONSE_OK) {
4853 ARDOUR::AudioIntervalMap silences;
4854 d.silences (silences);
4855 StripSilence s (*_session, silences, d.fade_length());
4856 apply_filter (s, _("strip silence"), &d);
4861 Editor::apply_midi_note_edit_op_to_region (MidiOperator& op, MidiRegionView& mrv)
4863 Evoral::Sequence<Evoral::MusicalTime>::Notes selected;
4864 mrv.selection_as_notelist (selected, true);
4866 vector<Evoral::Sequence<Evoral::MusicalTime>::Notes> v;
4867 v.push_back (selected);
4869 framepos_t pos_frames = mrv.midi_region()->position() - mrv.midi_region()->start();
4870 Evoral::MusicalTime pos_beats = _session->tempo_map().framewalk_to_beats(0, pos_frames);
4872 return op (mrv.midi_region()->model(), pos_beats, v);
4876 Editor::apply_midi_note_edit_op (MidiOperator& op)
4880 RegionSelection rs = get_regions_from_selection_and_entered ();
4886 begin_reversible_command (op.name ());
4888 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
4889 RegionSelection::iterator tmp = r;
4892 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*r);
4895 cmd = apply_midi_note_edit_op_to_region (op, *mrv);
4898 _session->add_command (cmd);
4905 commit_reversible_command ();
4909 Editor::fork_region ()
4911 RegionSelection rs = get_regions_from_selection_and_entered ();
4917 begin_reversible_command (_("Fork Region(s)"));
4919 set_canvas_cursor (_cursors->wait);
4922 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
4923 RegionSelection::iterator tmp = r;
4926 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*>(*r);
4930 boost::shared_ptr<Playlist> playlist = mrv->region()->playlist();
4931 boost::shared_ptr<MidiSource> new_source = _session->create_midi_source_by_stealing_name (mrv->midi_view()->track());
4932 boost::shared_ptr<MidiRegion> newregion = mrv->midi_region()->clone (new_source);
4934 playlist->clear_changes ();
4935 playlist->replace_region (mrv->region(), newregion, mrv->region()->position());
4936 _session->add_command(new StatefulDiffCommand (playlist));
4938 error << string_compose (_("Could not unlink %1"), mrv->region()->name()) << endmsg;
4945 commit_reversible_command ();
4947 set_canvas_cursor (current_canvas_cursor);
4951 Editor::quantize_region ()
4953 int selected_midi_region_cnt = 0;
4959 RegionSelection rs = get_regions_from_selection_and_entered ();
4965 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
4966 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*r);
4968 selected_midi_region_cnt++;
4972 if (selected_midi_region_cnt == 0) {
4976 QuantizeDialog* qd = new QuantizeDialog (*this);
4979 const int r = qd->run ();
4982 if (r == Gtk::RESPONSE_OK) {
4983 Quantize quant (qd->snap_start(), qd->snap_end(),
4984 qd->start_grid_size(), qd->end_grid_size(),
4985 qd->strength(), qd->swing(), qd->threshold());
4987 apply_midi_note_edit_op (quant);
4992 Editor::legatize_region (bool shrink_only)
4994 int selected_midi_region_cnt = 0;
5000 RegionSelection rs = get_regions_from_selection_and_entered ();
5006 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
5007 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*r);
5009 selected_midi_region_cnt++;
5013 if (selected_midi_region_cnt == 0) {
5017 Legatize legatize(shrink_only);
5018 apply_midi_note_edit_op (legatize);
5022 Editor::insert_patch_change (bool from_context)
5024 RegionSelection rs = get_regions_from_selection_and_entered ();
5030 const framepos_t p = get_preferred_edit_position (false, from_context);
5032 /* XXX: bit of a hack; use the MIDNAM from the first selected region;
5033 there may be more than one, but the PatchChangeDialog can only offer
5034 one set of patch menus.
5036 MidiRegionView* first = dynamic_cast<MidiRegionView*> (rs.front ());
5038 Evoral::PatchChange<Evoral::MusicalTime> empty (Evoral::MusicalTime(), 0, 0, 0);
5039 PatchChangeDialog d (0, _session, empty, first->instrument_info(), Gtk::Stock::ADD);
5041 if (d.run() == RESPONSE_CANCEL) {
5045 for (RegionSelection::iterator i = rs.begin (); i != rs.end(); ++i) {
5046 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*i);
5048 if (p >= mrv->region()->first_frame() && p <= mrv->region()->last_frame()) {
5049 mrv->add_patch_change (p - mrv->region()->position(), d.patch ());
5056 Editor::apply_filter (Filter& filter, string command, ProgressReporter* progress)
5058 RegionSelection rs = get_regions_from_selection_and_entered ();
5064 begin_reversible_command (command);
5066 set_canvas_cursor (_cursors->wait);
5070 int const N = rs.size ();
5072 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
5073 RegionSelection::iterator tmp = r;
5076 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
5078 boost::shared_ptr<Playlist> playlist = arv->region()->playlist();
5081 progress->descend (1.0 / N);
5084 if (arv->audio_region()->apply (filter, progress) == 0) {
5086 playlist->clear_changes ();
5087 playlist->clear_owned_changes ();
5089 if (filter.results.empty ()) {
5091 /* no regions returned; remove the old one */
5092 playlist->remove_region (arv->region ());
5096 std::vector<boost::shared_ptr<Region> >::iterator res = filter.results.begin ();
5098 /* first region replaces the old one */
5099 playlist->replace_region (arv->region(), *res, (*res)->position());
5103 while (res != filter.results.end()) {
5104 playlist->add_region (*res, (*res)->position());
5110 /* We might have removed regions, which alters other regions' layering_index,
5111 so we need to do a recursive diff here.
5113 vector<Command*> cmds;
5114 playlist->rdiff (cmds);
5115 _session->add_commands (cmds);
5117 _session->add_command(new StatefulDiffCommand (playlist));
5123 progress->ascend ();
5131 commit_reversible_command ();
5134 set_canvas_cursor (current_canvas_cursor);
5138 Editor::external_edit_region ()
5144 Editor::reset_region_gain_envelopes ()
5146 RegionSelection rs = get_regions_from_selection_and_entered ();
5148 if (!_session || rs.empty()) {
5152 _session->begin_reversible_command (_("reset region gain"));
5154 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5155 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
5157 boost::shared_ptr<AutomationList> alist (arv->audio_region()->envelope());
5158 XMLNode& before (alist->get_state());
5160 arv->audio_region()->set_default_envelope ();
5161 _session->add_command (new MementoCommand<AutomationList>(*arv->audio_region()->envelope().get(), &before, &alist->get_state()));
5165 _session->commit_reversible_command ();
5169 Editor::set_region_gain_visibility (RegionView* rv)
5171 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (rv);
5173 arv->update_envelope_visibility();
5178 Editor::set_gain_envelope_visibility ()
5184 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5185 AudioTimeAxisView* v = dynamic_cast<AudioTimeAxisView*>(*i);
5187 v->audio_view()->foreach_regionview (sigc::mem_fun (this, &Editor::set_region_gain_visibility));
5193 Editor::toggle_gain_envelope_active ()
5195 if (_ignore_region_action) {
5199 RegionSelection rs = get_regions_from_selection_and_entered ();
5201 if (!_session || rs.empty()) {
5205 _session->begin_reversible_command (_("region gain envelope active"));
5207 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5208 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
5210 arv->region()->clear_changes ();
5211 arv->audio_region()->set_envelope_active (!arv->audio_region()->envelope_active());
5212 _session->add_command (new StatefulDiffCommand (arv->region()));
5216 _session->commit_reversible_command ();
5220 Editor::toggle_region_lock ()
5222 if (_ignore_region_action) {
5226 RegionSelection rs = get_regions_from_selection_and_entered ();
5228 if (!_session || rs.empty()) {
5232 _session->begin_reversible_command (_("toggle region lock"));
5234 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5235 (*i)->region()->clear_changes ();
5236 (*i)->region()->set_locked (!(*i)->region()->locked());
5237 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5240 _session->commit_reversible_command ();
5244 Editor::toggle_region_video_lock ()
5246 if (_ignore_region_action) {
5250 RegionSelection rs = get_regions_from_selection_and_entered ();
5252 if (!_session || rs.empty()) {
5256 _session->begin_reversible_command (_("Toggle Video Lock"));
5258 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5259 (*i)->region()->clear_changes ();
5260 (*i)->region()->set_video_locked (!(*i)->region()->video_locked());
5261 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5264 _session->commit_reversible_command ();
5268 Editor::toggle_region_lock_style ()
5270 if (_ignore_region_action) {
5274 RegionSelection rs = get_regions_from_selection_and_entered ();
5276 if (!_session || rs.empty()) {
5280 _session->begin_reversible_command (_("region lock style"));
5282 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5283 (*i)->region()->clear_changes ();
5284 PositionLockStyle const ns = (*i)->region()->position_lock_style() == AudioTime ? MusicTime : AudioTime;
5285 (*i)->region()->set_position_lock_style (ns);
5286 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5289 _session->commit_reversible_command ();
5293 Editor::toggle_opaque_region ()
5295 if (_ignore_region_action) {
5299 RegionSelection rs = get_regions_from_selection_and_entered ();
5301 if (!_session || rs.empty()) {
5305 _session->begin_reversible_command (_("change region opacity"));
5307 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5308 (*i)->region()->clear_changes ();
5309 (*i)->region()->set_opaque (!(*i)->region()->opaque());
5310 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5313 _session->commit_reversible_command ();
5317 Editor::toggle_record_enable ()
5319 bool new_state = false;
5321 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5322 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5325 if (!rtav->is_track())
5329 new_state = !rtav->track()->record_enabled();
5333 rtav->track()->set_record_enabled (new_state, this);
5338 Editor::toggle_solo ()
5340 bool new_state = false;
5342 boost::shared_ptr<RouteList> rl (new RouteList);
5344 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5345 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5352 new_state = !rtav->route()->soloed ();
5356 rl->push_back (rtav->route());
5359 _session->set_solo (rl, new_state, Session::rt_cleanup, true);
5363 Editor::toggle_mute ()
5365 bool new_state = false;
5367 boost::shared_ptr<RouteList> rl (new RouteList);
5369 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5370 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5377 new_state = !rtav->route()->muted();
5381 rl->push_back (rtav->route());
5384 _session->set_mute (rl, new_state, Session::rt_cleanup, true);
5388 Editor::toggle_solo_isolate ()
5394 Editor::fade_range ()
5396 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
5398 begin_reversible_command (_("fade range"));
5400 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
5401 (*i)->fade_range (selection->time);
5404 commit_reversible_command ();
5409 Editor::set_fade_length (bool in)
5411 RegionSelection rs = get_regions_from_selection_and_entered ();
5417 /* we need a region to measure the offset from the start */
5419 RegionView* rv = rs.front ();
5421 framepos_t pos = get_preferred_edit_position();
5425 if (pos > rv->region()->last_frame() || pos < rv->region()->first_frame()) {
5426 /* edit point is outside the relevant region */
5431 if (pos <= rv->region()->position()) {
5435 len = pos - rv->region()->position();
5436 cmd = _("set fade in length");
5438 if (pos >= rv->region()->last_frame()) {
5442 len = rv->region()->last_frame() - pos;
5443 cmd = _("set fade out length");
5446 begin_reversible_command (cmd);
5448 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5449 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5455 boost::shared_ptr<AutomationList> alist;
5457 alist = tmp->audio_region()->fade_in();
5459 alist = tmp->audio_region()->fade_out();
5462 XMLNode &before = alist->get_state();
5465 tmp->audio_region()->set_fade_in_length (len);
5466 tmp->audio_region()->set_fade_in_active (true);
5468 tmp->audio_region()->set_fade_out_length (len);
5469 tmp->audio_region()->set_fade_out_active (true);
5472 XMLNode &after = alist->get_state();
5473 _session->add_command(new MementoCommand<AutomationList>(*alist, &before, &after));
5476 commit_reversible_command ();
5480 Editor::set_fade_in_shape (FadeShape shape)
5482 RegionSelection rs = get_regions_from_selection_and_entered ();
5488 begin_reversible_command (_("set fade in shape"));
5490 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5491 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5497 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_in();
5498 XMLNode &before = alist->get_state();
5500 tmp->audio_region()->set_fade_in_shape (shape);
5502 XMLNode &after = alist->get_state();
5503 _session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
5506 commit_reversible_command ();
5511 Editor::set_fade_out_shape (FadeShape shape)
5513 RegionSelection rs = get_regions_from_selection_and_entered ();
5519 begin_reversible_command (_("set fade out shape"));
5521 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5522 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5528 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_out();
5529 XMLNode &before = alist->get_state();
5531 tmp->audio_region()->set_fade_out_shape (shape);
5533 XMLNode &after = alist->get_state();
5534 _session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
5537 commit_reversible_command ();
5541 Editor::set_fade_in_active (bool yn)
5543 RegionSelection rs = get_regions_from_selection_and_entered ();
5549 begin_reversible_command (_("set fade in active"));
5551 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5552 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5559 boost::shared_ptr<AudioRegion> ar (tmp->audio_region());
5561 ar->clear_changes ();
5562 ar->set_fade_in_active (yn);
5563 _session->add_command (new StatefulDiffCommand (ar));
5566 commit_reversible_command ();
5570 Editor::set_fade_out_active (bool yn)
5572 RegionSelection rs = get_regions_from_selection_and_entered ();
5578 begin_reversible_command (_("set fade out active"));
5580 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5581 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5587 boost::shared_ptr<AudioRegion> ar (tmp->audio_region());
5589 ar->clear_changes ();
5590 ar->set_fade_out_active (yn);
5591 _session->add_command(new StatefulDiffCommand (ar));
5594 commit_reversible_command ();
5598 Editor::toggle_region_fades (int dir)
5600 if (_ignore_region_action) {
5604 boost::shared_ptr<AudioRegion> ar;
5607 RegionSelection rs = get_regions_from_selection_and_entered ();
5613 RegionSelection::iterator i;
5614 for (i = rs.begin(); i != rs.end(); ++i) {
5615 if ((ar = boost::dynamic_pointer_cast<AudioRegion>((*i)->region())) != 0) {
5617 yn = ar->fade_out_active ();
5619 yn = ar->fade_in_active ();
5625 if (i == rs.end()) {
5629 /* XXX should this undo-able? */
5631 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5632 if ((ar = boost::dynamic_pointer_cast<AudioRegion>((*i)->region())) == 0) {
5635 if (dir == 1 || dir == 0) {
5636 ar->set_fade_in_active (!yn);
5639 if (dir == -1 || dir == 0) {
5640 ar->set_fade_out_active (!yn);
5646 /** Update region fade visibility after its configuration has been changed */
5648 Editor::update_region_fade_visibility ()
5650 bool _fade_visibility = _session->config.get_show_region_fades ();
5652 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5653 AudioTimeAxisView* v = dynamic_cast<AudioTimeAxisView*>(*i);
5655 if (_fade_visibility) {
5656 v->audio_view()->show_all_fades ();
5658 v->audio_view()->hide_all_fades ();
5665 Editor::set_edit_point ()
5670 if (!mouse_frame (where, ignored)) {
5676 if (selection->markers.empty()) {
5678 mouse_add_new_marker (where);
5683 Location* loc = find_location_from_marker (selection->markers.front(), ignored);
5686 loc->move_to (where);
5692 Editor::set_playhead_cursor ()
5694 if (entered_marker) {
5695 _session->request_locate (entered_marker->position(), _session->transport_rolling());
5700 if (!mouse_frame (where, ignored)) {
5707 _session->request_locate (where, _session->transport_rolling());
5711 if ( Config->get_follow_edits() )
5712 cancel_time_selection();
5716 Editor::split_region ()
5718 if ( !selection->time.empty()) {
5719 separate_regions_between (selection->time);
5723 RegionSelection rs = get_regions_from_selection_and_edit_point ();
5725 framepos_t where = get_preferred_edit_position ();
5731 split_regions_at (where, rs);
5734 struct EditorOrderRouteSorter {
5735 bool operator() (boost::shared_ptr<Route> a, boost::shared_ptr<Route> b) {
5736 return a->order_key () < b->order_key ();
5741 Editor::select_next_route()
5743 if (selection->tracks.empty()) {
5744 selection->set (track_views.front());
5748 TimeAxisView* current = selection->tracks.front();
5752 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5753 if (*i == current) {
5755 if (i != track_views.end()) {
5758 current = (*(track_views.begin()));
5759 //selection->set (*(track_views.begin()));
5764 rui = dynamic_cast<RouteUI *>(current);
5765 } while ( current->hidden() || (rui != NULL && !rui->route()->active()));
5767 selection->set(current);
5769 ensure_time_axis_view_is_visible (*current, false);
5773 Editor::select_prev_route()
5775 if (selection->tracks.empty()) {
5776 selection->set (track_views.front());
5780 TimeAxisView* current = selection->tracks.front();
5784 for (TrackViewList::reverse_iterator i = track_views.rbegin(); i != track_views.rend(); ++i) {
5785 if (*i == current) {
5787 if (i != track_views.rend()) {
5790 current = *(track_views.rbegin());
5795 rui = dynamic_cast<RouteUI *>(current);
5796 } while ( current->hidden() || (rui != NULL && !rui->route()->active()));
5798 selection->set (current);
5800 ensure_time_axis_view_is_visible (*current, false);
5804 Editor::set_loop_from_selection (bool play)
5806 if (_session == 0 || selection->time.empty()) {
5810 framepos_t start = selection->time[clicked_selection].start;
5811 framepos_t end = selection->time[clicked_selection].end;
5813 set_loop_range (start, end, _("set loop range from selection"));
5816 _session->request_locate (start, true);
5817 _session->request_play_loop (true);
5822 Editor::set_loop_from_edit_range (bool play)
5824 if (_session == 0) {
5831 if (!get_edit_op_range (start, end)) {
5835 set_loop_range (start, end, _("set loop range from edit range"));
5838 _session->request_locate (start, true);
5839 _session->request_play_loop (true);
5844 Editor::set_loop_from_region (bool play)
5846 framepos_t start = max_framepos;
5849 RegionSelection rs = get_regions_from_selection_and_entered ();
5855 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5856 if ((*i)->region()->position() < start) {
5857 start = (*i)->region()->position();
5859 if ((*i)->region()->last_frame() + 1 > end) {
5860 end = (*i)->region()->last_frame() + 1;
5864 set_loop_range (start, end, _("set loop range from region"));
5867 _session->request_locate (start, true);
5868 _session->request_play_loop (true);
5873 Editor::set_punch_from_selection ()
5875 if (_session == 0 || selection->time.empty()) {
5879 framepos_t start = selection->time[clicked_selection].start;
5880 framepos_t end = selection->time[clicked_selection].end;
5882 set_punch_range (start, end, _("set punch range from selection"));
5886 Editor::set_punch_from_edit_range ()
5888 if (_session == 0) {
5895 if (!get_edit_op_range (start, end)) {
5899 set_punch_range (start, end, _("set punch range from edit range"));
5903 Editor::set_punch_from_region ()
5905 framepos_t start = max_framepos;
5908 RegionSelection rs = get_regions_from_selection_and_entered ();
5914 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5915 if ((*i)->region()->position() < start) {
5916 start = (*i)->region()->position();
5918 if ((*i)->region()->last_frame() + 1 > end) {
5919 end = (*i)->region()->last_frame() + 1;
5923 set_punch_range (start, end, _("set punch range from region"));
5927 Editor::pitch_shift_region ()
5929 RegionSelection rs = get_regions_from_selection_and_entered ();
5931 RegionSelection audio_rs;
5932 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5933 if (dynamic_cast<AudioRegionView*> (*i)) {
5934 audio_rs.push_back (*i);
5938 if (audio_rs.empty()) {
5942 pitch_shift (audio_rs, 1.2);
5946 Editor::transpose_region ()
5948 RegionSelection rs = get_regions_from_selection_and_entered ();
5950 list<MidiRegionView*> midi_region_views;
5951 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5952 MidiRegionView* mrv = dynamic_cast<MidiRegionView*> (*i);
5954 midi_region_views.push_back (mrv);
5959 int const r = d.run ();
5960 if (r != RESPONSE_ACCEPT) {
5964 for (list<MidiRegionView*>::iterator i = midi_region_views.begin(); i != midi_region_views.end(); ++i) {
5965 (*i)->midi_region()->transpose (d.semitones ());
5970 Editor::set_tempo_from_region ()
5972 RegionSelection rs = get_regions_from_selection_and_entered ();
5974 if (!_session || rs.empty()) {
5978 RegionView* rv = rs.front();
5980 define_one_bar (rv->region()->position(), rv->region()->last_frame() + 1);
5984 Editor::use_range_as_bar ()
5986 framepos_t start, end;
5987 if (get_edit_op_range (start, end)) {
5988 define_one_bar (start, end);
5993 Editor::define_one_bar (framepos_t start, framepos_t end)
5995 framepos_t length = end - start;
5997 const Meter& m (_session->tempo_map().meter_at (start));
5999 /* length = 1 bar */
6001 /* now we want frames per beat.
6002 we have frames per bar, and beats per bar, so ...
6005 /* XXXX METER MATH */
6007 double frames_per_beat = length / m.divisions_per_bar();
6009 /* beats per minute = */
6011 double beats_per_minute = (_session->frame_rate() * 60.0) / frames_per_beat;
6013 /* now decide whether to:
6015 (a) set global tempo
6016 (b) add a new tempo marker
6020 const TempoSection& t (_session->tempo_map().tempo_section_at (start));
6022 bool do_global = false;
6024 if ((_session->tempo_map().n_tempos() == 1) && (_session->tempo_map().n_meters() == 1)) {
6026 /* only 1 tempo & 1 meter: ask if the user wants to set the tempo
6027 at the start, or create a new marker
6030 vector<string> options;
6031 options.push_back (_("Cancel"));
6032 options.push_back (_("Add new marker"));
6033 options.push_back (_("Set global tempo"));
6036 _("Define one bar"),
6037 _("Do you want to set the global tempo or add a new tempo marker?"),
6041 c.set_default_response (2);
6057 /* more than 1 tempo and/or meter section already, go ahead do the "usual":
6058 if the marker is at the region starter, change it, otherwise add
6063 begin_reversible_command (_("set tempo from region"));
6064 XMLNode& before (_session->tempo_map().get_state());
6067 _session->tempo_map().change_initial_tempo (beats_per_minute, t.note_type());
6068 } else if (t.frame() == start) {
6069 _session->tempo_map().change_existing_tempo_at (start, beats_per_minute, t.note_type());
6071 Timecode::BBT_Time bbt;
6072 _session->tempo_map().bbt_time (start, bbt);
6073 _session->tempo_map().add_tempo (Tempo (beats_per_minute, t.note_type()), bbt);
6076 XMLNode& after (_session->tempo_map().get_state());
6078 _session->add_command (new MementoCommand<TempoMap>(_session->tempo_map(), &before, &after));
6079 commit_reversible_command ();
6083 Editor::split_region_at_transients ()
6085 AnalysisFeatureList positions;
6087 RegionSelection rs = get_regions_from_selection_and_entered ();
6089 if (!_session || rs.empty()) {
6093 _session->begin_reversible_command (_("split regions"));
6095 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ) {
6097 RegionSelection::iterator tmp;
6102 boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion> ((*i)->region());
6104 if (ar && (ar->get_transients (positions) == 0)) {
6105 split_region_at_points ((*i)->region(), positions, true);
6112 _session->commit_reversible_command ();
6117 Editor::split_region_at_points (boost::shared_ptr<Region> r, AnalysisFeatureList& positions, bool can_ferret, bool select_new)
6119 bool use_rhythmic_rodent = false;
6121 boost::shared_ptr<Playlist> pl = r->playlist();
6123 list<boost::shared_ptr<Region> > new_regions;
6129 if (positions.empty()) {
6134 if (positions.size() > 20 && can_ferret) {
6135 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);
6136 MessageDialog msg (msgstr,
6139 Gtk::BUTTONS_OK_CANCEL);
6142 msg.add_button (_("Call for the Ferret!"), RESPONSE_APPLY);
6143 msg.set_secondary_text (_("Press OK to continue with this split operation\nor ask the Ferret dialog to tune the analysis"));
6145 msg.set_secondary_text (_("Press OK to continue with this split operation"));
6148 msg.set_title (_("Excessive split?"));
6151 int response = msg.run();
6157 case RESPONSE_APPLY:
6158 use_rhythmic_rodent = true;
6165 if (use_rhythmic_rodent) {
6166 show_rhythm_ferret ();
6170 AnalysisFeatureList::const_iterator x;
6172 pl->clear_changes ();
6173 pl->clear_owned_changes ();
6175 x = positions.begin();
6177 if (x == positions.end()) {
6182 pl->remove_region (r);
6186 while (x != positions.end()) {
6188 /* deal with positons that are out of scope of present region bounds */
6189 if (*x <= 0 || *x > r->length()) {
6194 /* file start = original start + how far we from the initial position ?
6197 framepos_t file_start = r->start() + pos;
6199 /* length = next position - current position
6202 framepos_t len = (*x) - pos;
6204 /* XXX we do we really want to allow even single-sample regions?
6205 shouldn't we have some kind of lower limit on region size?
6214 if (RegionFactory::region_name (new_name, r->name())) {
6218 /* do NOT announce new regions 1 by one, just wait till they are all done */
6222 plist.add (ARDOUR::Properties::start, file_start);
6223 plist.add (ARDOUR::Properties::length, len);
6224 plist.add (ARDOUR::Properties::name, new_name);
6225 plist.add (ARDOUR::Properties::layer, 0);
6227 boost::shared_ptr<Region> nr = RegionFactory::create (r->sources(), plist, false);
6228 /* because we set annouce to false, manually add the new region to the
6231 RegionFactory::map_add (nr);
6233 pl->add_region (nr, r->position() + pos);
6236 new_regions.push_front(nr);
6245 RegionFactory::region_name (new_name, r->name());
6247 /* Add the final region */
6250 plist.add (ARDOUR::Properties::start, r->start() + pos);
6251 plist.add (ARDOUR::Properties::length, r->last_frame() - (r->position() + pos) + 1);
6252 plist.add (ARDOUR::Properties::name, new_name);
6253 plist.add (ARDOUR::Properties::layer, 0);
6255 boost::shared_ptr<Region> nr = RegionFactory::create (r->sources(), plist, false);
6256 /* because we set annouce to false, manually add the new region to the
6259 RegionFactory::map_add (nr);
6260 pl->add_region (nr, r->position() + pos);
6263 new_regions.push_front(nr);
6268 /* We might have removed regions, which alters other regions' layering_index,
6269 so we need to do a recursive diff here.
6271 vector<Command*> cmds;
6273 _session->add_commands (cmds);
6275 _session->add_command (new StatefulDiffCommand (pl));
6279 for (list<boost::shared_ptr<Region> >::iterator i = new_regions.begin(); i != new_regions.end(); ++i){
6280 set_selected_regionview_from_region_list ((*i), Selection::Add);
6286 Editor::place_transient()
6292 RegionSelection rs = get_regions_from_selection_and_edit_point ();
6298 framepos_t where = get_preferred_edit_position();
6300 _session->begin_reversible_command (_("place transient"));
6302 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6303 framepos_t position = (*r)->region()->position();
6304 (*r)->region()->add_transient(where - position);
6307 _session->commit_reversible_command ();
6311 Editor::remove_transient(ArdourCanvas::Item* item)
6317 ArdourCanvas::Line* _line = reinterpret_cast<ArdourCanvas::Line*> (item);
6320 AudioRegionView* _arv = reinterpret_cast<AudioRegionView*> (item->get_data ("regionview"));
6321 _arv->remove_transient (*(float*) _line->get_data ("position"));
6325 Editor::snap_regions_to_grid ()
6327 list <boost::shared_ptr<Playlist > > used_playlists;
6329 RegionSelection rs = get_regions_from_selection_and_entered ();
6331 if (!_session || rs.empty()) {
6335 _session->begin_reversible_command (_("snap regions to grid"));
6337 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6339 boost::shared_ptr<Playlist> pl = (*r)->region()->playlist();
6341 if (!pl->frozen()) {
6342 /* we haven't seen this playlist before */
6344 /* remember used playlists so we can thaw them later */
6345 used_playlists.push_back(pl);
6349 framepos_t start_frame = (*r)->region()->first_frame ();
6350 snap_to (start_frame);
6351 (*r)->region()->set_position (start_frame);
6354 while (used_playlists.size() > 0) {
6355 list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
6357 used_playlists.pop_front();
6360 _session->commit_reversible_command ();
6364 Editor::close_region_gaps ()
6366 list <boost::shared_ptr<Playlist > > used_playlists;
6368 RegionSelection rs = get_regions_from_selection_and_entered ();
6370 if (!_session || rs.empty()) {
6374 Dialog dialog (_("Close Region Gaps"));
6377 table.set_spacings (12);
6378 table.set_border_width (12);
6379 Label* l = manage (left_aligned_label (_("Crossfade length")));
6380 table.attach (*l, 0, 1, 0, 1);
6382 SpinButton spin_crossfade (1, 0);
6383 spin_crossfade.set_range (0, 15);
6384 spin_crossfade.set_increments (1, 1);
6385 spin_crossfade.set_value (5);
6386 table.attach (spin_crossfade, 1, 2, 0, 1);
6388 table.attach (*manage (new Label (_("ms"))), 2, 3, 0, 1);
6390 l = manage (left_aligned_label (_("Pull-back length")));
6391 table.attach (*l, 0, 1, 1, 2);
6393 SpinButton spin_pullback (1, 0);
6394 spin_pullback.set_range (0, 100);
6395 spin_pullback.set_increments (1, 1);
6396 spin_pullback.set_value(30);
6397 table.attach (spin_pullback, 1, 2, 1, 2);
6399 table.attach (*manage (new Label (_("ms"))), 2, 3, 1, 2);
6401 dialog.get_vbox()->pack_start (table);
6402 dialog.add_button (Stock::CANCEL, RESPONSE_CANCEL);
6403 dialog.add_button (_("Ok"), RESPONSE_ACCEPT);
6406 if (dialog.run () == RESPONSE_CANCEL) {
6410 framepos_t crossfade_len = spin_crossfade.get_value();
6411 framepos_t pull_back_frames = spin_pullback.get_value();
6413 crossfade_len = lrintf (crossfade_len * _session->frame_rate()/1000);
6414 pull_back_frames = lrintf (pull_back_frames * _session->frame_rate()/1000);
6416 /* Iterate over the region list and make adjacent regions overlap by crossfade_len_ms */
6418 _session->begin_reversible_command (_("close region gaps"));
6421 boost::shared_ptr<Region> last_region;
6423 rs.sort_by_position_and_track();
6425 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6427 boost::shared_ptr<Playlist> pl = (*r)->region()->playlist();
6429 if (!pl->frozen()) {
6430 /* we haven't seen this playlist before */
6432 /* remember used playlists so we can thaw them later */
6433 used_playlists.push_back(pl);
6437 framepos_t position = (*r)->region()->position();
6439 if (idx == 0 || position < last_region->position()){
6440 last_region = (*r)->region();
6445 (*r)->region()->trim_front( (position - pull_back_frames));
6446 last_region->trim_end( (position - pull_back_frames + crossfade_len));
6448 last_region = (*r)->region();
6453 while (used_playlists.size() > 0) {
6454 list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
6456 used_playlists.pop_front();
6459 _session->commit_reversible_command ();
6463 Editor::tab_to_transient (bool forward)
6465 AnalysisFeatureList positions;
6467 RegionSelection rs = get_regions_from_selection_and_entered ();
6473 framepos_t pos = _session->audible_frame ();
6475 if (!selection->tracks.empty()) {
6477 /* don't waste time searching for transients in duplicate playlists.
6480 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
6482 for (TrackViewList::iterator t = ts.begin(); t != ts.end(); ++t) {
6484 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*t);
6487 boost::shared_ptr<Track> tr = rtv->track();
6489 boost::shared_ptr<Playlist> pl = tr->playlist ();
6491 framepos_t result = pl->find_next_transient (pos, forward ? 1 : -1);
6494 positions.push_back (result);
6507 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6508 (*r)->region()->get_transients (positions);
6512 TransientDetector::cleanup_transients (positions, _session->frame_rate(), 3.0);
6515 AnalysisFeatureList::iterator x;
6517 for (x = positions.begin(); x != positions.end(); ++x) {
6523 if (x != positions.end ()) {
6524 _session->request_locate (*x);
6528 AnalysisFeatureList::reverse_iterator x;
6530 for (x = positions.rbegin(); x != positions.rend(); ++x) {
6536 if (x != positions.rend ()) {
6537 _session->request_locate (*x);
6543 Editor::playhead_forward_to_grid ()
6549 framepos_t pos = playhead_cursor->current_frame ();
6550 if (pos < max_framepos - 1) {
6552 snap_to_internal (pos, RoundUpAlways, false);
6553 _session->request_locate (pos);
6559 Editor::playhead_backward_to_grid ()
6565 framepos_t pos = playhead_cursor->current_frame ();
6568 snap_to_internal (pos, RoundDownAlways, false);
6569 _session->request_locate (pos);
6574 Editor::set_track_height (Height h)
6576 TrackSelection& ts (selection->tracks);
6578 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
6579 (*x)->set_height_enum (h);
6584 Editor::toggle_tracks_active ()
6586 TrackSelection& ts (selection->tracks);
6588 bool target = false;
6594 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
6595 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*x);
6599 target = !rtv->_route->active();
6602 rtv->_route->set_active (target, this);
6608 Editor::remove_tracks ()
6610 TrackSelection& ts (selection->tracks);
6616 vector<string> choices;
6620 const char* trackstr;
6622 vector<boost::shared_ptr<Route> > routes;
6623 bool special_bus = false;
6625 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
6626 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*x);
6630 if (rtv->is_track()) {
6635 routes.push_back (rtv->_route);
6637 if (rtv->route()->is_master() || rtv->route()->is_monitor()) {
6642 if (special_bus && !Config->get_allow_special_bus_removal()) {
6643 MessageDialog msg (_("That would be bad news ...."),
6647 msg.set_secondary_text (string_compose (_(
6648 "Removing the master or monitor bus is such a bad idea\n\
6649 that %1 is not going to allow it.\n\
6651 If you really want to do this sort of thing\n\
6652 edit your ardour.rc file to set the\n\
6653 \"allow-special-bus-removal\" option to be \"yes\""), PROGRAM_NAME));
6660 if (ntracks + nbusses == 0) {
6664 // XXX should be using gettext plural forms, maybe?
6666 trackstr = _("tracks");
6668 trackstr = _("track");
6672 busstr = _("busses");
6679 prompt = string_compose (_("Do you really want to remove %1 %2 and %3 %4?\n"
6680 "(You may also lose the playlists associated with the %2)\n\n"
6681 "This action cannot be undone, and the session file will be overwritten!"),
6682 ntracks, trackstr, nbusses, busstr);
6684 prompt = string_compose (_("Do you really want to remove %1 %2?\n"
6685 "(You may also lose the playlists associated with the %2)\n\n"
6686 "This action cannot be undone, and the session file will be overwritten!"),
6689 } else if (nbusses) {
6690 prompt = string_compose (_("Do you really want to remove %1 %2?\n\n"
6691 "This action cannot be undone, and the session file will be overwritten"),
6695 choices.push_back (_("No, do nothing."));
6696 if (ntracks + nbusses > 1) {
6697 choices.push_back (_("Yes, remove them."));
6699 choices.push_back (_("Yes, remove it."));
6704 title = string_compose (_("Remove %1"), trackstr);
6706 title = string_compose (_("Remove %1"), busstr);
6709 Choice prompter (title, prompt, choices);
6711 if (prompter.run () != 1) {
6716 Session::StateProtector sp (_session);
6717 DisplaySuspender ds;
6718 for (vector<boost::shared_ptr<Route> >::iterator x = routes.begin(); x != routes.end(); ++x) {
6719 _session->remove_route (*x);
6725 Editor::do_insert_time ()
6727 if (selection->tracks.empty()) {
6731 InsertTimeDialog d (*this);
6732 int response = d.run ();
6734 if (response != RESPONSE_OK) {
6738 if (d.distance() == 0) {
6742 InsertTimeOption opt = d.intersected_region_action ();
6745 get_preferred_edit_position(),
6751 d.move_glued_markers(),
6752 d.move_locked_markers(),
6758 Editor::insert_time (
6759 framepos_t pos, framecnt_t frames, InsertTimeOption opt,
6760 bool all_playlists, bool ignore_music_glue, bool markers_too, bool glued_markers_too, bool locked_markers_too, bool tempo_too
6763 bool commit = false;
6765 if (Config->get_edit_mode() == Lock) {
6769 begin_reversible_command (_("insert time"));
6771 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
6773 for (TrackViewList::iterator x = ts.begin(); x != ts.end(); ++x) {
6777 /* don't operate on any playlist more than once, which could
6778 * happen if "all playlists" is enabled, but there is more
6779 * than 1 track using playlists "from" a given track.
6782 set<boost::shared_ptr<Playlist> > pl;
6784 if (all_playlists) {
6785 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*x);
6787 vector<boost::shared_ptr<Playlist> > all = _session->playlists->playlists_for_track (rtav->track ());
6788 for (vector<boost::shared_ptr<Playlist> >::iterator p = all.begin(); p != all.end(); ++p) {
6793 if ((*x)->playlist ()) {
6794 pl.insert ((*x)->playlist ());
6798 for (set<boost::shared_ptr<Playlist> >::iterator i = pl.begin(); i != pl.end(); ++i) {
6800 (*i)->clear_changes ();
6801 (*i)->clear_owned_changes ();
6803 if (opt == SplitIntersected) {
6807 (*i)->shift (pos, frames, (opt == MoveIntersected), ignore_music_glue);
6809 vector<Command*> cmds;
6811 _session->add_commands (cmds);
6813 _session->add_command (new StatefulDiffCommand (*i));
6818 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*x);
6820 rtav->route ()->shift (pos, frames);
6828 XMLNode& before (_session->locations()->get_state());
6829 Locations::LocationList copy (_session->locations()->list());
6831 for (Locations::LocationList::iterator i = copy.begin(); i != copy.end(); ++i) {
6833 Locations::LocationList::const_iterator tmp;
6835 bool const was_locked = (*i)->locked ();
6836 if (locked_markers_too) {
6840 if ((*i)->position_lock_style() == AudioTime || glued_markers_too) {
6842 if ((*i)->start() >= pos) {
6843 (*i)->set_start ((*i)->start() + frames);
6844 if (!(*i)->is_mark()) {
6845 (*i)->set_end ((*i)->end() + frames);
6858 XMLNode& after (_session->locations()->get_state());
6859 _session->add_command (new MementoCommand<Locations>(*_session->locations(), &before, &after));
6864 _session->tempo_map().insert_time (pos, frames);
6868 commit_reversible_command ();
6873 Editor::fit_selected_tracks ()
6875 if (!selection->tracks.empty()) {
6876 fit_tracks (selection->tracks);
6880 /* no selected tracks - use tracks with selected regions */
6882 if (!selection->regions.empty()) {
6883 for (RegionSelection::iterator r = selection->regions.begin(); r != selection->regions.end(); ++r) {
6884 tvl.push_back (&(*r)->get_time_axis_view ());
6890 } else if (internal_editing()) {
6891 /* no selected tracks, or regions, but in internal edit mode, so follow the mouse and use
6894 if (entered_track) {
6895 tvl.push_back (entered_track);
6904 Editor::fit_tracks (TrackViewList & tracks)
6906 if (tracks.empty()) {
6910 uint32_t child_heights = 0;
6911 int visible_tracks = 0;
6913 for (TrackSelection::iterator t = tracks.begin(); t != tracks.end(); ++t) {
6915 if (!(*t)->marked_for_display()) {
6919 child_heights += (*t)->effective_height() - (*t)->current_height();
6923 /* compute the per-track height from:
6925 total canvas visible height -
6926 height that will be taken by visible children of selected
6927 tracks - height of the ruler/hscroll area
6929 uint32_t h = (uint32_t) floor ((trackviews_height() - child_heights) / visible_tracks);
6930 double first_y_pos = DBL_MAX;
6932 if (h < TimeAxisView::preset_height (HeightSmall)) {
6933 MessageDialog msg (*this, _("There are too many tracks to fit in the current window"));
6934 /* too small to be displayed */
6938 undo_visual_stack.push_back (current_visual_state (true));
6939 no_save_visual = true;
6941 /* build a list of all tracks, including children */
6944 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
6946 TimeAxisView::Children c = (*i)->get_child_list ();
6947 for (TimeAxisView::Children::iterator j = c.begin(); j != c.end(); ++j) {
6948 all.push_back (j->get());
6952 bool prev_was_selected = false;
6953 bool is_selected = tracks.contains (all.front());
6954 bool next_is_selected;
6956 for (TrackViewList::iterator t = all.begin(); t != all.end(); ++t) {
6958 TrackViewList::iterator next;
6963 if (next != all.end()) {
6964 next_is_selected = tracks.contains (*next);
6966 next_is_selected = false;
6969 if ((*t)->marked_for_display ()) {
6971 (*t)->set_height (h);
6972 first_y_pos = std::min ((*t)->y_position (), first_y_pos);
6974 if (prev_was_selected && next_is_selected) {
6975 hide_track_in_display (*t);
6980 prev_was_selected = is_selected;
6981 is_selected = next_is_selected;
6985 set the controls_layout height now, because waiting for its size
6986 request signal handler will cause the vertical adjustment setting to fail
6989 controls_layout.property_height () = _full_canvas_height;
6990 vertical_adjustment.set_value (first_y_pos);
6992 redo_visual_stack.push_back (current_visual_state (true));
6994 visible_tracks_selector.set_text (_("Sel"));
6998 Editor::save_visual_state (uint32_t n)
7000 while (visual_states.size() <= n) {
7001 visual_states.push_back (0);
7004 if (visual_states[n] != 0) {
7005 delete visual_states[n];
7008 visual_states[n] = current_visual_state (true);
7013 Editor::goto_visual_state (uint32_t n)
7015 if (visual_states.size() <= n) {
7019 if (visual_states[n] == 0) {
7023 use_visual_state (*visual_states[n]);
7027 Editor::start_visual_state_op (uint32_t n)
7029 save_visual_state (n);
7031 PopUp* pup = new PopUp (WIN_POS_MOUSE, 1000, true);
7033 snprintf (buf, sizeof (buf), _("Saved view %u"), n+1);
7034 pup->set_text (buf);
7039 Editor::cancel_visual_state_op (uint32_t n)
7041 goto_visual_state (n);
7045 Editor::toggle_region_mute ()
7047 if (_ignore_region_action) {
7051 RegionSelection rs = get_regions_from_selection_and_entered ();
7057 if (rs.size() > 1) {
7058 begin_reversible_command (_("mute regions"));
7060 begin_reversible_command (_("mute region"));
7063 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
7065 (*i)->region()->playlist()->clear_changes ();
7066 (*i)->region()->set_muted (!(*i)->region()->muted ());
7067 _session->add_command (new StatefulDiffCommand ((*i)->region()->playlist()));
7071 commit_reversible_command ();
7075 Editor::combine_regions ()
7077 /* foreach track with selected regions, take all selected regions
7078 and join them into a new region containing the subregions (as a
7082 typedef set<RouteTimeAxisView*> RTVS;
7085 if (selection->regions.empty()) {
7089 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
7090 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(&(*i)->get_time_axis_view());
7093 tracks.insert (rtv);
7097 begin_reversible_command (_("combine regions"));
7099 vector<RegionView*> new_selection;
7101 for (RTVS::iterator i = tracks.begin(); i != tracks.end(); ++i) {
7104 if ((rv = (*i)->combine_regions ()) != 0) {
7105 new_selection.push_back (rv);
7109 selection->clear_regions ();
7110 for (vector<RegionView*>::iterator i = new_selection.begin(); i != new_selection.end(); ++i) {
7111 selection->add (*i);
7114 commit_reversible_command ();
7118 Editor::uncombine_regions ()
7120 typedef set<RouteTimeAxisView*> RTVS;
7123 if (selection->regions.empty()) {
7127 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
7128 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(&(*i)->get_time_axis_view());
7131 tracks.insert (rtv);
7135 begin_reversible_command (_("uncombine regions"));
7137 for (RTVS::iterator i = tracks.begin(); i != tracks.end(); ++i) {
7138 (*i)->uncombine_regions ();
7141 commit_reversible_command ();
7145 Editor::toggle_midi_input_active (bool flip_others)
7148 boost::shared_ptr<RouteList> rl (new RouteList);
7150 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
7151 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
7157 boost::shared_ptr<MidiTrack> mt = rtav->midi_track();
7160 rl->push_back (rtav->route());
7161 onoff = !mt->input_active();
7165 _session->set_exclusive_input_active (rl, onoff, flip_others);
7172 lock_dialog = new Gtk::Dialog (string_compose (_("%1: Locked"), PROGRAM_NAME), true);
7174 Gtk::Image* padlock = manage (new Gtk::Image (ARDOUR_UI_UTILS::get_icon ("padlock_closed")));
7175 lock_dialog->get_vbox()->pack_start (*padlock);
7177 ArdourButton* b = manage (new ArdourButton);
7178 b->set_name ("lock button");
7179 b->set_text (_("Click to unlock"));
7180 b->signal_clicked.connect (sigc::mem_fun (*this, &Editor::unlock));
7181 lock_dialog->get_vbox()->pack_start (*b);
7183 lock_dialog->get_vbox()->show_all ();
7184 lock_dialog->set_size_request (200, 200);
7188 /* The global menu bar continues to be accessible to applications
7189 with modal dialogs, which means that we need to desensitize
7190 all items in the menu bar. Since those items are really just
7191 proxies for actions, that means disabling all actions.
7193 ActionManager::disable_all_actions ();
7195 lock_dialog->present ();
7201 lock_dialog->hide ();
7204 ActionManager::pop_action_state ();
7207 if (ARDOUR_UI::config()->get_lock_gui_after_seconds()) {
7208 start_lock_event_timing ();
7213 Editor::bring_in_callback (Gtk::Label* label, uint32_t n, uint32_t total, string name)
7215 Gtkmm2ext::UI::instance()->call_slot (invalidator (*this), boost::bind (&Editor::update_bring_in_message, this, label, n, total, name));
7219 Editor::update_bring_in_message (Gtk::Label* label, uint32_t n, uint32_t total, string name)
7221 label->set_text (string_compose ("Copying %1, %2 of %3", name, n, total));
7222 Gtkmm2ext::UI::instance()->flush_pending ();
7226 Editor::bring_all_sources_into_session ()
7233 ArdourDialog w (_("Moving embedded files into session folder"));
7234 w.get_vbox()->pack_start (msg);
7237 /* flush all pending GUI events because we're about to start copying
7241 Gtkmm2ext::UI::instance()->flush_pending ();
7245 _session->bring_all_sources_into_session (boost::bind (&Editor::bring_in_callback, this, &msg, _1, _2, _3));