2 Copyright (C) 2000-2004 Paul Davis
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 /* Note: public Editor methods are documented in public_editor.h */
31 #include "pbd/error.h"
32 #include "pbd/basename.h"
33 #include "pbd/pthread_utils.h"
34 #include "pbd/memento_command.h"
35 #include "pbd/unwind.h"
36 #include "pbd/whitespace.h"
37 #include "pbd/stateful_diff_command.h"
39 #include <gtkmm2ext/utils.h>
40 #include <gtkmm2ext/choice.h>
41 #include <gtkmm2ext/popup.h>
43 #include "ardour/audio_track.h"
44 #include "ardour/audioregion.h"
45 #include "ardour/dB.h"
46 #include "ardour/location.h"
47 #include "ardour/midi_region.h"
48 #include "ardour/midi_track.h"
49 #include "ardour/operations.h"
50 #include "ardour/playlist_factory.h"
51 #include "ardour/profile.h"
52 #include "ardour/quantize.h"
53 #include "ardour/region_factory.h"
54 #include "ardour/reverse.h"
55 #include "ardour/session.h"
56 #include "ardour/session_playlists.h"
57 #include "ardour/strip_silence.h"
58 #include "ardour/transient_detector.h"
60 #include "canvas/canvas.h"
63 #include "ardour_ui.h"
64 #include "audio_region_view.h"
65 #include "audio_streamview.h"
66 #include "audio_time_axis.h"
67 #include "automation_region_view.h"
68 #include "automation_time_axis.h"
69 #include "control_point.h"
73 #include "editor_cursors.h"
74 #include "editor_drag.h"
75 #include "editor_regions.h"
76 #include "editor_routes.h"
77 #include "gui_thread.h"
78 #include "insert_time_dialog.h"
79 #include "interthread_progress_window.h"
80 #include "item_counts.h"
82 #include "midi_region_view.h"
83 #include "mixer_strip.h"
84 #include "mouse_cursors.h"
85 #include "normalize_dialog.h"
86 #include "paste_context.h"
87 #include "patch_change_dialog.h"
88 #include "quantize_dialog.h"
89 #include "region_gain_line.h"
90 #include "rgb_macros.h"
91 #include "route_time_axis.h"
92 #include "selection.h"
93 #include "selection_templates.h"
94 #include "streamview.h"
95 #include "strip_silence_dialog.h"
96 #include "time_axis_view.h"
97 #include "transpose_dialog.h"
102 using namespace ARDOUR;
105 using namespace Gtkmm2ext;
106 using namespace Editing;
107 using Gtkmm2ext::Keyboard;
109 /***********************************************************************
111 ***********************************************************************/
114 Editor::undo (uint32_t n)
116 if (_drags->active ()) {
126 Editor::redo (uint32_t n)
128 if (_drags->active ()) {
138 Editor::split_regions_at (framepos_t where, RegionSelection& regions)
142 RegionSelection pre_selected_regions = selection->regions;
143 bool working_on_selection = !pre_selected_regions.empty();
145 list<boost::shared_ptr<Playlist> > used_playlists;
146 list<RouteTimeAxisView*> used_trackviews;
148 if (regions.empty()) {
152 begin_reversible_command (_("split"));
154 // if splitting a single region, and snap-to is using
155 // region boundaries, don't pay attention to them
157 if (regions.size() == 1) {
158 switch (_snap_type) {
159 case SnapToRegionStart:
160 case SnapToRegionSync:
161 case SnapToRegionEnd:
170 EditorFreeze(); /* Emit Signal */
173 for (RegionSelection::iterator a = regions.begin(); a != regions.end(); ) {
175 RegionSelection::iterator tmp;
177 /* XXX this test needs to be more complicated, to make sure we really
178 have something to split.
181 if (!(*a)->region()->covers (where)) {
189 boost::shared_ptr<Playlist> pl = (*a)->region()->playlist();
197 /* we haven't seen this playlist before */
199 /* remember used playlists so we can thaw them later */
200 used_playlists.push_back(pl);
202 TimeAxisView& tv = (*a)->get_time_axis_view();
203 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (&tv);
205 used_trackviews.push_back (rtv);
212 pl->clear_changes ();
213 pl->split_region ((*a)->region(), where);
214 _session->add_command (new StatefulDiffCommand (pl));
220 vector<sigc::connection> region_added_connections;
222 for (list<RouteTimeAxisView*>::iterator i = used_trackviews.begin(); i != used_trackviews.end(); ++i) {
223 region_added_connections.push_back ((*i)->view()->RegionViewAdded.connect (sigc::mem_fun(*this, &Editor::collect_new_region_view)));
226 latest_regionviews.clear ();
228 while (used_playlists.size() > 0) {
229 list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
231 used_playlists.pop_front();
234 for (vector<sigc::connection>::iterator c = region_added_connections.begin(); c != region_added_connections.end(); ++c) {
238 commit_reversible_command ();
241 EditorThaw(); /* Emit Signal */
244 if (ARDOUR::Profile->get_mixbus()) {
245 //IFF we were working on selected regions, try to reinstate the other region selections that existed before the freeze/thaw.
246 _ignore_follow_edits = true; //a split will change the region selection in mysterious ways; its not practical or wanted to follow this edit
247 if( working_on_selection ) {
248 selection->add ( pre_selected_regions );
249 selection->add (latest_regionviews); //these are the new regions created after the split
251 _ignore_follow_edits = false;
255 /** Move one extreme of the current range selection. If more than one range is selected,
256 * the start of the earliest range or the end of the latest range is moved.
258 * @param move_end true to move the end of the current range selection, false to move
260 * @param next true to move the extreme to the next region boundary, false to move to
264 Editor::move_range_selection_start_or_end_to_region_boundary (bool move_end, bool next)
266 if (selection->time.start() == selection->time.end_frame()) {
270 framepos_t start = selection->time.start ();
271 framepos_t end = selection->time.end_frame ();
273 /* the position of the thing we may move */
274 framepos_t pos = move_end ? end : start;
275 int dir = next ? 1 : -1;
277 /* so we don't find the current region again */
278 if (dir > 0 || pos > 0) {
282 framepos_t const target = get_region_boundary (pos, dir, true, false);
297 begin_reversible_command (_("alter selection"));
298 selection->set_preserving_all_ranges (start, end);
299 commit_reversible_command ();
303 Editor::nudge_forward_release (GdkEventButton* ev)
305 if (ev->state & Keyboard::PrimaryModifier) {
306 nudge_forward (false, true);
308 nudge_forward (false, false);
314 Editor::nudge_backward_release (GdkEventButton* ev)
316 if (ev->state & Keyboard::PrimaryModifier) {
317 nudge_backward (false, true);
319 nudge_backward (false, false);
326 Editor::nudge_forward (bool next, bool force_playhead)
329 framepos_t next_distance;
335 RegionSelection rs = get_regions_from_selection_and_entered ();
337 if (!force_playhead && !rs.empty()) {
339 begin_reversible_command (_("nudge regions forward"));
341 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
342 boost::shared_ptr<Region> r ((*i)->region());
344 distance = get_nudge_distance (r->position(), next_distance);
347 distance = next_distance;
351 r->set_position (r->position() + distance);
352 _session->add_command (new StatefulDiffCommand (r));
355 commit_reversible_command ();
358 } else if (!force_playhead && !selection->markers.empty()) {
362 begin_reversible_command (_("nudge location forward"));
364 for (MarkerSelection::iterator i = selection->markers.begin(); i != selection->markers.end(); ++i) {
366 Location* loc = find_location_from_marker ((*i), is_start);
370 XMLNode& before (loc->get_state());
373 distance = get_nudge_distance (loc->start(), next_distance);
375 distance = next_distance;
377 if (max_framepos - distance > loc->start() + loc->length()) {
378 loc->set_start (loc->start() + distance);
380 loc->set_start (max_framepos - loc->length());
383 distance = get_nudge_distance (loc->end(), next_distance);
385 distance = next_distance;
387 if (max_framepos - distance > loc->end()) {
388 loc->set_end (loc->end() + distance);
390 loc->set_end (max_framepos);
393 XMLNode& after (loc->get_state());
394 _session->add_command (new MementoCommand<Location>(*loc, &before, &after));
398 commit_reversible_command ();
401 distance = get_nudge_distance (playhead_cursor->current_frame (), next_distance);
402 _session->request_locate (playhead_cursor->current_frame () + distance);
407 Editor::nudge_backward (bool next, bool force_playhead)
410 framepos_t next_distance;
416 RegionSelection rs = get_regions_from_selection_and_entered ();
418 if (!force_playhead && !rs.empty()) {
420 begin_reversible_command (_("nudge regions backward"));
422 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
423 boost::shared_ptr<Region> r ((*i)->region());
425 distance = get_nudge_distance (r->position(), next_distance);
428 distance = next_distance;
433 if (r->position() > distance) {
434 r->set_position (r->position() - distance);
438 _session->add_command (new StatefulDiffCommand (r));
441 commit_reversible_command ();
443 } else if (!force_playhead && !selection->markers.empty()) {
447 begin_reversible_command (_("nudge location forward"));
449 for (MarkerSelection::iterator i = selection->markers.begin(); i != selection->markers.end(); ++i) {
451 Location* loc = find_location_from_marker ((*i), is_start);
455 XMLNode& before (loc->get_state());
458 distance = get_nudge_distance (loc->start(), next_distance);
460 distance = next_distance;
462 if (distance < loc->start()) {
463 loc->set_start (loc->start() - distance);
468 distance = get_nudge_distance (loc->end(), next_distance);
471 distance = next_distance;
474 if (distance < loc->end() - loc->length()) {
475 loc->set_end (loc->end() - distance);
477 loc->set_end (loc->length());
481 XMLNode& after (loc->get_state());
482 _session->add_command (new MementoCommand<Location>(*loc, &before, &after));
486 commit_reversible_command ();
490 distance = get_nudge_distance (playhead_cursor->current_frame (), next_distance);
492 if (playhead_cursor->current_frame () > distance) {
493 _session->request_locate (playhead_cursor->current_frame () - distance);
495 _session->goto_start();
501 Editor::nudge_forward_capture_offset ()
503 RegionSelection rs = get_regions_from_selection_and_entered ();
505 if (!_session || rs.empty()) {
509 begin_reversible_command (_("nudge forward"));
511 framepos_t const distance = _session->worst_output_latency();
513 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
514 boost::shared_ptr<Region> r ((*i)->region());
517 r->set_position (r->position() + distance);
518 _session->add_command(new StatefulDiffCommand (r));
521 commit_reversible_command ();
525 Editor::nudge_backward_capture_offset ()
527 RegionSelection rs = get_regions_from_selection_and_entered ();
529 if (!_session || rs.empty()) {
533 begin_reversible_command (_("nudge backward"));
535 framepos_t const distance = _session->worst_output_latency();
537 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
538 boost::shared_ptr<Region> r ((*i)->region());
542 if (r->position() > distance) {
543 r->set_position (r->position() - distance);
547 _session->add_command(new StatefulDiffCommand (r));
550 commit_reversible_command ();
553 struct RegionSelectionPositionSorter {
554 bool operator() (RegionView* a, RegionView* b) {
555 return a->region()->position() < b->region()->position();
560 Editor::sequence_regions ()
563 framepos_t r_end_prev;
571 RegionSelection rs = get_regions_from_selection_and_entered ();
572 rs.sort(RegionSelectionPositionSorter());
576 begin_reversible_command (_("sequence regions"));
577 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
578 boost::shared_ptr<Region> r ((*i)->region());
586 if(r->position_locked())
593 r->set_position(r_end_prev);
596 _session->add_command (new StatefulDiffCommand (r));
598 r_end=r->position() + r->length();
602 commit_reversible_command ();
610 Editor::move_to_start ()
612 _session->goto_start ();
616 Editor::move_to_end ()
619 _session->request_locate (_session->current_end_frame());
623 Editor::build_region_boundary_cache ()
626 vector<RegionPoint> interesting_points;
627 boost::shared_ptr<Region> r;
628 TrackViewList tracks;
631 region_boundary_cache.clear ();
637 switch (_snap_type) {
638 case SnapToRegionStart:
639 interesting_points.push_back (Start);
641 case SnapToRegionEnd:
642 interesting_points.push_back (End);
644 case SnapToRegionSync:
645 interesting_points.push_back (SyncPoint);
647 case SnapToRegionBoundary:
648 interesting_points.push_back (Start);
649 interesting_points.push_back (End);
652 fatal << string_compose (_("build_region_boundary_cache called with snap_type = %1"), _snap_type) << endmsg;
653 abort(); /*NOTREACHED*/
657 TimeAxisView *ontrack = 0;
660 if (!selection->tracks.empty()) {
661 tlist = selection->tracks.filter_to_unique_playlists ();
663 tlist = track_views.filter_to_unique_playlists ();
666 while (pos < _session->current_end_frame() && !at_end) {
669 framepos_t lpos = max_framepos;
671 for (vector<RegionPoint>::iterator p = interesting_points.begin(); p != interesting_points.end(); ++p) {
673 if ((r = find_next_region (pos, *p, 1, tlist, &ontrack)) == 0) {
674 if (*p == interesting_points.back()) {
677 /* move to next point type */
683 rpos = r->first_frame();
687 rpos = r->last_frame();
691 rpos = r->sync_position ();
699 RouteTimeAxisView *rtav;
701 if (ontrack != 0 && (rtav = dynamic_cast<RouteTimeAxisView*>(ontrack)) != 0 ) {
702 if (rtav->track() != 0) {
703 speed = rtav->track()->speed();
707 rpos = track_frame_to_session_frame (rpos, speed);
713 /* prevent duplicates, but we don't use set<> because we want to be able
717 vector<framepos_t>::iterator ri;
719 for (ri = region_boundary_cache.begin(); ri != region_boundary_cache.end(); ++ri) {
725 if (ri == region_boundary_cache.end()) {
726 region_boundary_cache.push_back (rpos);
733 /* finally sort to be sure that the order is correct */
735 sort (region_boundary_cache.begin(), region_boundary_cache.end());
738 boost::shared_ptr<Region>
739 Editor::find_next_region (framepos_t frame, RegionPoint point, int32_t dir, TrackViewList& tracks, TimeAxisView **ontrack)
741 TrackViewList::iterator i;
742 framepos_t closest = max_framepos;
743 boost::shared_ptr<Region> ret;
747 framepos_t track_frame;
748 RouteTimeAxisView *rtav;
750 for (i = tracks.begin(); i != tracks.end(); ++i) {
753 boost::shared_ptr<Region> r;
756 if ( (rtav = dynamic_cast<RouteTimeAxisView*>(*i)) != 0 ) {
757 if (rtav->track()!=0)
758 track_speed = rtav->track()->speed();
761 track_frame = session_frame_to_track_frame(frame, track_speed);
763 if ((r = (*i)->find_next_region (track_frame, point, dir)) == 0) {
769 rpos = r->first_frame ();
773 rpos = r->last_frame ();
777 rpos = r->sync_position ();
781 // rpos is a "track frame", converting it to "_session frame"
782 rpos = track_frame_to_session_frame(rpos, track_speed);
785 distance = rpos - frame;
787 distance = frame - rpos;
790 if (distance < closest) {
802 Editor::find_next_region_boundary (framepos_t pos, int32_t dir, const TrackViewList& tracks)
804 framecnt_t distance = max_framepos;
805 framepos_t current_nearest = -1;
807 for (TrackViewList::const_iterator i = tracks.begin(); i != tracks.end(); ++i) {
808 framepos_t contender;
811 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*i);
817 if ((contender = rtv->find_next_region_boundary (pos, dir)) < 0) {
821 d = ::llabs (pos - contender);
824 current_nearest = contender;
829 return current_nearest;
833 Editor::get_region_boundary (framepos_t pos, int32_t dir, bool with_selection, bool only_onscreen)
838 if (with_selection && Config->get_region_boundaries_from_selected_tracks()) {
840 if (!selection->tracks.empty()) {
842 target = find_next_region_boundary (pos, dir, selection->tracks);
846 if (only_onscreen || Config->get_region_boundaries_from_onscreen_tracks()) {
847 get_onscreen_tracks (tvl);
848 target = find_next_region_boundary (pos, dir, tvl);
850 target = find_next_region_boundary (pos, dir, track_views);
856 if (only_onscreen || Config->get_region_boundaries_from_onscreen_tracks()) {
857 get_onscreen_tracks (tvl);
858 target = find_next_region_boundary (pos, dir, tvl);
860 target = find_next_region_boundary (pos, dir, track_views);
868 Editor::cursor_to_region_boundary (bool with_selection, int32_t dir)
870 framepos_t pos = playhead_cursor->current_frame ();
877 // so we don't find the current region again..
878 if (dir > 0 || pos > 0) {
882 if ((target = get_region_boundary (pos, dir, with_selection, false)) < 0) {
886 _session->request_locate (target);
890 Editor::cursor_to_next_region_boundary (bool with_selection)
892 cursor_to_region_boundary (with_selection, 1);
896 Editor::cursor_to_previous_region_boundary (bool with_selection)
898 cursor_to_region_boundary (with_selection, -1);
902 Editor::cursor_to_region_point (EditorCursor* cursor, RegionPoint point, int32_t dir)
904 boost::shared_ptr<Region> r;
905 framepos_t pos = cursor->current_frame ();
911 TimeAxisView *ontrack = 0;
913 // so we don't find the current region again..
917 if (!selection->tracks.empty()) {
919 r = find_next_region (pos, point, dir, selection->tracks, &ontrack);
921 } else if (clicked_axisview) {
924 t.push_back (clicked_axisview);
926 r = find_next_region (pos, point, dir, t, &ontrack);
930 r = find_next_region (pos, point, dir, track_views, &ontrack);
939 pos = r->first_frame ();
943 pos = r->last_frame ();
947 pos = r->sync_position ();
952 RouteTimeAxisView *rtav;
954 if ( ontrack != 0 && (rtav = dynamic_cast<RouteTimeAxisView*>(ontrack)) != 0 ) {
955 if (rtav->track() != 0) {
956 speed = rtav->track()->speed();
960 pos = track_frame_to_session_frame(pos, speed);
962 if (cursor == playhead_cursor) {
963 _session->request_locate (pos);
965 cursor->set_position (pos);
970 Editor::cursor_to_next_region_point (EditorCursor* cursor, RegionPoint point)
972 cursor_to_region_point (cursor, point, 1);
976 Editor::cursor_to_previous_region_point (EditorCursor* cursor, RegionPoint point)
978 cursor_to_region_point (cursor, point, -1);
982 Editor::cursor_to_selection_start (EditorCursor *cursor)
986 switch (mouse_mode) {
988 if (!selection->regions.empty()) {
989 pos = selection->regions.start();
994 if (!selection->time.empty()) {
995 pos = selection->time.start ();
1003 if (cursor == playhead_cursor) {
1004 _session->request_locate (pos);
1006 cursor->set_position (pos);
1011 Editor::cursor_to_selection_end (EditorCursor *cursor)
1015 switch (mouse_mode) {
1017 if (!selection->regions.empty()) {
1018 pos = selection->regions.end_frame();
1023 if (!selection->time.empty()) {
1024 pos = selection->time.end_frame ();
1032 if (cursor == playhead_cursor) {
1033 _session->request_locate (pos);
1035 cursor->set_position (pos);
1040 Editor::selected_marker_to_region_boundary (bool with_selection, int32_t dir)
1050 if (selection->markers.empty()) {
1054 if (!mouse_frame (mouse, ignored)) {
1058 add_location_mark (mouse);
1061 if ((loc = find_location_from_marker (selection->markers.front(), ignored)) == 0) {
1065 framepos_t pos = loc->start();
1067 // so we don't find the current region again..
1068 if (dir > 0 || pos > 0) {
1072 if ((target = get_region_boundary (pos, dir, with_selection, false)) < 0) {
1076 loc->move_to (target);
1080 Editor::selected_marker_to_next_region_boundary (bool with_selection)
1082 selected_marker_to_region_boundary (with_selection, 1);
1086 Editor::selected_marker_to_previous_region_boundary (bool with_selection)
1088 selected_marker_to_region_boundary (with_selection, -1);
1092 Editor::selected_marker_to_region_point (RegionPoint point, int32_t dir)
1094 boost::shared_ptr<Region> r;
1099 if (!_session || selection->markers.empty()) {
1103 if ((loc = find_location_from_marker (selection->markers.front(), ignored)) == 0) {
1107 TimeAxisView *ontrack = 0;
1111 // so we don't find the current region again..
1115 if (!selection->tracks.empty()) {
1117 r = find_next_region (pos, point, dir, selection->tracks, &ontrack);
1121 r = find_next_region (pos, point, dir, track_views, &ontrack);
1130 pos = r->first_frame ();
1134 pos = r->last_frame ();
1138 pos = r->adjust_to_sync (r->first_frame());
1143 RouteTimeAxisView *rtav;
1145 if (ontrack != 0 && (rtav = dynamic_cast<RouteTimeAxisView*>(ontrack)) != 0) {
1146 if (rtav->track() != 0) {
1147 speed = rtav->track()->speed();
1151 pos = track_frame_to_session_frame(pos, speed);
1157 Editor::selected_marker_to_next_region_point (RegionPoint point)
1159 selected_marker_to_region_point (point, 1);
1163 Editor::selected_marker_to_previous_region_point (RegionPoint point)
1165 selected_marker_to_region_point (point, -1);
1169 Editor::selected_marker_to_selection_start ()
1175 if (!_session || selection->markers.empty()) {
1179 if ((loc = find_location_from_marker (selection->markers.front(), ignored)) == 0) {
1183 switch (mouse_mode) {
1185 if (!selection->regions.empty()) {
1186 pos = selection->regions.start();
1191 if (!selection->time.empty()) {
1192 pos = selection->time.start ();
1204 Editor::selected_marker_to_selection_end ()
1210 if (!_session || selection->markers.empty()) {
1214 if ((loc = find_location_from_marker (selection->markers.front(), ignored)) == 0) {
1218 switch (mouse_mode) {
1220 if (!selection->regions.empty()) {
1221 pos = selection->regions.end_frame();
1226 if (!selection->time.empty()) {
1227 pos = selection->time.end_frame ();
1239 Editor::scroll_playhead (bool forward)
1241 framepos_t pos = playhead_cursor->current_frame ();
1242 framecnt_t delta = (framecnt_t) floor (current_page_samples() / 0.8);
1245 if (pos == max_framepos) {
1249 if (pos < max_framepos - delta) {
1268 _session->request_locate (pos);
1272 Editor::cursor_align (bool playhead_to_edit)
1278 if (playhead_to_edit) {
1280 if (selection->markers.empty()) {
1284 _session->request_locate (selection->markers.front()->position(), _session->transport_rolling());
1287 /* move selected markers to playhead */
1289 for (MarkerSelection::iterator i = selection->markers.begin(); i != selection->markers.end(); ++i) {
1292 Location* loc = find_location_from_marker (*i, ignored);
1294 if (loc->is_mark()) {
1295 loc->set_start (playhead_cursor->current_frame ());
1297 loc->set (playhead_cursor->current_frame (),
1298 playhead_cursor->current_frame () + loc->length());
1305 Editor::scroll_backward (float pages)
1307 framepos_t const one_page = (framepos_t) rint (_visible_canvas_width * samples_per_pixel);
1308 framepos_t const cnt = (framepos_t) floor (pages * one_page);
1311 if (leftmost_frame < cnt) {
1314 frame = leftmost_frame - cnt;
1317 reset_x_origin (frame);
1321 Editor::scroll_forward (float pages)
1323 framepos_t const one_page = (framepos_t) rint (_visible_canvas_width * samples_per_pixel);
1324 framepos_t const cnt = (framepos_t) floor (pages * one_page);
1327 if (max_framepos - cnt < leftmost_frame) {
1328 frame = max_framepos - cnt;
1330 frame = leftmost_frame + cnt;
1333 reset_x_origin (frame);
1337 Editor::scroll_tracks_down ()
1339 double vert_value = vertical_adjustment.get_value() + vertical_adjustment.get_page_size();
1340 if (vert_value > vertical_adjustment.get_upper() - _visible_canvas_height) {
1341 vert_value = vertical_adjustment.get_upper() - _visible_canvas_height;
1344 vertical_adjustment.set_value (vert_value);
1348 Editor::scroll_tracks_up ()
1350 vertical_adjustment.set_value (vertical_adjustment.get_value() - vertical_adjustment.get_page_size());
1354 Editor::scroll_tracks_down_line ()
1356 double vert_value = vertical_adjustment.get_value() + 60;
1358 if (vert_value > vertical_adjustment.get_upper() - _visible_canvas_height) {
1359 vert_value = vertical_adjustment.get_upper() - _visible_canvas_height;
1362 vertical_adjustment.set_value (vert_value);
1366 Editor::scroll_tracks_up_line ()
1368 reset_y_origin (vertical_adjustment.get_value() - 60);
1372 Editor::scroll_down_one_track ()
1374 TrackViewList::reverse_iterator next = track_views.rend();
1375 std::pair<TimeAxisView*,double> res;
1376 const double top_of_trackviews = vertical_adjustment.get_value();
1378 for (TrackViewList::reverse_iterator t = track_views.rbegin(); t != track_views.rend(); ++t) {
1379 if ((*t)->hidden()) {
1384 /* If this is the upper-most visible trackview, we want to display
1385 the one above it (next)
1388 res = (*t)->covers_y_position (top_of_trackviews);
1396 /* move to the track below the first one that covers the */
1398 if (next != track_views.rend()) {
1399 ensure_time_axis_view_is_visible (**next, true);
1407 Editor::scroll_up_one_track ()
1409 TrackViewList::iterator prev = track_views.end();
1410 std::pair<TimeAxisView*,double> res;
1411 double top_of_trackviews = vertical_adjustment.get_value ();
1413 for (TrackViewList::iterator t = track_views.begin(); t != track_views.end(); ++t) {
1415 if ((*t)->hidden()) {
1419 /* find the trackview at the top of the trackview group */
1420 res = (*t)->covers_y_position (top_of_trackviews);
1429 if (prev != track_views.end()) {
1430 ensure_time_axis_view_is_visible (**prev, true);
1440 Editor::tav_zoom_step (bool coarser)
1442 DisplaySuspender ds;
1446 if (selection->tracks.empty()) {
1449 ts = &selection->tracks;
1452 for (TrackViewList::iterator i = ts->begin(); i != ts->end(); ++i) {
1453 TimeAxisView *tv = (static_cast<TimeAxisView*>(*i));
1454 tv->step_height (coarser);
1459 Editor::tav_zoom_smooth (bool coarser, bool force_all)
1461 DisplaySuspender ds;
1465 if (selection->tracks.empty() || force_all) {
1468 ts = &selection->tracks;
1471 for (TrackViewList::iterator i = ts->begin(); i != ts->end(); ++i) {
1472 TimeAxisView *tv = (static_cast<TimeAxisView*>(*i));
1473 uint32_t h = tv->current_height ();
1478 if (h >= TimeAxisView::preset_height (HeightSmall)) {
1483 tv->set_height (h + 5);
1490 Editor::temporal_zoom_step (bool coarser)
1492 ENSURE_GUI_THREAD (*this, &Editor::temporal_zoom_step, coarser)
1494 framecnt_t nspp = samples_per_pixel;
1502 temporal_zoom (nspp);
1506 Editor::temporal_zoom (framecnt_t fpp)
1512 framepos_t current_page = current_page_samples();
1513 framepos_t current_leftmost = leftmost_frame;
1514 framepos_t current_rightmost;
1515 framepos_t current_center;
1516 framepos_t new_page_size;
1517 framepos_t half_page_size;
1518 framepos_t leftmost_after_zoom = 0;
1520 bool in_track_canvas;
1524 if (fpp == samples_per_pixel) {
1528 // Imposing an arbitrary limit to zoom out as too much zoom out produces
1529 // segfaults for lack of memory. If somebody decides this is not high enough I
1530 // believe it can be raisen to higher values but some limit must be in place.
1532 // This constant represents 1 day @ 48kHz on a 1600 pixel wide display
1533 // all of which is used for the editor track displays. The whole day
1534 // would be 4147200000 samples, so 2592000 samples per pixel.
1536 nfpp = min (fpp, (framecnt_t) 2592000);
1537 nfpp = max ((framecnt_t) 1, nfpp);
1539 new_page_size = (framepos_t) floor (_visible_canvas_width * nfpp);
1540 half_page_size = new_page_size / 2;
1542 switch (zoom_focus) {
1544 leftmost_after_zoom = current_leftmost;
1547 case ZoomFocusRight:
1548 current_rightmost = leftmost_frame + current_page;
1549 if (current_rightmost < new_page_size) {
1550 leftmost_after_zoom = 0;
1552 leftmost_after_zoom = current_rightmost - new_page_size;
1556 case ZoomFocusCenter:
1557 current_center = current_leftmost + (current_page/2);
1558 if (current_center < half_page_size) {
1559 leftmost_after_zoom = 0;
1561 leftmost_after_zoom = current_center - half_page_size;
1565 case ZoomFocusPlayhead:
1566 /* centre playhead */
1567 l = playhead_cursor->current_frame () - (new_page_size * 0.5);
1570 leftmost_after_zoom = 0;
1571 } else if (l > max_framepos) {
1572 leftmost_after_zoom = max_framepos - new_page_size;
1574 leftmost_after_zoom = (framepos_t) l;
1578 case ZoomFocusMouse:
1579 /* try to keep the mouse over the same point in the display */
1581 if (!mouse_frame (where, in_track_canvas)) {
1582 /* use playhead instead */
1583 where = playhead_cursor->current_frame ();
1585 if (where < half_page_size) {
1586 leftmost_after_zoom = 0;
1588 leftmost_after_zoom = where - half_page_size;
1593 l = - ((new_page_size * ((where - current_leftmost)/(double)current_page)) - where);
1596 leftmost_after_zoom = 0;
1597 } else if (l > max_framepos) {
1598 leftmost_after_zoom = max_framepos - new_page_size;
1600 leftmost_after_zoom = (framepos_t) l;
1607 /* try to keep the edit point in the same place */
1608 where = get_preferred_edit_position ();
1612 double l = - ((new_page_size * ((where - current_leftmost)/(double)current_page)) - where);
1615 leftmost_after_zoom = 0;
1616 } else if (l > max_framepos) {
1617 leftmost_after_zoom = max_framepos - new_page_size;
1619 leftmost_after_zoom = (framepos_t) l;
1623 /* edit point not defined */
1630 // leftmost_after_zoom = min (leftmost_after_zoom, _session->current_end_frame());
1632 reposition_and_zoom (leftmost_after_zoom, nfpp);
1636 Editor::calc_extra_zoom_edges(framepos_t &start, framepos_t &end)
1638 /* this func helps make sure we leave a little space
1639 at each end of the editor so that the zoom doesn't fit the region
1640 precisely to the screen.
1643 GdkScreen* screen = gdk_screen_get_default ();
1644 const gint pixwidth = gdk_screen_get_width (screen);
1645 const gint mmwidth = gdk_screen_get_width_mm (screen);
1646 const double pix_per_mm = (double) pixwidth/ (double) mmwidth;
1647 const double one_centimeter_in_pixels = pix_per_mm * 10.0;
1649 const framepos_t range = end - start;
1650 const framecnt_t new_fpp = (framecnt_t) ceil ((double) range / (double) _visible_canvas_width);
1651 const framepos_t extra_samples = (framepos_t) floor (one_centimeter_in_pixels * new_fpp);
1653 if (start > extra_samples) {
1654 start -= extra_samples;
1659 if (max_framepos - extra_samples > end) {
1660 end += extra_samples;
1667 Editor::temporal_zoom_region (bool both_axes)
1669 framepos_t start = max_framepos;
1671 set<TimeAxisView*> tracks;
1673 RegionSelection rs = get_regions_from_selection_and_entered ();
1679 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
1681 if ((*i)->region()->position() < start) {
1682 start = (*i)->region()->position();
1685 if ((*i)->region()->last_frame() + 1 > end) {
1686 end = (*i)->region()->last_frame() + 1;
1689 tracks.insert (&((*i)->get_time_axis_view()));
1692 if ((start == 0 && end == 0) || end < start) {
1696 calc_extra_zoom_edges (start, end);
1698 /* if we're zooming on both axes we need to save track heights etc.
1701 undo_visual_stack.push_back (current_visual_state (both_axes));
1703 PBD::Unwinder<bool> nsv (no_save_visual, true);
1705 temporal_zoom_by_frame (start, end);
1708 uint32_t per_track_height = (uint32_t) floor ((_visible_canvas_height - 10.0) / tracks.size());
1710 /* set visible track heights appropriately */
1712 for (set<TimeAxisView*>::iterator t = tracks.begin(); t != tracks.end(); ++t) {
1713 (*t)->set_height (per_track_height);
1716 /* hide irrelevant tracks */
1718 DisplaySuspender ds;
1720 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1721 if (find (tracks.begin(), tracks.end(), (*i)) == tracks.end()) {
1722 hide_track_in_display (*i);
1726 vertical_adjustment.set_value (0.0);
1729 redo_visual_stack.push_back (current_visual_state (both_axes));
1733 Editor::zoom_to_region (bool both_axes)
1735 temporal_zoom_region (both_axes);
1739 Editor::temporal_zoom_selection (bool both_axes)
1741 if (!selection) return;
1743 //if a range is selected, zoom to that
1744 if (!selection->time.empty()) {
1746 framepos_t start = selection->time.start();
1747 framepos_t end = selection->time.end_frame();
1749 calc_extra_zoom_edges(start, end);
1751 temporal_zoom_by_frame (start, end);
1754 fit_selected_tracks();
1757 temporal_zoom_region (both_axes);
1764 Editor::temporal_zoom_session ()
1766 ENSURE_GUI_THREAD (*this, &Editor::temporal_zoom_session)
1769 framecnt_t start = _session->current_start_frame();
1770 framecnt_t end = _session->current_end_frame();
1772 if (_session->actively_recording () ) {
1773 framepos_t cur = playhead_cursor->current_frame ();
1775 /* recording beyond the end marker; zoom out
1776 * by 5 seconds more so that if 'follow
1777 * playhead' is active we don't immediately
1780 end = cur + _session->frame_rate() * 5;
1784 if ((start == 0 && end == 0) || end < start) {
1788 calc_extra_zoom_edges(start, end);
1790 temporal_zoom_by_frame (start, end);
1795 Editor::temporal_zoom_by_frame (framepos_t start, framepos_t end)
1797 if (!_session) return;
1799 if ((start == 0 && end == 0) || end < start) {
1803 framepos_t range = end - start;
1805 const framecnt_t new_fpp = (framecnt_t) ceil ((double) range / (double) _visible_canvas_width);
1807 framepos_t new_page = range;
1808 framepos_t middle = (framepos_t) floor ((double) start + ((double) range / 2.0f));
1809 framepos_t new_leftmost = (framepos_t) floor ((double) middle - ((double) new_page / 2.0f));
1811 if (new_leftmost > middle) {
1815 if (new_leftmost < 0) {
1819 reposition_and_zoom (new_leftmost, new_fpp);
1823 Editor::temporal_zoom_to_frame (bool coarser, framepos_t frame)
1829 framecnt_t range_before = frame - leftmost_frame;
1833 if (samples_per_pixel <= 1) {
1836 new_spp = samples_per_pixel + (samples_per_pixel/2);
1838 range_before += range_before/2;
1840 if (samples_per_pixel >= 1) {
1841 new_spp = samples_per_pixel - (samples_per_pixel/2);
1843 /* could bail out here since we cannot zoom any finer,
1844 but leave that to the equality test below
1846 new_spp = samples_per_pixel;
1849 range_before -= range_before/2;
1852 if (new_spp == samples_per_pixel) {
1856 /* zoom focus is automatically taken as @param frame when this
1860 framepos_t new_leftmost = frame - (framepos_t)range_before;
1862 if (new_leftmost > frame) {
1866 if (new_leftmost < 0) {
1870 reposition_and_zoom (new_leftmost, new_spp);
1875 Editor::choose_new_marker_name(string &name) {
1877 if (!Config->get_name_new_markers()) {
1878 /* don't prompt user for a new name */
1882 ArdourPrompter dialog (true);
1884 dialog.set_prompt (_("New Name:"));
1886 dialog.set_title (_("New Location Marker"));
1888 dialog.set_name ("MarkNameWindow");
1889 dialog.set_size_request (250, -1);
1890 dialog.set_position (Gtk::WIN_POS_MOUSE);
1892 dialog.add_button (Stock::OK, RESPONSE_ACCEPT);
1893 dialog.set_initial_text (name);
1897 switch (dialog.run ()) {
1898 case RESPONSE_ACCEPT:
1904 dialog.get_result(name);
1911 Editor::add_location_from_selection ()
1915 if (selection->time.empty()) {
1919 if (_session == 0 || clicked_axisview == 0) {
1923 framepos_t start = selection->time[clicked_selection].start;
1924 framepos_t end = selection->time[clicked_selection].end;
1926 _session->locations()->next_available_name(rangename,"selection");
1927 Location *location = new Location (*_session, start, end, rangename, Location::IsRangeMarker);
1929 _session->begin_reversible_command (_("add marker"));
1930 XMLNode &before = _session->locations()->get_state();
1931 _session->locations()->add (location, true);
1932 XMLNode &after = _session->locations()->get_state();
1933 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
1934 _session->commit_reversible_command ();
1938 Editor::add_location_mark (framepos_t where)
1942 select_new_marker = true;
1944 _session->locations()->next_available_name(markername,"mark");
1945 if (!choose_new_marker_name(markername)) {
1948 Location *location = new Location (*_session, where, where, markername, Location::IsMark);
1949 _session->begin_reversible_command (_("add marker"));
1950 XMLNode &before = _session->locations()->get_state();
1951 _session->locations()->add (location, true);
1952 XMLNode &after = _session->locations()->get_state();
1953 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
1954 _session->commit_reversible_command ();
1958 Editor::add_location_from_playhead_cursor ()
1960 add_location_mark (_session->audible_frame());
1964 Editor::remove_location_at_playhead_cursor ()
1969 _session->begin_reversible_command (_("remove marker"));
1970 XMLNode &before = _session->locations()->get_state();
1971 bool removed = false;
1973 //find location(s) at this time
1974 Locations::LocationList locs;
1975 _session->locations()->find_all_between (_session->audible_frame(), _session->audible_frame()+1, locs, Location::Flags(0));
1976 for (Locations::LocationList::iterator i = locs.begin(); i != locs.end(); ++i) {
1977 if ((*i)->is_mark()) {
1978 _session->locations()->remove (*i);
1985 XMLNode &after = _session->locations()->get_state();
1986 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
1987 _session->commit_reversible_command ();
1992 /** Add a range marker around each selected region */
1994 Editor::add_locations_from_region ()
1996 RegionSelection rs = get_regions_from_selection_and_entered ();
2002 _session->begin_reversible_command (selection->regions.size () > 1 ? _("add markers") : _("add marker"));
2003 XMLNode &before = _session->locations()->get_state();
2005 for (RegionSelection::iterator i = rs.begin (); i != rs.end (); ++i) {
2007 boost::shared_ptr<Region> region = (*i)->region ();
2009 Location *location = new Location (*_session, region->position(), region->last_frame(), region->name(), Location::IsRangeMarker);
2011 _session->locations()->add (location, true);
2014 XMLNode &after = _session->locations()->get_state();
2015 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2016 _session->commit_reversible_command ();
2019 /** Add a single range marker around all selected regions */
2021 Editor::add_location_from_region ()
2023 RegionSelection rs = get_regions_from_selection_and_entered ();
2029 _session->begin_reversible_command (_("add marker"));
2030 XMLNode &before = _session->locations()->get_state();
2034 if (rs.size() > 1) {
2035 _session->locations()->next_available_name(markername, "regions");
2037 RegionView* rv = *(rs.begin());
2038 boost::shared_ptr<Region> region = rv->region();
2039 markername = region->name();
2042 if (!choose_new_marker_name(markername)) {
2046 // single range spanning all selected
2047 Location *location = new Location (*_session, selection->regions.start(), selection->regions.end_frame(), markername, Location::IsRangeMarker);
2048 _session->locations()->add (location, true);
2050 XMLNode &after = _session->locations()->get_state();
2051 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2052 _session->commit_reversible_command ();
2058 Editor::jump_forward_to_mark ()
2064 framepos_t pos = _session->locations()->first_mark_after (playhead_cursor->current_frame());
2070 _session->request_locate (pos, _session->transport_rolling());
2074 Editor::jump_backward_to_mark ()
2080 framepos_t pos = _session->locations()->first_mark_before (playhead_cursor->current_frame());
2086 _session->request_locate (pos, _session->transport_rolling());
2092 framepos_t const pos = _session->audible_frame ();
2095 _session->locations()->next_available_name (markername, "mark");
2097 if (!choose_new_marker_name (markername)) {
2101 _session->locations()->add (new Location (*_session, pos, 0, markername, Location::IsMark), true);
2105 Editor::clear_markers ()
2108 _session->begin_reversible_command (_("clear markers"));
2109 XMLNode &before = _session->locations()->get_state();
2110 _session->locations()->clear_markers ();
2111 XMLNode &after = _session->locations()->get_state();
2112 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2113 _session->commit_reversible_command ();
2118 Editor::clear_ranges ()
2121 _session->begin_reversible_command (_("clear ranges"));
2122 XMLNode &before = _session->locations()->get_state();
2124 _session->locations()->clear_ranges ();
2126 XMLNode &after = _session->locations()->get_state();
2127 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2128 _session->commit_reversible_command ();
2133 Editor::clear_locations ()
2135 _session->begin_reversible_command (_("clear locations"));
2136 XMLNode &before = _session->locations()->get_state();
2137 _session->locations()->clear ();
2138 XMLNode &after = _session->locations()->get_state();
2139 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2140 _session->commit_reversible_command ();
2141 _session->locations()->clear ();
2145 Editor::unhide_markers ()
2147 for (LocationMarkerMap::iterator i = location_markers.begin(); i != location_markers.end(); ++i) {
2148 Location *l = (*i).first;
2149 if (l->is_hidden() && l->is_mark()) {
2150 l->set_hidden(false, this);
2156 Editor::unhide_ranges ()
2158 for (LocationMarkerMap::iterator i = location_markers.begin(); i != location_markers.end(); ++i) {
2159 Location *l = (*i).first;
2160 if (l->is_hidden() && l->is_range_marker()) {
2161 l->set_hidden(false, this);
2166 /* INSERT/REPLACE */
2169 Editor::insert_region_list_selection (float times)
2171 RouteTimeAxisView *tv = 0;
2172 boost::shared_ptr<Playlist> playlist;
2174 if (clicked_routeview != 0) {
2175 tv = clicked_routeview;
2176 } else if (!selection->tracks.empty()) {
2177 if ((tv = dynamic_cast<RouteTimeAxisView*>(selection->tracks.front())) == 0) {
2180 } else if (entered_track != 0) {
2181 if ((tv = dynamic_cast<RouteTimeAxisView*>(entered_track)) == 0) {
2188 if ((playlist = tv->playlist()) == 0) {
2192 boost::shared_ptr<Region> region = _regions->get_single_selection ();
2197 begin_reversible_command (_("insert region"));
2198 playlist->clear_changes ();
2199 playlist->add_region ((RegionFactory::create (region, true)), get_preferred_edit_position(), times);
2200 if (Config->get_edit_mode() == Ripple)
2201 playlist->ripple (get_preferred_edit_position(), region->length() * times, boost::shared_ptr<Region>());
2203 _session->add_command(new StatefulDiffCommand (playlist));
2204 commit_reversible_command ();
2207 /* BUILT-IN EFFECTS */
2210 Editor::reverse_selection ()
2215 /* GAIN ENVELOPE EDITING */
2218 Editor::edit_envelope ()
2225 Editor::transition_to_rolling (bool fwd)
2231 if (_session->config.get_external_sync()) {
2232 switch (Config->get_sync_source()) {
2236 /* transport controlled by the master */
2241 if (_session->is_auditioning()) {
2242 _session->cancel_audition ();
2246 _session->request_transport_speed (fwd ? 1.0f : -1.0f);
2250 Editor::play_from_start ()
2252 _session->request_locate (_session->current_start_frame(), true);
2256 Editor::play_from_edit_point ()
2258 _session->request_locate (get_preferred_edit_position(), true);
2262 Editor::play_from_edit_point_and_return ()
2264 framepos_t start_frame;
2265 framepos_t return_frame;
2267 start_frame = get_preferred_edit_position (true);
2269 if (_session->transport_rolling()) {
2270 _session->request_locate (start_frame, false);
2274 /* don't reset the return frame if its already set */
2276 if ((return_frame = _session->requested_return_frame()) < 0) {
2277 return_frame = _session->audible_frame();
2280 if (start_frame >= 0) {
2281 _session->request_roll_at_and_return (start_frame, return_frame);
2286 Editor::play_selection ()
2288 if (selection->time.empty()) {
2292 _session->request_play_range (&selection->time, true);
2296 Editor::get_preroll ()
2298 return 1.0 /*Config->get_edit_preroll_seconds()*/ * _session->frame_rate();
2303 Editor::maybe_locate_with_edit_preroll ( framepos_t location )
2305 if ( _session->transport_rolling() || !Config->get_follow_edits() || _ignore_follow_edits )
2308 location -= get_preroll();
2310 //don't try to locate before the beginning of time
2314 //if follow_playhead is on, keep the playhead on the screen
2315 if ( _follow_playhead )
2316 if ( location < leftmost_frame )
2317 location = leftmost_frame;
2319 _session->request_locate( location );
2323 Editor::play_with_preroll ()
2325 if (selection->time.empty()) {
2328 framepos_t preroll = get_preroll();
2330 framepos_t start = 0;
2331 if (selection->time[clicked_selection].start > preroll)
2332 start = selection->time[clicked_selection].start - preroll;
2334 framepos_t end = selection->time[clicked_selection].end + preroll;
2336 AudioRange ar (start, end, 0);
2337 list<AudioRange> lar;
2340 _session->request_play_range (&lar, true);
2345 Editor::play_location (Location& location)
2347 if (location.start() <= location.end()) {
2351 _session->request_bounded_roll (location.start(), location.end());
2355 Editor::loop_location (Location& location)
2357 if (location.start() <= location.end()) {
2363 if ((tll = transport_loop_location()) != 0) {
2364 tll->set (location.start(), location.end());
2366 // enable looping, reposition and start rolling
2367 _session->request_locate (tll->start(), true);
2368 _session->request_play_loop (true);
2373 Editor::do_layer_operation (LayerOperation op)
2375 if (selection->regions.empty ()) {
2379 bool const multiple = selection->regions.size() > 1;
2383 begin_reversible_command (_("raise regions"));
2385 begin_reversible_command (_("raise region"));
2391 begin_reversible_command (_("raise regions to top"));
2393 begin_reversible_command (_("raise region to top"));
2399 begin_reversible_command (_("lower regions"));
2401 begin_reversible_command (_("lower region"));
2407 begin_reversible_command (_("lower regions to bottom"));
2409 begin_reversible_command (_("lower region"));
2414 set<boost::shared_ptr<Playlist> > playlists = selection->regions.playlists ();
2415 for (set<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
2416 (*i)->clear_owned_changes ();
2419 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
2420 boost::shared_ptr<Region> r = (*i)->region ();
2432 r->lower_to_bottom ();
2436 for (set<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
2437 vector<Command*> cmds;
2439 _session->add_commands (cmds);
2442 commit_reversible_command ();
2446 Editor::raise_region ()
2448 do_layer_operation (Raise);
2452 Editor::raise_region_to_top ()
2454 do_layer_operation (RaiseToTop);
2458 Editor::lower_region ()
2460 do_layer_operation (Lower);
2464 Editor::lower_region_to_bottom ()
2466 do_layer_operation (LowerToBottom);
2469 /** Show the region editor for the selected regions */
2471 Editor::show_region_properties ()
2473 selection->foreach_regionview (&RegionView::show_region_editor);
2476 /** Show the midi list editor for the selected MIDI regions */
2478 Editor::show_midi_list_editor ()
2480 selection->foreach_midi_regionview (&MidiRegionView::show_list_editor);
2484 Editor::rename_region ()
2486 RegionSelection rs = get_regions_from_selection_and_entered ();
2492 ArdourDialog d (*this, _("Rename Region"), true, false);
2494 Label label (_("New name:"));
2497 hbox.set_spacing (6);
2498 hbox.pack_start (label, false, false);
2499 hbox.pack_start (entry, true, true);
2501 d.get_vbox()->set_border_width (12);
2502 d.get_vbox()->pack_start (hbox, false, false);
2504 d.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
2505 d.add_button(Gtk::Stock::OK, Gtk::RESPONSE_OK);
2507 d.set_size_request (300, -1);
2509 entry.set_text (rs.front()->region()->name());
2510 entry.select_region (0, -1);
2512 entry.signal_activate().connect (sigc::bind (sigc::mem_fun (d, &Dialog::response), RESPONSE_OK));
2518 int const ret = d.run();
2522 if (ret != RESPONSE_OK) {
2526 std::string str = entry.get_text();
2527 strip_whitespace_edges (str);
2529 rs.front()->region()->set_name (str);
2530 _regions->redisplay ();
2535 Editor::audition_playlist_region_via_route (boost::shared_ptr<Region> region, Route& route)
2537 if (_session->is_auditioning()) {
2538 _session->cancel_audition ();
2541 // note: some potential for creativity here, because region doesn't
2542 // have to belong to the playlist that Route is handling
2544 // bool was_soloed = route.soloed();
2546 route.set_solo (true, this);
2548 _session->request_bounded_roll (region->position(), region->position() + region->length());
2550 /* XXX how to unset the solo state ? */
2553 /** Start an audition of the first selected region */
2555 Editor::play_edit_range ()
2557 framepos_t start, end;
2559 if (get_edit_op_range (start, end)) {
2560 _session->request_bounded_roll (start, end);
2565 Editor::play_selected_region ()
2567 framepos_t start = max_framepos;
2570 RegionSelection rs = get_regions_from_selection_and_entered ();
2576 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
2577 if ((*i)->region()->position() < start) {
2578 start = (*i)->region()->position();
2580 if ((*i)->region()->last_frame() + 1 > end) {
2581 end = (*i)->region()->last_frame() + 1;
2585 _session->request_bounded_roll (start, end);
2589 Editor::audition_playlist_region_standalone (boost::shared_ptr<Region> region)
2591 _session->audition_region (region);
2595 Editor::region_from_selection ()
2597 if (clicked_axisview == 0) {
2601 if (selection->time.empty()) {
2605 framepos_t start = selection->time[clicked_selection].start;
2606 framepos_t end = selection->time[clicked_selection].end;
2608 TrackViewList tracks = get_tracks_for_range_action ();
2610 framepos_t selection_cnt = end - start + 1;
2612 for (TrackSelection::iterator i = tracks.begin(); i != tracks.end(); ++i) {
2613 boost::shared_ptr<Region> current;
2614 boost::shared_ptr<Playlist> pl;
2615 framepos_t internal_start;
2618 if ((pl = (*i)->playlist()) == 0) {
2622 if ((current = pl->top_region_at (start)) == 0) {
2626 internal_start = start - current->position();
2627 RegionFactory::region_name (new_name, current->name(), true);
2631 plist.add (ARDOUR::Properties::start, current->start() + internal_start);
2632 plist.add (ARDOUR::Properties::length, selection_cnt);
2633 plist.add (ARDOUR::Properties::name, new_name);
2634 plist.add (ARDOUR::Properties::layer, 0);
2636 boost::shared_ptr<Region> region (RegionFactory::create (current, plist));
2641 Editor::create_region_from_selection (vector<boost::shared_ptr<Region> >& new_regions)
2643 if (selection->time.empty() || selection->tracks.empty()) {
2647 framepos_t start = selection->time[clicked_selection].start;
2648 framepos_t end = selection->time[clicked_selection].end;
2650 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
2651 sort_track_selection (ts);
2653 for (TrackSelection::iterator i = ts.begin(); i != ts.end(); ++i) {
2654 boost::shared_ptr<Region> current;
2655 boost::shared_ptr<Playlist> playlist;
2656 framepos_t internal_start;
2659 if ((playlist = (*i)->playlist()) == 0) {
2663 if ((current = playlist->top_region_at(start)) == 0) {
2667 internal_start = start - current->position();
2668 RegionFactory::region_name (new_name, current->name(), true);
2672 plist.add (ARDOUR::Properties::start, current->start() + internal_start);
2673 plist.add (ARDOUR::Properties::length, end - start + 1);
2674 plist.add (ARDOUR::Properties::name, new_name);
2676 new_regions.push_back (RegionFactory::create (current, plist));
2681 Editor::split_multichannel_region ()
2683 RegionSelection rs = get_regions_from_selection_and_entered ();
2689 vector< boost::shared_ptr<Region> > v;
2691 for (list<RegionView*>::iterator x = rs.begin(); x != rs.end(); ++x) {
2692 (*x)->region()->separate_by_channel (*_session, v);
2697 Editor::new_region_from_selection ()
2699 region_from_selection ();
2700 cancel_selection ();
2704 add_if_covered (RegionView* rv, const AudioRange* ar, RegionSelection* rs)
2706 switch (rv->region()->coverage (ar->start, ar->end - 1)) {
2707 // n.b. -1 because AudioRange::end is one past the end, but coverage expects inclusive ranges
2708 case Evoral::OverlapNone:
2716 * - selected tracks, or if there are none...
2717 * - tracks containing selected regions, or if there are none...
2722 Editor::get_tracks_for_range_action () const
2726 if (selection->tracks.empty()) {
2728 /* use tracks with selected regions */
2730 RegionSelection rs = selection->regions;
2732 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
2733 TimeAxisView* tv = &(*i)->get_time_axis_view();
2735 if (!t.contains (tv)) {
2741 /* no regions and no tracks: use all tracks */
2747 t = selection->tracks;
2750 return t.filter_to_unique_playlists();
2754 Editor::separate_regions_between (const TimeSelection& ts)
2756 bool in_command = false;
2757 boost::shared_ptr<Playlist> playlist;
2758 RegionSelection new_selection;
2760 TrackViewList tmptracks = get_tracks_for_range_action ();
2761 sort_track_selection (tmptracks);
2763 for (TrackSelection::iterator i = tmptracks.begin(); i != tmptracks.end(); ++i) {
2765 RouteTimeAxisView* rtv;
2767 if ((rtv = dynamic_cast<RouteTimeAxisView*> ((*i))) != 0) {
2769 if (rtv->is_track()) {
2771 /* no edits to destructive tracks */
2773 if (rtv->track()->destructive()) {
2777 if ((playlist = rtv->playlist()) != 0) {
2779 playlist->clear_changes ();
2781 /* XXX need to consider musical time selections here at some point */
2783 double speed = rtv->track()->speed();
2786 for (list<AudioRange>::const_iterator t = ts.begin(); t != ts.end(); ++t) {
2788 sigc::connection c = rtv->view()->RegionViewAdded.connect (
2789 sigc::mem_fun(*this, &Editor::collect_new_region_view));
2791 latest_regionviews.clear ();
2793 playlist->partition ((framepos_t)((*t).start * speed),
2794 (framepos_t)((*t).end * speed), false);
2798 if (!latest_regionviews.empty()) {
2800 rtv->view()->foreach_regionview (sigc::bind (
2801 sigc::ptr_fun (add_if_covered),
2802 &(*t), &new_selection));
2805 begin_reversible_command (_("separate"));
2809 /* pick up changes to existing regions */
2811 vector<Command*> cmds;
2812 playlist->rdiff (cmds);
2813 _session->add_commands (cmds);
2815 /* pick up changes to the playlist itself (adds/removes)
2818 _session->add_command(new StatefulDiffCommand (playlist));
2827 // selection->set (new_selection);
2829 commit_reversible_command ();
2833 struct PlaylistState {
2834 boost::shared_ptr<Playlist> playlist;
2838 /** Take tracks from get_tracks_for_range_action and cut any regions
2839 * on those tracks so that the tracks are empty over the time
2843 Editor::separate_region_from_selection ()
2845 /* preferentially use *all* ranges in the time selection if we're in range mode
2846 to allow discontiguous operation, since get_edit_op_range() currently
2847 returns a single range.
2850 if (!selection->time.empty()) {
2852 separate_regions_between (selection->time);
2859 if (get_edit_op_range (start, end)) {
2861 AudioRange ar (start, end, 1);
2865 separate_regions_between (ts);
2871 Editor::separate_region_from_punch ()
2873 Location* loc = _session->locations()->auto_punch_location();
2875 separate_regions_using_location (*loc);
2880 Editor::separate_region_from_loop ()
2882 Location* loc = _session->locations()->auto_loop_location();
2884 separate_regions_using_location (*loc);
2889 Editor::separate_regions_using_location (Location& loc)
2891 if (loc.is_mark()) {
2895 AudioRange ar (loc.start(), loc.end(), 1);
2900 separate_regions_between (ts);
2903 /** Separate regions under the selected region */
2905 Editor::separate_under_selected_regions ()
2907 vector<PlaylistState> playlists;
2911 rs = get_regions_from_selection_and_entered();
2913 if (!_session || rs.empty()) {
2917 begin_reversible_command (_("separate region under"));
2919 list<boost::shared_ptr<Region> > regions_to_remove;
2921 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
2922 // we can't just remove the region(s) in this loop because
2923 // this removes them from the RegionSelection, and they thus
2924 // disappear from underneath the iterator, and the ++i above
2925 // SEGVs in a puzzling fashion.
2927 // so, first iterate over the regions to be removed from rs and
2928 // add them to the regions_to_remove list, and then
2929 // iterate over the list to actually remove them.
2931 regions_to_remove.push_back ((*i)->region());
2934 for (list<boost::shared_ptr<Region> >::iterator rl = regions_to_remove.begin(); rl != regions_to_remove.end(); ++rl) {
2936 boost::shared_ptr<Playlist> playlist = (*rl)->playlist();
2939 // is this check necessary?
2943 vector<PlaylistState>::iterator i;
2945 //only take state if this is a new playlist.
2946 for (i = playlists.begin(); i != playlists.end(); ++i) {
2947 if ((*i).playlist == playlist) {
2952 if (i == playlists.end()) {
2954 PlaylistState before;
2955 before.playlist = playlist;
2956 before.before = &playlist->get_state();
2958 playlist->freeze ();
2959 playlists.push_back(before);
2962 //Partition on the region bounds
2963 playlist->partition ((*rl)->first_frame() - 1, (*rl)->last_frame() + 1, true);
2965 //Re-add region that was just removed due to the partition operation
2966 playlist->add_region( (*rl), (*rl)->first_frame() );
2969 vector<PlaylistState>::iterator pl;
2971 for (pl = playlists.begin(); pl != playlists.end(); ++pl) {
2972 (*pl).playlist->thaw ();
2973 _session->add_command(new MementoCommand<Playlist>(*(*pl).playlist, (*pl).before, &(*pl).playlist->get_state()));
2976 commit_reversible_command ();
2980 Editor::crop_region_to_selection ()
2982 if (!selection->time.empty()) {
2984 crop_region_to (selection->time.start(), selection->time.end_frame());
2991 if (get_edit_op_range (start, end)) {
2992 crop_region_to (start, end);
2999 Editor::crop_region_to (framepos_t start, framepos_t end)
3001 vector<boost::shared_ptr<Playlist> > playlists;
3002 boost::shared_ptr<Playlist> playlist;
3005 if (selection->tracks.empty()) {
3006 ts = track_views.filter_to_unique_playlists();
3008 ts = selection->tracks.filter_to_unique_playlists ();
3011 sort_track_selection (ts);
3013 for (TrackSelection::iterator i = ts.begin(); i != ts.end(); ++i) {
3015 RouteTimeAxisView* rtv;
3017 if ((rtv = dynamic_cast<RouteTimeAxisView*> ((*i))) != 0) {
3019 boost::shared_ptr<Track> t = rtv->track();
3021 if (t != 0 && ! t->destructive()) {
3023 if ((playlist = rtv->playlist()) != 0) {
3024 playlists.push_back (playlist);
3030 if (playlists.empty()) {
3034 framepos_t the_start;
3038 begin_reversible_command (_("trim to selection"));
3040 for (vector<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
3042 boost::shared_ptr<Region> region;
3046 if ((region = (*i)->top_region_at(the_start)) == 0) {
3050 /* now adjust lengths to that we do the right thing
3051 if the selection extends beyond the region
3054 the_start = max (the_start, (framepos_t) region->position());
3055 if (max_framepos - the_start < region->length()) {
3056 the_end = the_start + region->length() - 1;
3058 the_end = max_framepos;
3060 the_end = min (end, the_end);
3061 cnt = the_end - the_start + 1;
3063 region->clear_changes ();
3064 region->trim_to (the_start, cnt);
3065 _session->add_command (new StatefulDiffCommand (region));
3068 commit_reversible_command ();
3072 Editor::region_fill_track ()
3074 RegionSelection rs = get_regions_from_selection_and_entered ();
3076 if (!_session || rs.empty()) {
3080 framepos_t const end = _session->current_end_frame ();
3082 begin_reversible_command (Operations::region_fill);
3084 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3086 boost::shared_ptr<Region> region ((*i)->region());
3088 boost::shared_ptr<Playlist> pl = region->playlist();
3090 if (end <= region->last_frame()) {
3094 double times = (double) (end - region->last_frame()) / (double) region->length();
3100 pl->clear_changes ();
3101 pl->add_region (RegionFactory::create (region, true), region->last_frame(), times);
3102 _session->add_command (new StatefulDiffCommand (pl));
3105 commit_reversible_command ();
3109 Editor::region_fill_selection ()
3111 if (clicked_routeview == 0 || !clicked_routeview->is_audio_track()) {
3115 if (selection->time.empty()) {
3119 boost::shared_ptr<Region> region = _regions->get_single_selection ();
3124 framepos_t start = selection->time[clicked_selection].start;
3125 framepos_t end = selection->time[clicked_selection].end;
3127 boost::shared_ptr<Playlist> playlist;
3129 if (selection->tracks.empty()) {
3133 framepos_t selection_length = end - start;
3134 float times = (float)selection_length / region->length();
3136 begin_reversible_command (Operations::fill_selection);
3138 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
3140 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
3142 if ((playlist = (*i)->playlist()) == 0) {
3146 playlist->clear_changes ();
3147 playlist->add_region (RegionFactory::create (region, true), start, times);
3148 _session->add_command (new StatefulDiffCommand (playlist));
3151 commit_reversible_command ();
3155 Editor::set_region_sync_position ()
3157 set_sync_point (get_preferred_edit_position (), get_regions_from_selection_and_edit_point ());
3161 Editor::set_sync_point (framepos_t where, const RegionSelection& rs)
3163 bool in_command = false;
3165 for (RegionSelection::const_iterator r = rs.begin(); r != rs.end(); ++r) {
3167 if (!(*r)->region()->covers (where)) {
3171 boost::shared_ptr<Region> region ((*r)->region());
3174 begin_reversible_command (_("set sync point"));
3178 region->clear_changes ();
3179 region->set_sync_position (where);
3180 _session->add_command(new StatefulDiffCommand (region));
3184 commit_reversible_command ();
3188 /** Remove the sync positions of the selection */
3190 Editor::remove_region_sync ()
3192 RegionSelection rs = get_regions_from_selection_and_entered ();
3198 begin_reversible_command (_("remove region sync"));
3200 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3202 (*i)->region()->clear_changes ();
3203 (*i)->region()->clear_sync_position ();
3204 _session->add_command(new StatefulDiffCommand ((*i)->region()));
3207 commit_reversible_command ();
3211 Editor::naturalize_region ()
3213 RegionSelection rs = get_regions_from_selection_and_entered ();
3219 if (rs.size() > 1) {
3220 begin_reversible_command (_("move regions to original position"));
3222 begin_reversible_command (_("move region to original position"));
3225 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3226 (*i)->region()->clear_changes ();
3227 (*i)->region()->move_to_natural_position ();
3228 _session->add_command (new StatefulDiffCommand ((*i)->region()));
3231 commit_reversible_command ();
3235 Editor::align_regions (RegionPoint what)
3237 RegionSelection const rs = get_regions_from_selection_and_edit_point ();
3243 begin_reversible_command (_("align selection"));
3245 framepos_t const position = get_preferred_edit_position ();
3247 for (RegionSelection::const_iterator i = rs.begin(); i != rs.end(); ++i) {
3248 align_region_internal ((*i)->region(), what, position);
3251 commit_reversible_command ();
3254 struct RegionSortByTime {
3255 bool operator() (const RegionView* a, const RegionView* b) {
3256 return a->region()->position() < b->region()->position();
3261 Editor::align_regions_relative (RegionPoint point)
3263 RegionSelection const rs = get_regions_from_selection_and_edit_point ();
3269 framepos_t const position = get_preferred_edit_position ();
3271 framepos_t distance = 0;
3275 list<RegionView*> sorted;
3276 rs.by_position (sorted);
3278 boost::shared_ptr<Region> r ((*sorted.begin())->region());
3283 if (position > r->position()) {
3284 distance = position - r->position();
3286 distance = r->position() - position;
3292 if (position > r->last_frame()) {
3293 distance = position - r->last_frame();
3294 pos = r->position() + distance;
3296 distance = r->last_frame() - position;
3297 pos = r->position() - distance;
3303 pos = r->adjust_to_sync (position);
3304 if (pos > r->position()) {
3305 distance = pos - r->position();
3307 distance = r->position() - pos;
3313 if (pos == r->position()) {
3317 begin_reversible_command (_("align selection (relative)"));
3319 /* move first one specially */
3321 r->clear_changes ();
3322 r->set_position (pos);
3323 _session->add_command(new StatefulDiffCommand (r));
3325 /* move rest by the same amount */
3329 for (list<RegionView*>::iterator i = sorted.begin(); i != sorted.end(); ++i) {
3331 boost::shared_ptr<Region> region ((*i)->region());
3333 region->clear_changes ();
3336 region->set_position (region->position() + distance);
3338 region->set_position (region->position() - distance);
3341 _session->add_command(new StatefulDiffCommand (region));
3345 commit_reversible_command ();
3349 Editor::align_region (boost::shared_ptr<Region> region, RegionPoint point, framepos_t position)
3351 begin_reversible_command (_("align region"));
3352 align_region_internal (region, point, position);
3353 commit_reversible_command ();
3357 Editor::align_region_internal (boost::shared_ptr<Region> region, RegionPoint point, framepos_t position)
3359 region->clear_changes ();
3363 region->set_position (region->adjust_to_sync (position));
3367 if (position > region->length()) {
3368 region->set_position (position - region->length());
3373 region->set_position (position);
3377 _session->add_command(new StatefulDiffCommand (region));
3381 Editor::trim_region_front ()
3387 Editor::trim_region_back ()
3389 trim_region (false);
3393 Editor::trim_region (bool front)
3395 framepos_t where = get_preferred_edit_position();
3396 RegionSelection rs = get_regions_from_selection_and_edit_point ();
3402 begin_reversible_command (front ? _("trim front") : _("trim back"));
3404 for (list<RegionView*>::const_iterator i = rs.by_layer().begin(); i != rs.by_layer().end(); ++i) {
3405 if (!(*i)->region()->locked()) {
3407 (*i)->region()->clear_changes ();
3410 (*i)->region()->trim_front (where);
3411 maybe_locate_with_edit_preroll ( where );
3413 (*i)->region()->trim_end (where);
3414 maybe_locate_with_edit_preroll ( where );
3417 _session->add_command (new StatefulDiffCommand ((*i)->region()));
3421 commit_reversible_command ();
3424 /** Trim the end of the selected regions to the position of the edit cursor */
3426 Editor::trim_region_to_loop ()
3428 Location* loc = _session->locations()->auto_loop_location();
3432 trim_region_to_location (*loc, _("trim to loop"));
3436 Editor::trim_region_to_punch ()
3438 Location* loc = _session->locations()->auto_punch_location();
3442 trim_region_to_location (*loc, _("trim to punch"));
3446 Editor::trim_region_to_location (const Location& loc, const char* str)
3448 RegionSelection rs = get_regions_from_selection_and_entered ();
3450 begin_reversible_command (str);
3452 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
3453 RegionView* rv = (*x);
3455 /* require region to span proposed trim */
3456 switch (rv->region()->coverage (loc.start(), loc.end())) {
3457 case Evoral::OverlapInternal:
3463 RouteTimeAxisView* tav = dynamic_cast<RouteTimeAxisView*> (&rv->get_time_axis_view());
3472 if (tav->track() != 0) {
3473 speed = tav->track()->speed();
3476 start = session_frame_to_track_frame (loc.start(), speed);
3477 end = session_frame_to_track_frame (loc.end(), speed);
3479 rv->region()->clear_changes ();
3480 rv->region()->trim_to (start, (end - start));
3481 _session->add_command(new StatefulDiffCommand (rv->region()));
3484 commit_reversible_command ();
3488 Editor::trim_region_to_previous_region_end ()
3490 return trim_to_region(false);
3494 Editor::trim_region_to_next_region_start ()
3496 return trim_to_region(true);
3500 Editor::trim_to_region(bool forward)
3502 RegionSelection rs = get_regions_from_selection_and_entered ();
3504 begin_reversible_command (_("trim to region"));
3506 boost::shared_ptr<Region> next_region;
3508 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
3510 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*x);
3516 AudioTimeAxisView* atav = dynamic_cast<AudioTimeAxisView*> (&arv->get_time_axis_view());
3524 if (atav->track() != 0) {
3525 speed = atav->track()->speed();
3529 boost::shared_ptr<Region> region = arv->region();
3530 boost::shared_ptr<Playlist> playlist (region->playlist());
3532 region->clear_changes ();
3536 next_region = playlist->find_next_region (region->first_frame(), Start, 1);
3542 region->trim_end((framepos_t) ( (next_region->first_frame() - 1) * speed));
3543 arv->region_changed (PropertyChange (ARDOUR::Properties::length));
3547 next_region = playlist->find_next_region (region->first_frame(), Start, 0);
3553 region->trim_front((framepos_t) ((next_region->last_frame() + 1) * speed));
3555 arv->region_changed (ARDOUR::bounds_change);
3558 _session->add_command(new StatefulDiffCommand (region));
3561 commit_reversible_command ();
3565 Editor::unfreeze_route ()
3567 if (clicked_routeview == 0 || !clicked_routeview->is_track()) {
3571 clicked_routeview->track()->unfreeze ();
3575 Editor::_freeze_thread (void* arg)
3577 return static_cast<Editor*>(arg)->freeze_thread ();
3581 Editor::freeze_thread ()
3583 /* create event pool because we may need to talk to the session */
3584 SessionEvent::create_per_thread_pool ("freeze events", 64);
3585 /* create per-thread buffers for process() tree to use */
3586 clicked_routeview->audio_track()->freeze_me (*current_interthread_info);
3587 current_interthread_info->done = true;
3592 Editor::freeze_route ()
3598 /* stop transport before we start. this is important */
3600 _session->request_transport_speed (0.0);
3602 /* wait for just a little while, because the above call is asynchronous */
3604 Glib::usleep (250000);
3606 if (clicked_routeview == 0 || !clicked_routeview->is_audio_track()) {
3610 if (!clicked_routeview->track()->bounceable (clicked_routeview->track()->main_outs(), true)) {
3612 _("This track/bus cannot be frozen because the signal adds or loses channels before reaching the outputs.\n"
3613 "This is typically caused by plugins that generate stereo output from mono input or vice versa.")
3615 d.set_title (_("Cannot freeze"));
3620 if (clicked_routeview->track()->has_external_redirects()) {
3621 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"
3622 "Freezing will only process the signal as far as the first send/insert/return."),
3623 clicked_routeview->track()->name()), true, MESSAGE_INFO, BUTTONS_NONE, true);
3625 d.add_button (_("Freeze anyway"), Gtk::RESPONSE_OK);
3626 d.add_button (_("Don't freeze"), Gtk::RESPONSE_CANCEL);
3627 d.set_title (_("Freeze Limits"));
3629 int response = d.run ();
3632 case Gtk::RESPONSE_CANCEL:
3639 InterThreadInfo itt;
3640 current_interthread_info = &itt;
3642 InterthreadProgressWindow ipw (current_interthread_info, _("Freeze"), _("Cancel Freeze"));
3644 pthread_create_and_store (X_("freezer"), &itt.thread, _freeze_thread, this);
3646 set_canvas_cursor (_cursors->wait);
3648 while (!itt.done && !itt.cancel) {
3649 gtk_main_iteration ();
3652 current_interthread_info = 0;
3653 set_canvas_cursor (current_canvas_cursor);
3657 Editor::bounce_range_selection (bool replace, bool enable_processing)
3659 if (selection->time.empty()) {
3663 TrackSelection views = selection->tracks;
3665 for (TrackViewList::iterator i = views.begin(); i != views.end(); ++i) {
3667 if (enable_processing) {
3669 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*i);
3671 if (rtv && rtv->track() && replace && enable_processing && !rtv->track()->bounceable (rtv->track()->main_outs(), false)) {
3673 _("You can't perform this operation because the processing of the signal "
3674 "will cause one or more of the tracks to end up with a region with more channels than this track has inputs.\n\n"
3675 "You can do this without processing, which is a different operation.")
3677 d.set_title (_("Cannot bounce"));
3684 framepos_t start = selection->time[clicked_selection].start;
3685 framepos_t end = selection->time[clicked_selection].end;
3686 framepos_t cnt = end - start + 1;
3688 begin_reversible_command (_("bounce range"));
3690 for (TrackViewList::iterator i = views.begin(); i != views.end(); ++i) {
3692 RouteTimeAxisView* rtv;
3694 if ((rtv = dynamic_cast<RouteTimeAxisView*> (*i)) == 0) {
3698 boost::shared_ptr<Playlist> playlist;
3700 if ((playlist = rtv->playlist()) == 0) {
3704 InterThreadInfo itt;
3706 playlist->clear_changes ();
3707 playlist->clear_owned_changes ();
3709 boost::shared_ptr<Region> r;
3711 if (enable_processing) {
3712 r = rtv->track()->bounce_range (start, start+cnt, itt, rtv->track()->main_outs(), false);
3714 r = rtv->track()->bounce_range (start, start+cnt, itt, boost::shared_ptr<Processor>(), false);
3722 list<AudioRange> ranges;
3723 ranges.push_back (AudioRange (start, start+cnt, 0));
3724 playlist->cut (ranges); // discard result
3725 playlist->add_region (r, start);
3728 vector<Command*> cmds;
3729 playlist->rdiff (cmds);
3730 _session->add_commands (cmds);
3732 _session->add_command (new StatefulDiffCommand (playlist));
3735 commit_reversible_command ();
3738 /** Delete selected regions, automation points or a time range */
3742 //special case: if the user is pointing in the editor/mixer strip, they may be trying to delete a plugin.
3743 //we need this because the editor-mixer strip is in the editor window, so it doesn't get the bindings from the mix window
3744 bool deleted = false;
3745 if ( current_mixer_strip && current_mixer_strip == MixerStrip::entered_mixer_strip() )
3746 deleted = current_mixer_strip->delete_processors ();
3752 /** Cut selected regions, automation points or a time range */
3759 /** Copy selected regions, automation points or a time range */
3767 /** @return true if a Cut, Copy or Clear is possible */
3769 Editor::can_cut_copy () const
3771 if (!selection->time.empty() || !selection->regions.empty() || !selection->points.empty())
3778 /** Cut, copy or clear selected regions, automation points or a time range.
3779 * @param op Operation (Delete, Cut, Copy or Clear)
3782 Editor::cut_copy (CutCopyOp op)
3784 /* only cancel selection if cut/copy is successful.*/
3790 opname = _("delete");
3799 opname = _("clear");
3803 /* if we're deleting something, and the mouse is still pressed,
3804 the thing we started a drag for will be gone when we release
3805 the mouse button(s). avoid this. see part 2 at the end of
3809 if (op == Delete || op == Cut || op == Clear) {
3810 if (_drags->active ()) {
3815 if ( op != Delete ) //"Delete" doesn't change copy/paste buf
3816 cut_buffer->clear ();
3818 if (entered_marker) {
3820 /* cut/delete op while pointing at a marker */
3823 Location* loc = find_location_from_marker (entered_marker, ignored);
3825 if (_session && loc) {
3826 Glib::signal_idle().connect (sigc::bind (sigc::mem_fun(*this, &Editor::really_remove_marker), loc));
3833 if (internal_editing()) {
3835 switch (effective_mouse_mode()) {
3838 begin_reversible_command (opname + ' ' + X_("MIDI"));
3840 commit_reversible_command ();
3849 bool did_edit = false;
3851 if (!selection->regions.empty() || !selection->points.empty()) {
3852 begin_reversible_command (opname + ' ' + _("objects"));
3855 if (!selection->regions.empty()) {
3856 cut_copy_regions (op, selection->regions);
3858 if (op == Cut || op == Delete) {
3859 selection->clear_regions ();
3863 if (!selection->points.empty()) {
3864 cut_copy_points (op);
3866 if (op == Cut || op == Delete) {
3867 selection->clear_points ();
3870 } else if (selection->time.empty()) {
3871 framepos_t start, end;
3872 /* no time selection, see if we can get an edit range
3875 if (get_edit_op_range (start, end)) {
3876 selection->set (start, end);
3878 } else if (!selection->time.empty()) {
3879 begin_reversible_command (opname + ' ' + _("range"));
3882 cut_copy_ranges (op);
3884 if (op == Cut || op == Delete) {
3885 selection->clear_time ();
3890 /* reset repeated paste state */
3893 commit_reversible_command ();
3896 if (op == Delete || op == Cut || op == Clear) {
3901 struct AutomationRecord {
3902 AutomationRecord () : state (0) , line(NULL) {}
3903 AutomationRecord (XMLNode* s, const AutomationLine* l) : state (s) , line (l) {}
3905 XMLNode* state; ///< state before any operation
3906 const AutomationLine* line; ///< line this came from
3907 boost::shared_ptr<Evoral::ControlList> copy; ///< copied events for the cut buffer
3910 /** Cut, copy or clear selected automation points.
3911 * @param op Operation (Cut, Copy or Clear)
3914 Editor::cut_copy_points (CutCopyOp op)
3916 if (selection->points.empty ()) {
3920 /* XXX: not ideal, as there may be more than one track involved in the point selection */
3921 _last_cut_copy_source_track = &selection->points.front()->line().trackview;
3923 /* Keep a record of the AutomationLists that we end up using in this operation */
3924 typedef std::map<boost::shared_ptr<AutomationList>, AutomationRecord> Lists;
3927 /* Go through all selected points, making an AutomationRecord for each distinct AutomationList */
3928 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
3929 const AutomationLine& line = (*i)->line();
3930 const boost::shared_ptr<AutomationList> al = line.the_list();
3931 if (lists.find (al) == lists.end ()) {
3932 /* We haven't seen this list yet, so make a record for it. This includes
3933 taking a copy of its current state, in case this is needed for undo later.
3935 lists[al] = AutomationRecord (&al->get_state (), &line);
3939 if (op == Cut || op == Copy) {
3940 /* This operation will involve putting things in the cut buffer, so create an empty
3941 ControlList for each of our source lists to put the cut buffer data in.
3943 framepos_t start = std::numeric_limits<framepos_t>::max();
3944 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
3945 i->second.copy = i->first->create (i->first->parameter (), i->first->descriptor());
3947 /* Calculate earliest start position of any point in selection. */
3948 start = std::min(start, i->second.line->session_position(i->first->begin()));
3951 /* Add all selected points to the relevant copy ControlLists */
3952 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
3953 boost::shared_ptr<AutomationList> al = (*i)->line().the_list();
3954 AutomationList::const_iterator j = (*i)->model ();
3955 lists[al].copy->fast_simple_add ((*j)->when, (*j)->value);
3958 /* Snap start time backwards, so copy/paste is snap aligned. */
3959 snap_to(start, RoundDownMaybe);
3961 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
3962 /* Correct this copy list so that it is relative to the earliest
3963 start time, so relative ordering between points is preserved
3964 when copying from several lists. */
3965 const AutomationLine* line = i->second.line;
3966 const double line_offset = line->time_converter().from(start);
3968 for (AutomationList::iterator j = i->second.copy->begin(); j != i->second.copy->end(); ++j) {
3969 (*j)->when -= line_offset;
3972 /* And add it to the cut buffer */
3973 cut_buffer->add (i->second.copy);
3977 if (op == Delete || op == Cut) {
3978 /* This operation needs to remove things from the main AutomationList, so do that now */
3980 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
3981 i->first->freeze ();
3984 /* Remove each selected point from its AutomationList */
3985 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
3986 boost::shared_ptr<AutomationList> al = (*i)->line().the_list();
3987 al->erase ((*i)->model ());
3990 /* Thaw the lists and add undo records for them */
3991 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
3992 boost::shared_ptr<AutomationList> al = i->first;
3994 _session->add_command (new MementoCommand<AutomationList> (*al.get(), i->second.state, &(al->get_state ())));
3999 /** Cut, copy or clear selected automation points.
4000 * @param op Operation (Cut, Copy or Clear)
4003 Editor::cut_copy_midi (CutCopyOp op)
4005 for (MidiRegionSelection::iterator i = selection->midi_regions.begin(); i != selection->midi_regions.end(); ++i) {
4006 MidiRegionView* mrv = dynamic_cast<MidiRegionView*>(*i);
4008 mrv->cut_copy_clear (op);
4010 /* XXX: not ideal, as there may be more than one track involved in the selection */
4011 _last_cut_copy_source_track = &mrv->get_time_axis_view();
4015 if (!selection->points.empty()) {
4016 cut_copy_points (op);
4017 if (op == Cut || op == Delete) {
4018 selection->clear_points ();
4023 struct lt_playlist {
4024 bool operator () (const PlaylistState& a, const PlaylistState& b) {
4025 return a.playlist < b.playlist;
4029 struct PlaylistMapping {
4031 boost::shared_ptr<Playlist> pl;
4033 PlaylistMapping (TimeAxisView* tvp) : tv (tvp) {}
4036 /** Remove `clicked_regionview' */
4038 Editor::remove_clicked_region ()
4040 if (clicked_routeview == 0 || clicked_regionview == 0) {
4044 begin_reversible_command (_("remove region"));
4046 boost::shared_ptr<Playlist> playlist = clicked_routeview->playlist();
4048 playlist->clear_changes ();
4049 playlist->clear_owned_changes ();
4050 playlist->remove_region (clicked_regionview->region());
4051 if (Config->get_edit_mode() == Ripple)
4052 playlist->ripple (clicked_regionview->region()->position(), -clicked_regionview->region()->length(), boost::shared_ptr<Region>());
4054 /* We might have removed regions, which alters other regions' layering_index,
4055 so we need to do a recursive diff here.
4057 vector<Command*> cmds;
4058 playlist->rdiff (cmds);
4059 _session->add_commands (cmds);
4061 _session->add_command(new StatefulDiffCommand (playlist));
4062 commit_reversible_command ();
4066 /** Remove the selected regions */
4068 Editor::remove_selected_regions ()
4070 RegionSelection rs = get_regions_from_selection_and_entered ();
4072 if (!_session || rs.empty()) {
4076 begin_reversible_command (_("remove region"));
4078 list<boost::shared_ptr<Region> > regions_to_remove;
4080 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
4081 // we can't just remove the region(s) in this loop because
4082 // this removes them from the RegionSelection, and they thus
4083 // disappear from underneath the iterator, and the ++i above
4084 // SEGVs in a puzzling fashion.
4086 // so, first iterate over the regions to be removed from rs and
4087 // add them to the regions_to_remove list, and then
4088 // iterate over the list to actually remove them.
4090 regions_to_remove.push_back ((*i)->region());
4093 vector<boost::shared_ptr<Playlist> > playlists;
4095 for (list<boost::shared_ptr<Region> >::iterator rl = regions_to_remove.begin(); rl != regions_to_remove.end(); ++rl) {
4097 boost::shared_ptr<Playlist> playlist = (*rl)->playlist();
4100 // is this check necessary?
4104 /* get_regions_from_selection_and_entered() guarantees that
4105 the playlists involved are unique, so there is no need
4109 playlists.push_back (playlist);
4111 playlist->clear_changes ();
4112 playlist->clear_owned_changes ();
4113 playlist->freeze ();
4114 playlist->remove_region (*rl);
4115 if (Config->get_edit_mode() == Ripple)
4116 playlist->ripple ((*rl)->position(), -(*rl)->length(), boost::shared_ptr<Region>());
4120 vector<boost::shared_ptr<Playlist> >::iterator pl;
4122 for (pl = playlists.begin(); pl != playlists.end(); ++pl) {
4125 /* We might have removed regions, which alters other regions' layering_index,
4126 so we need to do a recursive diff here.
4128 vector<Command*> cmds;
4129 (*pl)->rdiff (cmds);
4130 _session->add_commands (cmds);
4132 _session->add_command(new StatefulDiffCommand (*pl));
4135 commit_reversible_command ();
4138 /** Cut, copy or clear selected regions.
4139 * @param op Operation (Cut, Copy or Clear)
4142 Editor::cut_copy_regions (CutCopyOp op, RegionSelection& rs)
4144 /* we can't use a std::map here because the ordering is important, and we can't trivially sort
4145 a map when we want ordered access to both elements. i think.
4148 vector<PlaylistMapping> pmap;
4150 framepos_t first_position = max_framepos;
4152 typedef set<boost::shared_ptr<Playlist> > FreezeList;
4153 FreezeList freezelist;
4155 /* get ordering correct before we cut/copy */
4157 rs.sort_by_position_and_track ();
4159 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
4161 first_position = min ((framepos_t) (*x)->region()->position(), first_position);
4163 if (op == Cut || op == Clear || op == Delete) {
4164 boost::shared_ptr<Playlist> pl = (*x)->region()->playlist();
4167 FreezeList::iterator fl;
4169 // only take state if this is a new playlist.
4170 for (fl = freezelist.begin(); fl != freezelist.end(); ++fl) {
4176 if (fl == freezelist.end()) {
4177 pl->clear_changes();
4178 pl->clear_owned_changes ();
4180 freezelist.insert (pl);
4185 TimeAxisView* tv = &(*x)->get_time_axis_view();
4186 vector<PlaylistMapping>::iterator z;
4188 for (z = pmap.begin(); z != pmap.end(); ++z) {
4189 if ((*z).tv == tv) {
4194 if (z == pmap.end()) {
4195 pmap.push_back (PlaylistMapping (tv));
4199 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ) {
4201 boost::shared_ptr<Playlist> pl = (*x)->region()->playlist();
4204 /* region not yet associated with a playlist (e.g. unfinished
4211 TimeAxisView& tv = (*x)->get_time_axis_view();
4212 boost::shared_ptr<Playlist> npl;
4213 RegionSelection::iterator tmp;
4220 vector<PlaylistMapping>::iterator z;
4222 for (z = pmap.begin(); z != pmap.end(); ++z) {
4223 if ((*z).tv == &tv) {
4228 assert (z != pmap.end());
4231 npl = PlaylistFactory::create (pl->data_type(), *_session, "cutlist", true);
4239 boost::shared_ptr<Region> r = (*x)->region();
4240 boost::shared_ptr<Region> _xx;
4246 pl->remove_region (r);
4247 if (Config->get_edit_mode() == Ripple)
4248 pl->ripple (r->position(), -r->length(), boost::shared_ptr<Region>());
4252 _xx = RegionFactory::create (r);
4253 npl->add_region (_xx, r->position() - first_position);
4254 pl->remove_region (r);
4255 if (Config->get_edit_mode() == Ripple)
4256 pl->ripple (r->position(), -r->length(), boost::shared_ptr<Region>());
4260 /* copy region before adding, so we're not putting same object into two different playlists */
4261 npl->add_region (RegionFactory::create (r), r->position() - first_position);
4265 pl->remove_region (r);
4266 if (Config->get_edit_mode() == Ripple)
4267 pl->ripple (r->position(), -r->length(), boost::shared_ptr<Region>());
4276 list<boost::shared_ptr<Playlist> > foo;
4278 /* the pmap is in the same order as the tracks in which selected regions occured */
4280 for (vector<PlaylistMapping>::iterator i = pmap.begin(); i != pmap.end(); ++i) {
4283 foo.push_back ((*i).pl);
4288 cut_buffer->set (foo);
4292 _last_cut_copy_source_track = 0;
4294 _last_cut_copy_source_track = pmap.front().tv;
4298 for (FreezeList::iterator pl = freezelist.begin(); pl != freezelist.end(); ++pl) {
4301 /* We might have removed regions, which alters other regions' layering_index,
4302 so we need to do a recursive diff here.
4304 vector<Command*> cmds;
4305 (*pl)->rdiff (cmds);
4306 _session->add_commands (cmds);
4308 _session->add_command (new StatefulDiffCommand (*pl));
4313 Editor::cut_copy_ranges (CutCopyOp op)
4315 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4317 /* Sort the track selection now, so that it if is used, the playlists
4318 selected by the calls below to cut_copy_clear are in the order that
4319 their tracks appear in the editor. This makes things like paste
4320 of ranges work properly.
4323 sort_track_selection (ts);
4326 if (!entered_track) {
4329 ts.push_back (entered_track);
4332 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4333 (*i)->cut_copy_clear (*selection, op);
4338 Editor::paste (float times, bool from_context)
4340 DEBUG_TRACE (DEBUG::CutNPaste, "paste to preferred edit pos\n");
4342 paste_internal (get_preferred_edit_position (false, from_context), times);
4346 Editor::mouse_paste ()
4351 if (!mouse_frame (where, ignored)) {
4356 paste_internal (where, 1);
4360 Editor::paste_internal (framepos_t position, float times)
4362 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("apparent paste position is %1\n", position));
4364 if (cut_buffer->empty(internal_editing())) {
4368 if (position == max_framepos) {
4369 position = get_preferred_edit_position();
4370 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("preferred edit position is %1\n", position));
4373 if (position == last_paste_pos) {
4374 /* repeated paste in the same position */
4377 /* paste in new location, reset repeated paste state */
4379 last_paste_pos = position;
4382 /* get everything in the correct order */
4385 if (!selection->tracks.empty()) {
4386 /* If there is a track selection, paste into exactly those tracks and
4387 only those tracks. This allows the user to be explicit and override
4388 the below "do the reasonable thing" logic. */
4389 ts = selection->tracks.filter_to_unique_playlists ();
4390 sort_track_selection (ts);
4392 /* Figure out which track to base the paste at. */
4393 TimeAxisView* base_track = NULL;
4394 if (_edit_point == Editing::EditAtMouse && entered_track) {
4395 /* With the mouse edit point, paste onto the track under the mouse. */
4396 base_track = entered_track;
4397 } else if (_edit_point == Editing::EditAtMouse && entered_regionview) {
4398 /* With the mouse edit point, paste onto the track of the region under the mouse. */
4399 base_track = &entered_regionview->get_time_axis_view();
4400 } else if (_last_cut_copy_source_track) {
4401 /* Paste to the track that the cut/copy came from (see mantis #333). */
4402 base_track = _last_cut_copy_source_track;
4404 /* This is "impossible" since we've copied... well, do nothing. */
4408 /* Walk up to parent if necessary, so base track is a route. */
4409 while (base_track->get_parent()) {
4410 base_track = base_track->get_parent();
4413 /* Add base track and all tracks below it. The paste logic will select
4414 the appropriate object types from the cut buffer in relative order. */
4415 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4416 if ((*i)->order() >= base_track->order()) {
4421 /* Sort tracks so the nth track of type T will pick the nth object of type T. */
4422 sort_track_selection (ts);
4424 /* Add automation children of each track in order, for pasting several lines. */
4425 for (TrackViewList::iterator i = ts.begin(); i != ts.end();) {
4426 /* Add any automation children for pasting several lines */
4427 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*i++);
4432 typedef RouteTimeAxisView::AutomationTracks ATracks;
4433 const ATracks& atracks = rtv->automation_tracks();
4434 for (ATracks::const_iterator a = atracks.begin(); a != atracks.end(); ++a) {
4435 i = ts.insert(i, a->second.get());
4440 /* We now have a list of trackviews starting at base_track, including
4441 automation children, in the order shown in the editor, e.g. R1,
4442 R1.A1, R1.A2, R2, R2.A1, ... */
4445 if (ts.size() == 1 && cut_buffer->lines.size() == 1 &&
4446 dynamic_cast<AutomationTimeAxisView*>(ts.front())) {
4447 /* Only one line copied, and one automation track selected. Do a
4448 "greedy" paste from one automation type to another. */
4450 begin_reversible_command (Operations::paste);
4452 PasteContext ctx(paste_count, times, ItemCounts(), true);
4453 ts.front()->paste (position, *cut_buffer, ctx);
4455 commit_reversible_command ();
4457 } else if (internal_editing ()) {
4459 /* undo/redo is handled by individual tracks/regions */
4462 get_regions_at (rs, position, ts);
4464 PasteContext ctx(paste_count, times, ItemCounts(), false);
4465 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
4466 MidiRegionView* mrv = dynamic_cast<MidiRegionView*> (*r);
4468 mrv->paste (position, *cut_buffer, ctx);
4474 /* we do redo (do you do voodoo?) */
4476 begin_reversible_command (Operations::paste);
4478 PasteContext ctx(paste_count, times, ItemCounts(), false);
4479 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4480 (*i)->paste (position, *cut_buffer, ctx);
4483 commit_reversible_command ();
4488 Editor::duplicate_some_regions (RegionSelection& regions, float times)
4490 boost::shared_ptr<Playlist> playlist;
4491 RegionSelection sel = regions; // clear (below) may clear the argument list if its the current region selection
4492 RegionSelection foo;
4494 framepos_t const start_frame = regions.start ();
4495 framepos_t const end_frame = regions.end_frame ();
4497 begin_reversible_command (Operations::duplicate_region);
4499 selection->clear_regions ();
4501 for (RegionSelection::iterator i = sel.begin(); i != sel.end(); ++i) {
4503 boost::shared_ptr<Region> r ((*i)->region());
4505 TimeAxisView& tv = (*i)->get_time_axis_view();
4506 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (&tv);
4507 latest_regionviews.clear ();
4508 sigc::connection c = rtv->view()->RegionViewAdded.connect (sigc::mem_fun(*this, &Editor::collect_new_region_view));
4510 playlist = (*i)->region()->playlist();
4511 playlist->clear_changes ();
4512 playlist->duplicate (r, end_frame + (r->first_frame() - start_frame), times);
4513 _session->add_command(new StatefulDiffCommand (playlist));
4517 foo.insert (foo.end(), latest_regionviews.begin(), latest_regionviews.end());
4520 commit_reversible_command ();
4523 selection->set (foo);
4528 Editor::duplicate_selection (float times)
4530 if (selection->time.empty() || selection->tracks.empty()) {
4534 boost::shared_ptr<Playlist> playlist;
4535 vector<boost::shared_ptr<Region> > new_regions;
4536 vector<boost::shared_ptr<Region> >::iterator ri;
4538 create_region_from_selection (new_regions);
4540 if (new_regions.empty()) {
4544 begin_reversible_command (_("duplicate selection"));
4546 ri = new_regions.begin();
4548 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4550 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4551 if ((playlist = (*i)->playlist()) == 0) {
4554 playlist->clear_changes ();
4555 playlist->duplicate (*ri, selection->time[clicked_selection].end, times);
4556 _session->add_command (new StatefulDiffCommand (playlist));
4559 if (ri == new_regions.end()) {
4564 commit_reversible_command ();
4567 /** Reset all selected points to the relevant default value */
4569 Editor::reset_point_selection ()
4571 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
4572 ARDOUR::AutomationList::iterator j = (*i)->model ();
4573 (*j)->value = (*i)->line().the_list()->default_value ();
4578 Editor::center_playhead ()
4580 float const page = _visible_canvas_width * samples_per_pixel;
4581 center_screen_internal (playhead_cursor->current_frame (), page);
4585 Editor::center_edit_point ()
4587 float const page = _visible_canvas_width * samples_per_pixel;
4588 center_screen_internal (get_preferred_edit_position(), page);
4591 /** Caller must begin and commit a reversible command */
4593 Editor::clear_playlist (boost::shared_ptr<Playlist> playlist)
4595 playlist->clear_changes ();
4597 _session->add_command (new StatefulDiffCommand (playlist));
4601 Editor::nudge_track (bool use_edit, bool forwards)
4603 boost::shared_ptr<Playlist> playlist;
4604 framepos_t distance;
4605 framepos_t next_distance;
4609 start = get_preferred_edit_position();
4614 if ((distance = get_nudge_distance (start, next_distance)) == 0) {
4618 if (selection->tracks.empty()) {
4622 begin_reversible_command (_("nudge track"));
4624 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4626 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4628 if ((playlist = (*i)->playlist()) == 0) {
4632 playlist->clear_changes ();
4633 playlist->clear_owned_changes ();
4635 playlist->nudge_after (start, distance, forwards);
4637 vector<Command*> cmds;
4639 playlist->rdiff (cmds);
4640 _session->add_commands (cmds);
4642 _session->add_command (new StatefulDiffCommand (playlist));
4645 commit_reversible_command ();
4649 Editor::remove_last_capture ()
4651 vector<string> choices;
4658 if (Config->get_verify_remove_last_capture()) {
4659 prompt = _("Do you really want to destroy the last capture?"
4660 "\n(This is destructive and cannot be undone)");
4662 choices.push_back (_("No, do nothing."));
4663 choices.push_back (_("Yes, destroy it."));
4665 Gtkmm2ext::Choice prompter (_("Destroy last capture"), prompt, choices);
4667 if (prompter.run () == 1) {
4668 _session->remove_last_capture ();
4669 _regions->redisplay ();
4673 _session->remove_last_capture();
4674 _regions->redisplay ();
4679 Editor::normalize_region ()
4685 RegionSelection rs = get_regions_from_selection_and_entered ();
4691 NormalizeDialog dialog (rs.size() > 1);
4693 if (dialog.run () == RESPONSE_CANCEL) {
4697 set_canvas_cursor (_cursors->wait);
4700 /* XXX: should really only count audio regions here */
4701 int const regions = rs.size ();
4703 /* Make a list of the selected audio regions' maximum amplitudes, and also
4704 obtain the maximum amplitude of them all.
4706 list<double> max_amps;
4708 for (RegionSelection::const_iterator i = rs.begin(); i != rs.end(); ++i) {
4709 AudioRegionView const * arv = dynamic_cast<AudioRegionView const *> (*i);
4711 dialog.descend (1.0 / regions);
4712 double const a = arv->audio_region()->maximum_amplitude (&dialog);
4715 /* the user cancelled the operation */
4716 set_canvas_cursor (current_canvas_cursor);
4720 max_amps.push_back (a);
4721 max_amp = max (max_amp, a);
4726 begin_reversible_command (_("normalize"));
4728 list<double>::const_iterator a = max_amps.begin ();
4730 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
4731 AudioRegionView* const arv = dynamic_cast<AudioRegionView*> (*r);
4736 arv->region()->clear_changes ();
4738 double const amp = dialog.normalize_individually() ? *a : max_amp;
4740 arv->audio_region()->normalize (amp, dialog.target ());
4741 _session->add_command (new StatefulDiffCommand (arv->region()));
4746 commit_reversible_command ();
4747 set_canvas_cursor (current_canvas_cursor);
4752 Editor::reset_region_scale_amplitude ()
4758 RegionSelection rs = get_regions_from_selection_and_entered ();
4764 begin_reversible_command ("reset gain");
4766 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
4767 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
4770 arv->region()->clear_changes ();
4771 arv->audio_region()->set_scale_amplitude (1.0f);
4772 _session->add_command (new StatefulDiffCommand (arv->region()));
4775 commit_reversible_command ();
4779 Editor::adjust_region_gain (bool up)
4781 RegionSelection rs = get_regions_from_selection_and_entered ();
4783 if (!_session || rs.empty()) {
4787 begin_reversible_command ("adjust region gain");
4789 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
4790 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
4795 arv->region()->clear_changes ();
4797 double dB = accurate_coefficient_to_dB (arv->audio_region()->scale_amplitude ());
4805 arv->audio_region()->set_scale_amplitude (dB_to_coefficient (dB));
4806 _session->add_command (new StatefulDiffCommand (arv->region()));
4809 commit_reversible_command ();
4814 Editor::reverse_region ()
4820 Reverse rev (*_session);
4821 apply_filter (rev, _("reverse regions"));
4825 Editor::strip_region_silence ()
4831 RegionSelection rs = get_regions_from_selection_and_entered ();
4837 std::list<RegionView*> audio_only;
4839 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
4840 AudioRegionView* const arv = dynamic_cast<AudioRegionView*> (*i);
4842 audio_only.push_back (arv);
4846 StripSilenceDialog d (_session, audio_only);
4847 int const r = d.run ();
4851 if (r == Gtk::RESPONSE_OK) {
4852 ARDOUR::AudioIntervalMap silences;
4853 d.silences (silences);
4854 StripSilence s (*_session, silences, d.fade_length());
4855 apply_filter (s, _("strip silence"), &d);
4860 Editor::apply_midi_note_edit_op_to_region (MidiOperator& op, MidiRegionView& mrv)
4862 Evoral::Sequence<Evoral::MusicalTime>::Notes selected;
4863 mrv.selection_as_notelist (selected, true);
4865 vector<Evoral::Sequence<Evoral::MusicalTime>::Notes> v;
4866 v.push_back (selected);
4868 framepos_t pos_frames = mrv.midi_region()->position() - mrv.midi_region()->start();
4869 Evoral::MusicalTime pos_beats = _session->tempo_map().framewalk_to_beats(0, pos_frames);
4871 return op (mrv.midi_region()->model(), pos_beats, v);
4875 Editor::apply_midi_note_edit_op (MidiOperator& op)
4879 RegionSelection rs = get_regions_from_selection_and_entered ();
4885 begin_reversible_command (op.name ());
4887 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
4888 RegionSelection::iterator tmp = r;
4891 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*r);
4894 cmd = apply_midi_note_edit_op_to_region (op, *mrv);
4897 _session->add_command (cmd);
4904 commit_reversible_command ();
4908 Editor::fork_region ()
4910 RegionSelection rs = get_regions_from_selection_and_entered ();
4916 begin_reversible_command (_("Fork Region(s)"));
4918 set_canvas_cursor (_cursors->wait);
4921 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
4922 RegionSelection::iterator tmp = r;
4925 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*>(*r);
4929 boost::shared_ptr<Playlist> playlist = mrv->region()->playlist();
4930 boost::shared_ptr<MidiSource> new_source = _session->create_midi_source_by_stealing_name (mrv->midi_view()->track());
4931 boost::shared_ptr<MidiRegion> newregion = mrv->midi_region()->clone (new_source);
4933 playlist->clear_changes ();
4934 playlist->replace_region (mrv->region(), newregion, mrv->region()->position());
4935 _session->add_command(new StatefulDiffCommand (playlist));
4937 error << string_compose (_("Could not unlink %1"), mrv->region()->name()) << endmsg;
4944 commit_reversible_command ();
4946 set_canvas_cursor (current_canvas_cursor);
4950 Editor::quantize_region ()
4952 int selected_midi_region_cnt = 0;
4958 RegionSelection rs = get_regions_from_selection_and_entered ();
4964 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
4965 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*r);
4967 selected_midi_region_cnt++;
4971 if (selected_midi_region_cnt == 0) {
4975 QuantizeDialog* qd = new QuantizeDialog (*this);
4978 const int r = qd->run ();
4981 if (r == Gtk::RESPONSE_OK) {
4982 Quantize quant (qd->snap_start(), qd->snap_end(),
4983 qd->start_grid_size(), qd->end_grid_size(),
4984 qd->strength(), qd->swing(), qd->threshold());
4986 apply_midi_note_edit_op (quant);
4991 Editor::insert_patch_change (bool from_context)
4993 RegionSelection rs = get_regions_from_selection_and_entered ();
4999 const framepos_t p = get_preferred_edit_position (false, from_context);
5001 /* XXX: bit of a hack; use the MIDNAM from the first selected region;
5002 there may be more than one, but the PatchChangeDialog can only offer
5003 one set of patch menus.
5005 MidiRegionView* first = dynamic_cast<MidiRegionView*> (rs.front ());
5007 Evoral::PatchChange<Evoral::MusicalTime> empty (Evoral::MusicalTime(), 0, 0, 0);
5008 PatchChangeDialog d (0, _session, empty, first->instrument_info(), Gtk::Stock::ADD);
5010 if (d.run() == RESPONSE_CANCEL) {
5014 for (RegionSelection::iterator i = rs.begin (); i != rs.end(); ++i) {
5015 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*i);
5017 if (p >= mrv->region()->first_frame() && p <= mrv->region()->last_frame()) {
5018 mrv->add_patch_change (p - mrv->region()->position(), d.patch ());
5025 Editor::apply_filter (Filter& filter, string command, ProgressReporter* progress)
5027 RegionSelection rs = get_regions_from_selection_and_entered ();
5033 begin_reversible_command (command);
5035 set_canvas_cursor (_cursors->wait);
5039 int const N = rs.size ();
5041 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
5042 RegionSelection::iterator tmp = r;
5045 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
5047 boost::shared_ptr<Playlist> playlist = arv->region()->playlist();
5050 progress->descend (1.0 / N);
5053 if (arv->audio_region()->apply (filter, progress) == 0) {
5055 playlist->clear_changes ();
5056 playlist->clear_owned_changes ();
5058 if (filter.results.empty ()) {
5060 /* no regions returned; remove the old one */
5061 playlist->remove_region (arv->region ());
5065 std::vector<boost::shared_ptr<Region> >::iterator res = filter.results.begin ();
5067 /* first region replaces the old one */
5068 playlist->replace_region (arv->region(), *res, (*res)->position());
5072 while (res != filter.results.end()) {
5073 playlist->add_region (*res, (*res)->position());
5079 /* We might have removed regions, which alters other regions' layering_index,
5080 so we need to do a recursive diff here.
5082 vector<Command*> cmds;
5083 playlist->rdiff (cmds);
5084 _session->add_commands (cmds);
5086 _session->add_command(new StatefulDiffCommand (playlist));
5092 progress->ascend ();
5100 commit_reversible_command ();
5103 set_canvas_cursor (current_canvas_cursor);
5107 Editor::external_edit_region ()
5113 Editor::reset_region_gain_envelopes ()
5115 RegionSelection rs = get_regions_from_selection_and_entered ();
5117 if (!_session || rs.empty()) {
5121 _session->begin_reversible_command (_("reset region gain"));
5123 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5124 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
5126 boost::shared_ptr<AutomationList> alist (arv->audio_region()->envelope());
5127 XMLNode& before (alist->get_state());
5129 arv->audio_region()->set_default_envelope ();
5130 _session->add_command (new MementoCommand<AutomationList>(*arv->audio_region()->envelope().get(), &before, &alist->get_state()));
5134 _session->commit_reversible_command ();
5138 Editor::set_region_gain_visibility (RegionView* rv)
5140 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (rv);
5142 arv->update_envelope_visibility();
5147 Editor::set_gain_envelope_visibility ()
5153 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5154 AudioTimeAxisView* v = dynamic_cast<AudioTimeAxisView*>(*i);
5156 v->audio_view()->foreach_regionview (sigc::mem_fun (this, &Editor::set_region_gain_visibility));
5162 Editor::toggle_gain_envelope_active ()
5164 if (_ignore_region_action) {
5168 RegionSelection rs = get_regions_from_selection_and_entered ();
5170 if (!_session || rs.empty()) {
5174 _session->begin_reversible_command (_("region gain envelope active"));
5176 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5177 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
5179 arv->region()->clear_changes ();
5180 arv->audio_region()->set_envelope_active (!arv->audio_region()->envelope_active());
5181 _session->add_command (new StatefulDiffCommand (arv->region()));
5185 _session->commit_reversible_command ();
5189 Editor::toggle_region_lock ()
5191 if (_ignore_region_action) {
5195 RegionSelection rs = get_regions_from_selection_and_entered ();
5197 if (!_session || rs.empty()) {
5201 _session->begin_reversible_command (_("toggle region lock"));
5203 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5204 (*i)->region()->clear_changes ();
5205 (*i)->region()->set_locked (!(*i)->region()->locked());
5206 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5209 _session->commit_reversible_command ();
5213 Editor::toggle_region_video_lock ()
5215 if (_ignore_region_action) {
5219 RegionSelection rs = get_regions_from_selection_and_entered ();
5221 if (!_session || rs.empty()) {
5225 _session->begin_reversible_command (_("Toggle Video Lock"));
5227 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5228 (*i)->region()->clear_changes ();
5229 (*i)->region()->set_video_locked (!(*i)->region()->video_locked());
5230 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5233 _session->commit_reversible_command ();
5237 Editor::toggle_region_lock_style ()
5239 if (_ignore_region_action) {
5243 RegionSelection rs = get_regions_from_selection_and_entered ();
5245 if (!_session || rs.empty()) {
5249 _session->begin_reversible_command (_("region lock style"));
5251 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5252 (*i)->region()->clear_changes ();
5253 PositionLockStyle const ns = (*i)->region()->position_lock_style() == AudioTime ? MusicTime : AudioTime;
5254 (*i)->region()->set_position_lock_style (ns);
5255 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5258 _session->commit_reversible_command ();
5262 Editor::toggle_opaque_region ()
5264 if (_ignore_region_action) {
5268 RegionSelection rs = get_regions_from_selection_and_entered ();
5270 if (!_session || rs.empty()) {
5274 _session->begin_reversible_command (_("change region opacity"));
5276 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5277 (*i)->region()->clear_changes ();
5278 (*i)->region()->set_opaque (!(*i)->region()->opaque());
5279 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5282 _session->commit_reversible_command ();
5286 Editor::toggle_record_enable ()
5288 bool new_state = false;
5290 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5291 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5294 if (!rtav->is_track())
5298 new_state = !rtav->track()->record_enabled();
5302 rtav->track()->set_record_enabled (new_state, this);
5307 Editor::toggle_solo ()
5309 bool new_state = false;
5311 boost::shared_ptr<RouteList> rl (new RouteList);
5313 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5314 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5321 new_state = !rtav->route()->soloed ();
5325 rl->push_back (rtav->route());
5328 _session->set_solo (rl, new_state, Session::rt_cleanup, true);
5332 Editor::toggle_mute ()
5334 bool new_state = false;
5336 boost::shared_ptr<RouteList> rl (new RouteList);
5338 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5339 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5346 new_state = !rtav->route()->muted();
5350 rl->push_back (rtav->route());
5353 _session->set_mute (rl, new_state, Session::rt_cleanup, true);
5357 Editor::toggle_solo_isolate ()
5363 Editor::fade_range ()
5365 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
5367 begin_reversible_command (_("fade range"));
5369 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
5370 (*i)->fade_range (selection->time);
5373 commit_reversible_command ();
5378 Editor::set_fade_length (bool in)
5380 RegionSelection rs = get_regions_from_selection_and_entered ();
5386 /* we need a region to measure the offset from the start */
5388 RegionView* rv = rs.front ();
5390 framepos_t pos = get_preferred_edit_position();
5394 if (pos > rv->region()->last_frame() || pos < rv->region()->first_frame()) {
5395 /* edit point is outside the relevant region */
5400 if (pos <= rv->region()->position()) {
5404 len = pos - rv->region()->position();
5405 cmd = _("set fade in length");
5407 if (pos >= rv->region()->last_frame()) {
5411 len = rv->region()->last_frame() - pos;
5412 cmd = _("set fade out length");
5415 begin_reversible_command (cmd);
5417 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5418 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5424 boost::shared_ptr<AutomationList> alist;
5426 alist = tmp->audio_region()->fade_in();
5428 alist = tmp->audio_region()->fade_out();
5431 XMLNode &before = alist->get_state();
5434 tmp->audio_region()->set_fade_in_length (len);
5435 tmp->audio_region()->set_fade_in_active (true);
5437 tmp->audio_region()->set_fade_out_length (len);
5438 tmp->audio_region()->set_fade_out_active (true);
5441 XMLNode &after = alist->get_state();
5442 _session->add_command(new MementoCommand<AutomationList>(*alist, &before, &after));
5445 commit_reversible_command ();
5449 Editor::set_fade_in_shape (FadeShape shape)
5451 RegionSelection rs = get_regions_from_selection_and_entered ();
5457 begin_reversible_command (_("set fade in shape"));
5459 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5460 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5466 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_in();
5467 XMLNode &before = alist->get_state();
5469 tmp->audio_region()->set_fade_in_shape (shape);
5471 XMLNode &after = alist->get_state();
5472 _session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
5475 commit_reversible_command ();
5480 Editor::set_fade_out_shape (FadeShape shape)
5482 RegionSelection rs = get_regions_from_selection_and_entered ();
5488 begin_reversible_command (_("set fade out 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_out();
5498 XMLNode &before = alist->get_state();
5500 tmp->audio_region()->set_fade_out_shape (shape);
5502 XMLNode &after = alist->get_state();
5503 _session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
5506 commit_reversible_command ();
5510 Editor::set_fade_in_active (bool yn)
5512 RegionSelection rs = get_regions_from_selection_and_entered ();
5518 begin_reversible_command (_("set fade in active"));
5520 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5521 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5528 boost::shared_ptr<AudioRegion> ar (tmp->audio_region());
5530 ar->clear_changes ();
5531 ar->set_fade_in_active (yn);
5532 _session->add_command (new StatefulDiffCommand (ar));
5535 commit_reversible_command ();
5539 Editor::set_fade_out_active (bool yn)
5541 RegionSelection rs = get_regions_from_selection_and_entered ();
5547 begin_reversible_command (_("set fade out active"));
5549 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5550 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5556 boost::shared_ptr<AudioRegion> ar (tmp->audio_region());
5558 ar->clear_changes ();
5559 ar->set_fade_out_active (yn);
5560 _session->add_command(new StatefulDiffCommand (ar));
5563 commit_reversible_command ();
5567 Editor::toggle_region_fades (int dir)
5569 if (_ignore_region_action) {
5573 boost::shared_ptr<AudioRegion> ar;
5576 RegionSelection rs = get_regions_from_selection_and_entered ();
5582 RegionSelection::iterator i;
5583 for (i = rs.begin(); i != rs.end(); ++i) {
5584 if ((ar = boost::dynamic_pointer_cast<AudioRegion>((*i)->region())) != 0) {
5586 yn = ar->fade_out_active ();
5588 yn = ar->fade_in_active ();
5594 if (i == rs.end()) {
5598 /* XXX should this undo-able? */
5600 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5601 if ((ar = boost::dynamic_pointer_cast<AudioRegion>((*i)->region())) == 0) {
5604 if (dir == 1 || dir == 0) {
5605 ar->set_fade_in_active (!yn);
5608 if (dir == -1 || dir == 0) {
5609 ar->set_fade_out_active (!yn);
5615 /** Update region fade visibility after its configuration has been changed */
5617 Editor::update_region_fade_visibility ()
5619 bool _fade_visibility = _session->config.get_show_region_fades ();
5621 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5622 AudioTimeAxisView* v = dynamic_cast<AudioTimeAxisView*>(*i);
5624 if (_fade_visibility) {
5625 v->audio_view()->show_all_fades ();
5627 v->audio_view()->hide_all_fades ();
5634 Editor::set_edit_point ()
5639 if (!mouse_frame (where, ignored)) {
5645 if (selection->markers.empty()) {
5647 mouse_add_new_marker (where);
5652 Location* loc = find_location_from_marker (selection->markers.front(), ignored);
5655 loc->move_to (where);
5661 Editor::set_playhead_cursor ()
5663 if (entered_marker) {
5664 _session->request_locate (entered_marker->position(), _session->transport_rolling());
5669 if (!mouse_frame (where, ignored)) {
5676 _session->request_locate (where, _session->transport_rolling());
5680 if ( Config->get_follow_edits() )
5681 cancel_time_selection();
5685 Editor::split_region ()
5687 if ( !selection->time.empty()) {
5688 separate_regions_between (selection->time);
5692 RegionSelection rs = get_regions_from_selection_and_edit_point ();
5694 framepos_t where = get_preferred_edit_position ();
5700 split_regions_at (where, rs);
5703 struct EditorOrderRouteSorter {
5704 bool operator() (boost::shared_ptr<Route> a, boost::shared_ptr<Route> b) {
5705 return a->order_key () < b->order_key ();
5710 Editor::select_next_route()
5712 if (selection->tracks.empty()) {
5713 selection->set (track_views.front());
5717 TimeAxisView* current = selection->tracks.front();
5721 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5722 if (*i == current) {
5724 if (i != track_views.end()) {
5727 current = (*(track_views.begin()));
5728 //selection->set (*(track_views.begin()));
5733 rui = dynamic_cast<RouteUI *>(current);
5734 } while ( current->hidden() || (rui != NULL && !rui->route()->active()));
5736 selection->set(current);
5738 ensure_time_axis_view_is_visible (*current, false);
5742 Editor::select_prev_route()
5744 if (selection->tracks.empty()) {
5745 selection->set (track_views.front());
5749 TimeAxisView* current = selection->tracks.front();
5753 for (TrackViewList::reverse_iterator i = track_views.rbegin(); i != track_views.rend(); ++i) {
5754 if (*i == current) {
5756 if (i != track_views.rend()) {
5759 current = *(track_views.rbegin());
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::set_loop_from_selection (bool play)
5775 if (_session == 0 || selection->time.empty()) {
5779 framepos_t start = selection->time[clicked_selection].start;
5780 framepos_t end = selection->time[clicked_selection].end;
5782 set_loop_range (start, end, _("set loop range from selection"));
5785 _session->request_locate (start, true);
5786 _session->request_play_loop (true);
5791 Editor::set_loop_from_edit_range (bool play)
5793 if (_session == 0) {
5800 if (!get_edit_op_range (start, end)) {
5804 set_loop_range (start, end, _("set loop range from edit range"));
5807 _session->request_locate (start, true);
5808 _session->request_play_loop (true);
5813 Editor::set_loop_from_region (bool play)
5815 framepos_t start = max_framepos;
5818 RegionSelection rs = get_regions_from_selection_and_entered ();
5824 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5825 if ((*i)->region()->position() < start) {
5826 start = (*i)->region()->position();
5828 if ((*i)->region()->last_frame() + 1 > end) {
5829 end = (*i)->region()->last_frame() + 1;
5833 set_loop_range (start, end, _("set loop range from region"));
5836 _session->request_locate (start, true);
5837 _session->request_play_loop (true);
5842 Editor::set_punch_from_selection ()
5844 if (_session == 0 || selection->time.empty()) {
5848 framepos_t start = selection->time[clicked_selection].start;
5849 framepos_t end = selection->time[clicked_selection].end;
5851 set_punch_range (start, end, _("set punch range from selection"));
5855 Editor::set_punch_from_edit_range ()
5857 if (_session == 0) {
5864 if (!get_edit_op_range (start, end)) {
5868 set_punch_range (start, end, _("set punch range from edit range"));
5872 Editor::set_punch_from_region ()
5874 framepos_t start = max_framepos;
5877 RegionSelection rs = get_regions_from_selection_and_entered ();
5883 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5884 if ((*i)->region()->position() < start) {
5885 start = (*i)->region()->position();
5887 if ((*i)->region()->last_frame() + 1 > end) {
5888 end = (*i)->region()->last_frame() + 1;
5892 set_punch_range (start, end, _("set punch range from region"));
5896 Editor::pitch_shift_region ()
5898 RegionSelection rs = get_regions_from_selection_and_entered ();
5900 RegionSelection audio_rs;
5901 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5902 if (dynamic_cast<AudioRegionView*> (*i)) {
5903 audio_rs.push_back (*i);
5907 if (audio_rs.empty()) {
5911 pitch_shift (audio_rs, 1.2);
5915 Editor::transpose_region ()
5917 RegionSelection rs = get_regions_from_selection_and_entered ();
5919 list<MidiRegionView*> midi_region_views;
5920 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5921 MidiRegionView* mrv = dynamic_cast<MidiRegionView*> (*i);
5923 midi_region_views.push_back (mrv);
5928 int const r = d.run ();
5929 if (r != RESPONSE_ACCEPT) {
5933 for (list<MidiRegionView*>::iterator i = midi_region_views.begin(); i != midi_region_views.end(); ++i) {
5934 (*i)->midi_region()->transpose (d.semitones ());
5939 Editor::set_tempo_from_region ()
5941 RegionSelection rs = get_regions_from_selection_and_entered ();
5943 if (!_session || rs.empty()) {
5947 RegionView* rv = rs.front();
5949 define_one_bar (rv->region()->position(), rv->region()->last_frame() + 1);
5953 Editor::use_range_as_bar ()
5955 framepos_t start, end;
5956 if (get_edit_op_range (start, end)) {
5957 define_one_bar (start, end);
5962 Editor::define_one_bar (framepos_t start, framepos_t end)
5964 framepos_t length = end - start;
5966 const Meter& m (_session->tempo_map().meter_at (start));
5968 /* length = 1 bar */
5970 /* now we want frames per beat.
5971 we have frames per bar, and beats per bar, so ...
5974 /* XXXX METER MATH */
5976 double frames_per_beat = length / m.divisions_per_bar();
5978 /* beats per minute = */
5980 double beats_per_minute = (_session->frame_rate() * 60.0) / frames_per_beat;
5982 /* now decide whether to:
5984 (a) set global tempo
5985 (b) add a new tempo marker
5989 const TempoSection& t (_session->tempo_map().tempo_section_at (start));
5991 bool do_global = false;
5993 if ((_session->tempo_map().n_tempos() == 1) && (_session->tempo_map().n_meters() == 1)) {
5995 /* only 1 tempo & 1 meter: ask if the user wants to set the tempo
5996 at the start, or create a new marker
5999 vector<string> options;
6000 options.push_back (_("Cancel"));
6001 options.push_back (_("Add new marker"));
6002 options.push_back (_("Set global tempo"));
6005 _("Define one bar"),
6006 _("Do you want to set the global tempo or add a new tempo marker?"),
6010 c.set_default_response (2);
6026 /* more than 1 tempo and/or meter section already, go ahead do the "usual":
6027 if the marker is at the region starter, change it, otherwise add
6032 begin_reversible_command (_("set tempo from region"));
6033 XMLNode& before (_session->tempo_map().get_state());
6036 _session->tempo_map().change_initial_tempo (beats_per_minute, t.note_type());
6037 } else if (t.frame() == start) {
6038 _session->tempo_map().change_existing_tempo_at (start, beats_per_minute, t.note_type());
6040 Timecode::BBT_Time bbt;
6041 _session->tempo_map().bbt_time (start, bbt);
6042 _session->tempo_map().add_tempo (Tempo (beats_per_minute, t.note_type()), bbt);
6045 XMLNode& after (_session->tempo_map().get_state());
6047 _session->add_command (new MementoCommand<TempoMap>(_session->tempo_map(), &before, &after));
6048 commit_reversible_command ();
6052 Editor::split_region_at_transients ()
6054 AnalysisFeatureList positions;
6056 RegionSelection rs = get_regions_from_selection_and_entered ();
6058 if (!_session || rs.empty()) {
6062 _session->begin_reversible_command (_("split regions"));
6064 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ) {
6066 RegionSelection::iterator tmp;
6071 boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion> ((*i)->region());
6073 if (ar && (ar->get_transients (positions) == 0)) {
6074 split_region_at_points ((*i)->region(), positions, true);
6081 _session->commit_reversible_command ();
6086 Editor::split_region_at_points (boost::shared_ptr<Region> r, AnalysisFeatureList& positions, bool can_ferret, bool select_new)
6088 bool use_rhythmic_rodent = false;
6090 boost::shared_ptr<Playlist> pl = r->playlist();
6092 list<boost::shared_ptr<Region> > new_regions;
6098 if (positions.empty()) {
6103 if (positions.size() > 20 && can_ferret) {
6104 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);
6105 MessageDialog msg (msgstr,
6108 Gtk::BUTTONS_OK_CANCEL);
6111 msg.add_button (_("Call for the Ferret!"), RESPONSE_APPLY);
6112 msg.set_secondary_text (_("Press OK to continue with this split operation\nor ask the Ferret dialog to tune the analysis"));
6114 msg.set_secondary_text (_("Press OK to continue with this split operation"));
6117 msg.set_title (_("Excessive split?"));
6120 int response = msg.run();
6126 case RESPONSE_APPLY:
6127 use_rhythmic_rodent = true;
6134 if (use_rhythmic_rodent) {
6135 show_rhythm_ferret ();
6139 AnalysisFeatureList::const_iterator x;
6141 pl->clear_changes ();
6142 pl->clear_owned_changes ();
6144 x = positions.begin();
6146 if (x == positions.end()) {
6151 pl->remove_region (r);
6155 while (x != positions.end()) {
6157 /* deal with positons that are out of scope of present region bounds */
6158 if (*x <= 0 || *x > r->length()) {
6163 /* file start = original start + how far we from the initial position ?
6166 framepos_t file_start = r->start() + pos;
6168 /* length = next position - current position
6171 framepos_t len = (*x) - pos;
6173 /* XXX we do we really want to allow even single-sample regions?
6174 shouldn't we have some kind of lower limit on region size?
6183 if (RegionFactory::region_name (new_name, r->name())) {
6187 /* do NOT announce new regions 1 by one, just wait till they are all done */
6191 plist.add (ARDOUR::Properties::start, file_start);
6192 plist.add (ARDOUR::Properties::length, len);
6193 plist.add (ARDOUR::Properties::name, new_name);
6194 plist.add (ARDOUR::Properties::layer, 0);
6196 boost::shared_ptr<Region> nr = RegionFactory::create (r->sources(), plist, false);
6197 /* because we set annouce to false, manually add the new region to the
6200 RegionFactory::map_add (nr);
6202 pl->add_region (nr, r->position() + pos);
6205 new_regions.push_front(nr);
6214 RegionFactory::region_name (new_name, r->name());
6216 /* Add the final region */
6219 plist.add (ARDOUR::Properties::start, r->start() + pos);
6220 plist.add (ARDOUR::Properties::length, r->last_frame() - (r->position() + pos) + 1);
6221 plist.add (ARDOUR::Properties::name, new_name);
6222 plist.add (ARDOUR::Properties::layer, 0);
6224 boost::shared_ptr<Region> nr = RegionFactory::create (r->sources(), plist, false);
6225 /* because we set annouce to false, manually add the new region to the
6228 RegionFactory::map_add (nr);
6229 pl->add_region (nr, r->position() + pos);
6232 new_regions.push_front(nr);
6237 /* We might have removed regions, which alters other regions' layering_index,
6238 so we need to do a recursive diff here.
6240 vector<Command*> cmds;
6242 _session->add_commands (cmds);
6244 _session->add_command (new StatefulDiffCommand (pl));
6248 for (list<boost::shared_ptr<Region> >::iterator i = new_regions.begin(); i != new_regions.end(); ++i){
6249 set_selected_regionview_from_region_list ((*i), Selection::Add);
6255 Editor::place_transient()
6261 RegionSelection rs = get_regions_from_selection_and_edit_point ();
6267 framepos_t where = get_preferred_edit_position();
6269 _session->begin_reversible_command (_("place transient"));
6271 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6272 framepos_t position = (*r)->region()->position();
6273 (*r)->region()->add_transient(where - position);
6276 _session->commit_reversible_command ();
6280 Editor::remove_transient(ArdourCanvas::Item* item)
6286 ArdourCanvas::Line* _line = reinterpret_cast<ArdourCanvas::Line*> (item);
6289 AudioRegionView* _arv = reinterpret_cast<AudioRegionView*> (item->get_data ("regionview"));
6290 _arv->remove_transient (*(float*) _line->get_data ("position"));
6294 Editor::snap_regions_to_grid ()
6296 list <boost::shared_ptr<Playlist > > used_playlists;
6298 RegionSelection rs = get_regions_from_selection_and_entered ();
6300 if (!_session || rs.empty()) {
6304 _session->begin_reversible_command (_("snap regions to grid"));
6306 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6308 boost::shared_ptr<Playlist> pl = (*r)->region()->playlist();
6310 if (!pl->frozen()) {
6311 /* we haven't seen this playlist before */
6313 /* remember used playlists so we can thaw them later */
6314 used_playlists.push_back(pl);
6318 framepos_t start_frame = (*r)->region()->first_frame ();
6319 snap_to (start_frame);
6320 (*r)->region()->set_position (start_frame);
6323 while (used_playlists.size() > 0) {
6324 list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
6326 used_playlists.pop_front();
6329 _session->commit_reversible_command ();
6333 Editor::close_region_gaps ()
6335 list <boost::shared_ptr<Playlist > > used_playlists;
6337 RegionSelection rs = get_regions_from_selection_and_entered ();
6339 if (!_session || rs.empty()) {
6343 Dialog dialog (_("Close Region Gaps"));
6346 table.set_spacings (12);
6347 table.set_border_width (12);
6348 Label* l = manage (left_aligned_label (_("Crossfade length")));
6349 table.attach (*l, 0, 1, 0, 1);
6351 SpinButton spin_crossfade (1, 0);
6352 spin_crossfade.set_range (0, 15);
6353 spin_crossfade.set_increments (1, 1);
6354 spin_crossfade.set_value (5);
6355 table.attach (spin_crossfade, 1, 2, 0, 1);
6357 table.attach (*manage (new Label (_("ms"))), 2, 3, 0, 1);
6359 l = manage (left_aligned_label (_("Pull-back length")));
6360 table.attach (*l, 0, 1, 1, 2);
6362 SpinButton spin_pullback (1, 0);
6363 spin_pullback.set_range (0, 100);
6364 spin_pullback.set_increments (1, 1);
6365 spin_pullback.set_value(30);
6366 table.attach (spin_pullback, 1, 2, 1, 2);
6368 table.attach (*manage (new Label (_("ms"))), 2, 3, 1, 2);
6370 dialog.get_vbox()->pack_start (table);
6371 dialog.add_button (Stock::CANCEL, RESPONSE_CANCEL);
6372 dialog.add_button (_("Ok"), RESPONSE_ACCEPT);
6375 if (dialog.run () == RESPONSE_CANCEL) {
6379 framepos_t crossfade_len = spin_crossfade.get_value();
6380 framepos_t pull_back_frames = spin_pullback.get_value();
6382 crossfade_len = lrintf (crossfade_len * _session->frame_rate()/1000);
6383 pull_back_frames = lrintf (pull_back_frames * _session->frame_rate()/1000);
6385 /* Iterate over the region list and make adjacent regions overlap by crossfade_len_ms */
6387 _session->begin_reversible_command (_("close region gaps"));
6390 boost::shared_ptr<Region> last_region;
6392 rs.sort_by_position_and_track();
6394 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6396 boost::shared_ptr<Playlist> pl = (*r)->region()->playlist();
6398 if (!pl->frozen()) {
6399 /* we haven't seen this playlist before */
6401 /* remember used playlists so we can thaw them later */
6402 used_playlists.push_back(pl);
6406 framepos_t position = (*r)->region()->position();
6408 if (idx == 0 || position < last_region->position()){
6409 last_region = (*r)->region();
6414 (*r)->region()->trim_front( (position - pull_back_frames));
6415 last_region->trim_end( (position - pull_back_frames + crossfade_len));
6417 last_region = (*r)->region();
6422 while (used_playlists.size() > 0) {
6423 list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
6425 used_playlists.pop_front();
6428 _session->commit_reversible_command ();
6432 Editor::tab_to_transient (bool forward)
6434 AnalysisFeatureList positions;
6436 RegionSelection rs = get_regions_from_selection_and_entered ();
6442 framepos_t pos = _session->audible_frame ();
6444 if (!selection->tracks.empty()) {
6446 /* don't waste time searching for transients in duplicate playlists.
6449 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
6451 for (TrackViewList::iterator t = ts.begin(); t != ts.end(); ++t) {
6453 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*t);
6456 boost::shared_ptr<Track> tr = rtv->track();
6458 boost::shared_ptr<Playlist> pl = tr->playlist ();
6460 framepos_t result = pl->find_next_transient (pos, forward ? 1 : -1);
6463 positions.push_back (result);
6476 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6477 (*r)->region()->get_transients (positions);
6481 TransientDetector::cleanup_transients (positions, _session->frame_rate(), 3.0);
6484 AnalysisFeatureList::iterator x;
6486 for (x = positions.begin(); x != positions.end(); ++x) {
6492 if (x != positions.end ()) {
6493 _session->request_locate (*x);
6497 AnalysisFeatureList::reverse_iterator x;
6499 for (x = positions.rbegin(); x != positions.rend(); ++x) {
6505 if (x != positions.rend ()) {
6506 _session->request_locate (*x);
6512 Editor::playhead_forward_to_grid ()
6518 framepos_t pos = playhead_cursor->current_frame ();
6519 if (pos < max_framepos - 1) {
6521 snap_to_internal (pos, RoundUpAlways, false);
6522 _session->request_locate (pos);
6528 Editor::playhead_backward_to_grid ()
6534 framepos_t pos = playhead_cursor->current_frame ();
6537 snap_to_internal (pos, RoundDownAlways, false);
6538 _session->request_locate (pos);
6543 Editor::set_track_height (Height h)
6545 TrackSelection& ts (selection->tracks);
6547 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
6548 (*x)->set_height_enum (h);
6553 Editor::toggle_tracks_active ()
6555 TrackSelection& ts (selection->tracks);
6557 bool target = false;
6563 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
6564 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*x);
6568 target = !rtv->_route->active();
6571 rtv->_route->set_active (target, this);
6577 Editor::remove_tracks ()
6579 TrackSelection& ts (selection->tracks);
6585 vector<string> choices;
6589 const char* trackstr;
6591 vector<boost::shared_ptr<Route> > routes;
6592 bool special_bus = false;
6594 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
6595 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*x);
6599 if (rtv->is_track()) {
6604 routes.push_back (rtv->_route);
6606 if (rtv->route()->is_master() || rtv->route()->is_monitor()) {
6611 if (special_bus && !Config->get_allow_special_bus_removal()) {
6612 MessageDialog msg (_("That would be bad news ...."),
6616 msg.set_secondary_text (string_compose (_(
6617 "Removing the master or monitor bus is such a bad idea\n\
6618 that %1 is not going to allow it.\n\
6620 If you really want to do this sort of thing\n\
6621 edit your ardour.rc file to set the\n\
6622 \"allow-special-bus-removal\" option to be \"yes\""), PROGRAM_NAME));
6629 if (ntracks + nbusses == 0) {
6633 // XXX should be using gettext plural forms, maybe?
6635 trackstr = _("tracks");
6637 trackstr = _("track");
6641 busstr = _("busses");
6648 prompt = string_compose (_("Do you really want to remove %1 %2 and %3 %4?\n"
6649 "(You may also lose the playlists associated with the %2)\n\n"
6650 "This action cannot be undone, and the session file will be overwritten!"),
6651 ntracks, trackstr, nbusses, busstr);
6653 prompt = string_compose (_("Do you really want to remove %1 %2?\n"
6654 "(You may also lose the playlists associated with the %2)\n\n"
6655 "This action cannot be undone, and the session file will be overwritten!"),
6658 } else if (nbusses) {
6659 prompt = string_compose (_("Do you really want to remove %1 %2?\n\n"
6660 "This action cannot be undone, and the session file will be overwritten"),
6664 choices.push_back (_("No, do nothing."));
6665 if (ntracks + nbusses > 1) {
6666 choices.push_back (_("Yes, remove them."));
6668 choices.push_back (_("Yes, remove it."));
6673 title = string_compose (_("Remove %1"), trackstr);
6675 title = string_compose (_("Remove %1"), busstr);
6678 Choice prompter (title, prompt, choices);
6680 if (prompter.run () != 1) {
6685 Session::StateProtector sp (_session);
6686 DisplaySuspender ds;
6687 for (vector<boost::shared_ptr<Route> >::iterator x = routes.begin(); x != routes.end(); ++x) {
6688 _session->remove_route (*x);
6694 Editor::do_insert_time ()
6696 if (selection->tracks.empty()) {
6700 InsertTimeDialog d (*this);
6701 int response = d.run ();
6703 if (response != RESPONSE_OK) {
6707 if (d.distance() == 0) {
6711 InsertTimeOption opt = d.intersected_region_action ();
6714 get_preferred_edit_position(),
6720 d.move_glued_markers(),
6721 d.move_locked_markers(),
6727 Editor::insert_time (
6728 framepos_t pos, framecnt_t frames, InsertTimeOption opt,
6729 bool all_playlists, bool ignore_music_glue, bool markers_too, bool glued_markers_too, bool locked_markers_too, bool tempo_too
6732 bool commit = false;
6734 if (Config->get_edit_mode() == Lock) {
6738 begin_reversible_command (_("insert time"));
6740 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
6742 for (TrackViewList::iterator x = ts.begin(); x != ts.end(); ++x) {
6746 /* don't operate on any playlist more than once, which could
6747 * happen if "all playlists" is enabled, but there is more
6748 * than 1 track using playlists "from" a given track.
6751 set<boost::shared_ptr<Playlist> > pl;
6753 if (all_playlists) {
6754 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*x);
6756 vector<boost::shared_ptr<Playlist> > all = _session->playlists->playlists_for_track (rtav->track ());
6757 for (vector<boost::shared_ptr<Playlist> >::iterator p = all.begin(); p != all.end(); ++p) {
6762 if ((*x)->playlist ()) {
6763 pl.insert ((*x)->playlist ());
6767 for (set<boost::shared_ptr<Playlist> >::iterator i = pl.begin(); i != pl.end(); ++i) {
6769 (*i)->clear_changes ();
6770 (*i)->clear_owned_changes ();
6772 if (opt == SplitIntersected) {
6776 (*i)->shift (pos, frames, (opt == MoveIntersected), ignore_music_glue);
6778 vector<Command*> cmds;
6780 _session->add_commands (cmds);
6782 _session->add_command (new StatefulDiffCommand (*i));
6787 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*x);
6789 rtav->route ()->shift (pos, frames);
6797 XMLNode& before (_session->locations()->get_state());
6798 Locations::LocationList copy (_session->locations()->list());
6800 for (Locations::LocationList::iterator i = copy.begin(); i != copy.end(); ++i) {
6802 Locations::LocationList::const_iterator tmp;
6804 bool const was_locked = (*i)->locked ();
6805 if (locked_markers_too) {
6809 if ((*i)->position_lock_style() == AudioTime || glued_markers_too) {
6811 if ((*i)->start() >= pos) {
6812 (*i)->set_start ((*i)->start() + frames);
6813 if (!(*i)->is_mark()) {
6814 (*i)->set_end ((*i)->end() + frames);
6827 XMLNode& after (_session->locations()->get_state());
6828 _session->add_command (new MementoCommand<Locations>(*_session->locations(), &before, &after));
6833 _session->tempo_map().insert_time (pos, frames);
6837 commit_reversible_command ();
6842 Editor::fit_selected_tracks ()
6844 if (!selection->tracks.empty()) {
6845 fit_tracks (selection->tracks);
6849 /* no selected tracks - use tracks with selected regions */
6851 if (!selection->regions.empty()) {
6852 for (RegionSelection::iterator r = selection->regions.begin(); r != selection->regions.end(); ++r) {
6853 tvl.push_back (&(*r)->get_time_axis_view ());
6859 } else if (internal_editing()) {
6860 /* no selected tracks, or regions, but in internal edit mode, so follow the mouse and use
6863 if (entered_track) {
6864 tvl.push_back (entered_track);
6873 Editor::fit_tracks (TrackViewList & tracks)
6875 if (tracks.empty()) {
6879 uint32_t child_heights = 0;
6880 int visible_tracks = 0;
6882 for (TrackSelection::iterator t = tracks.begin(); t != tracks.end(); ++t) {
6884 if (!(*t)->marked_for_display()) {
6888 child_heights += (*t)->effective_height() - (*t)->current_height();
6892 /* compute the per-track height from:
6894 total canvas visible height -
6895 height that will be taken by visible children of selected
6896 tracks - height of the ruler/hscroll area
6898 uint32_t h = (uint32_t) floor ((trackviews_height() - child_heights) / visible_tracks);
6899 double first_y_pos = DBL_MAX;
6901 if (h < TimeAxisView::preset_height (HeightSmall)) {
6902 MessageDialog msg (*this, _("There are too many tracks to fit in the current window"));
6903 /* too small to be displayed */
6907 undo_visual_stack.push_back (current_visual_state (true));
6908 no_save_visual = true;
6910 /* build a list of all tracks, including children */
6913 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
6915 TimeAxisView::Children c = (*i)->get_child_list ();
6916 for (TimeAxisView::Children::iterator j = c.begin(); j != c.end(); ++j) {
6917 all.push_back (j->get());
6921 bool prev_was_selected = false;
6922 bool is_selected = tracks.contains (all.front());
6923 bool next_is_selected;
6925 for (TrackViewList::iterator t = all.begin(); t != all.end(); ++t) {
6927 TrackViewList::iterator next;
6932 if (next != all.end()) {
6933 next_is_selected = tracks.contains (*next);
6935 next_is_selected = false;
6938 if ((*t)->marked_for_display ()) {
6940 (*t)->set_height (h);
6941 first_y_pos = std::min ((*t)->y_position (), first_y_pos);
6943 if (prev_was_selected && next_is_selected) {
6944 hide_track_in_display (*t);
6949 prev_was_selected = is_selected;
6950 is_selected = next_is_selected;
6954 set the controls_layout height now, because waiting for its size
6955 request signal handler will cause the vertical adjustment setting to fail
6958 controls_layout.property_height () = _full_canvas_height;
6959 vertical_adjustment.set_value (first_y_pos);
6961 redo_visual_stack.push_back (current_visual_state (true));
6963 visible_tracks_selector.set_text (_("Sel"));
6967 Editor::save_visual_state (uint32_t n)
6969 while (visual_states.size() <= n) {
6970 visual_states.push_back (0);
6973 if (visual_states[n] != 0) {
6974 delete visual_states[n];
6977 visual_states[n] = current_visual_state (true);
6982 Editor::goto_visual_state (uint32_t n)
6984 if (visual_states.size() <= n) {
6988 if (visual_states[n] == 0) {
6992 use_visual_state (*visual_states[n]);
6996 Editor::start_visual_state_op (uint32_t n)
6998 save_visual_state (n);
7000 PopUp* pup = new PopUp (WIN_POS_MOUSE, 1000, true);
7002 snprintf (buf, sizeof (buf), _("Saved view %u"), n+1);
7003 pup->set_text (buf);
7008 Editor::cancel_visual_state_op (uint32_t n)
7010 goto_visual_state (n);
7014 Editor::toggle_region_mute ()
7016 if (_ignore_region_action) {
7020 RegionSelection rs = get_regions_from_selection_and_entered ();
7026 if (rs.size() > 1) {
7027 begin_reversible_command (_("mute regions"));
7029 begin_reversible_command (_("mute region"));
7032 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
7034 (*i)->region()->playlist()->clear_changes ();
7035 (*i)->region()->set_muted (!(*i)->region()->muted ());
7036 _session->add_command (new StatefulDiffCommand ((*i)->region()->playlist()));
7040 commit_reversible_command ();
7044 Editor::combine_regions ()
7046 /* foreach track with selected regions, take all selected regions
7047 and join them into a new region containing the subregions (as a
7051 typedef set<RouteTimeAxisView*> RTVS;
7054 if (selection->regions.empty()) {
7058 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
7059 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(&(*i)->get_time_axis_view());
7062 tracks.insert (rtv);
7066 begin_reversible_command (_("combine regions"));
7068 vector<RegionView*> new_selection;
7070 for (RTVS::iterator i = tracks.begin(); i != tracks.end(); ++i) {
7073 if ((rv = (*i)->combine_regions ()) != 0) {
7074 new_selection.push_back (rv);
7078 selection->clear_regions ();
7079 for (vector<RegionView*>::iterator i = new_selection.begin(); i != new_selection.end(); ++i) {
7080 selection->add (*i);
7083 commit_reversible_command ();
7087 Editor::uncombine_regions ()
7089 typedef set<RouteTimeAxisView*> RTVS;
7092 if (selection->regions.empty()) {
7096 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
7097 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(&(*i)->get_time_axis_view());
7100 tracks.insert (rtv);
7104 begin_reversible_command (_("uncombine regions"));
7106 for (RTVS::iterator i = tracks.begin(); i != tracks.end(); ++i) {
7107 (*i)->uncombine_regions ();
7110 commit_reversible_command ();
7114 Editor::toggle_midi_input_active (bool flip_others)
7117 boost::shared_ptr<RouteList> rl (new RouteList);
7119 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
7120 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
7126 boost::shared_ptr<MidiTrack> mt = rtav->midi_track();
7129 rl->push_back (rtav->route());
7130 onoff = !mt->input_active();
7134 _session->set_exclusive_input_active (rl, onoff, flip_others);
7141 lock_dialog = new Gtk::Dialog (string_compose (_("%1: Locked"), PROGRAM_NAME), true);
7143 Gtk::Image* padlock = manage (new Gtk::Image (ARDOUR_UI_UTILS::get_icon ("padlock_closed")));
7144 lock_dialog->get_vbox()->pack_start (*padlock);
7146 ArdourButton* b = manage (new ArdourButton);
7147 b->set_name ("lock button");
7148 b->set_text (_("Click to unlock"));
7149 b->signal_clicked.connect (sigc::mem_fun (*this, &Editor::unlock));
7150 lock_dialog->get_vbox()->pack_start (*b);
7152 lock_dialog->get_vbox()->show_all ();
7153 lock_dialog->set_size_request (200, 200);
7157 /* The global menu bar continues to be accessible to applications
7158 with modal dialogs, which means that we need to desensitize
7159 all items in the menu bar. Since those items are really just
7160 proxies for actions, that means disabling all actions.
7162 ActionManager::disable_all_actions ();
7164 lock_dialog->present ();
7170 lock_dialog->hide ();
7173 ActionManager::pop_action_state ();
7176 if (ARDOUR_UI::config()->get_lock_gui_after_seconds()) {
7177 start_lock_event_timing ();
7182 Editor::bring_in_callback (Gtk::Label* label, uint32_t n, uint32_t total, string name)
7184 Gtkmm2ext::UI::instance()->call_slot (invalidator (*this), boost::bind (&Editor::update_bring_in_message, this, label, n, total, name));
7188 Editor::update_bring_in_message (Gtk::Label* label, uint32_t n, uint32_t total, string name)
7190 label->set_text (string_compose ("Copying %1, %2 of %3", name, n, total));
7191 Gtkmm2ext::UI::instance()->flush_pending ();
7195 Editor::bring_all_sources_into_session ()
7202 ArdourDialog w (_("Moving embedded files into session folder"));
7203 w.get_vbox()->pack_start (msg);
7206 /* flush all pending GUI events because we're about to start copying
7210 Gtkmm2ext::UI::instance()->flush_pending ();
7214 _session->bring_all_sources_into_session (boost::bind (&Editor::bring_in_callback, this, &msg, _1, _2, _3));