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 boost::shared_ptr<Playlist> playlist = clicked_routeview->playlist();
4046 playlist->clear_changes ();
4047 playlist->clear_owned_changes ();
4048 playlist->remove_region (clicked_regionview->region());
4049 if (Config->get_edit_mode() == Ripple)
4050 playlist->ripple (clicked_regionview->region()->position(), -clicked_regionview->region()->length(), boost::shared_ptr<Region>());
4052 /* We might have removed regions, which alters other regions' layering_index,
4053 so we need to do a recursive diff here.
4055 vector<Command*> cmds;
4056 playlist->rdiff (cmds);
4057 _session->add_commands (cmds);
4059 _session->add_command(new StatefulDiffCommand (playlist));
4060 commit_reversible_command ();
4064 /** Remove the selected regions */
4066 Editor::remove_selected_regions ()
4068 RegionSelection rs = get_regions_from_selection_and_entered ();
4070 if (!_session || rs.empty()) {
4074 begin_reversible_command (_("remove region"));
4076 list<boost::shared_ptr<Region> > regions_to_remove;
4078 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
4079 // we can't just remove the region(s) in this loop because
4080 // this removes them from the RegionSelection, and they thus
4081 // disappear from underneath the iterator, and the ++i above
4082 // SEGVs in a puzzling fashion.
4084 // so, first iterate over the regions to be removed from rs and
4085 // add them to the regions_to_remove list, and then
4086 // iterate over the list to actually remove them.
4088 regions_to_remove.push_back ((*i)->region());
4091 vector<boost::shared_ptr<Playlist> > playlists;
4093 for (list<boost::shared_ptr<Region> >::iterator rl = regions_to_remove.begin(); rl != regions_to_remove.end(); ++rl) {
4095 boost::shared_ptr<Playlist> playlist = (*rl)->playlist();
4098 // is this check necessary?
4102 /* get_regions_from_selection_and_entered() guarantees that
4103 the playlists involved are unique, so there is no need
4107 playlists.push_back (playlist);
4109 playlist->clear_changes ();
4110 playlist->clear_owned_changes ();
4111 playlist->freeze ();
4112 playlist->remove_region (*rl);
4113 if (Config->get_edit_mode() == Ripple)
4114 playlist->ripple ((*rl)->position(), -(*rl)->length(), boost::shared_ptr<Region>());
4118 vector<boost::shared_ptr<Playlist> >::iterator pl;
4120 for (pl = playlists.begin(); pl != playlists.end(); ++pl) {
4123 /* We might have removed regions, which alters other regions' layering_index,
4124 so we need to do a recursive diff here.
4126 vector<Command*> cmds;
4127 (*pl)->rdiff (cmds);
4128 _session->add_commands (cmds);
4130 _session->add_command(new StatefulDiffCommand (*pl));
4133 commit_reversible_command ();
4136 /** Cut, copy or clear selected regions.
4137 * @param op Operation (Cut, Copy or Clear)
4140 Editor::cut_copy_regions (CutCopyOp op, RegionSelection& rs)
4142 /* we can't use a std::map here because the ordering is important, and we can't trivially sort
4143 a map when we want ordered access to both elements. i think.
4146 vector<PlaylistMapping> pmap;
4148 framepos_t first_position = max_framepos;
4150 typedef set<boost::shared_ptr<Playlist> > FreezeList;
4151 FreezeList freezelist;
4153 /* get ordering correct before we cut/copy */
4155 rs.sort_by_position_and_track ();
4157 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
4159 first_position = min ((framepos_t) (*x)->region()->position(), first_position);
4161 if (op == Cut || op == Clear || op == Delete) {
4162 boost::shared_ptr<Playlist> pl = (*x)->region()->playlist();
4165 FreezeList::iterator fl;
4167 // only take state if this is a new playlist.
4168 for (fl = freezelist.begin(); fl != freezelist.end(); ++fl) {
4174 if (fl == freezelist.end()) {
4175 pl->clear_changes();
4176 pl->clear_owned_changes ();
4178 freezelist.insert (pl);
4183 TimeAxisView* tv = &(*x)->get_time_axis_view();
4184 vector<PlaylistMapping>::iterator z;
4186 for (z = pmap.begin(); z != pmap.end(); ++z) {
4187 if ((*z).tv == tv) {
4192 if (z == pmap.end()) {
4193 pmap.push_back (PlaylistMapping (tv));
4197 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ) {
4199 boost::shared_ptr<Playlist> pl = (*x)->region()->playlist();
4202 /* region not yet associated with a playlist (e.g. unfinished
4209 TimeAxisView& tv = (*x)->get_time_axis_view();
4210 boost::shared_ptr<Playlist> npl;
4211 RegionSelection::iterator tmp;
4218 vector<PlaylistMapping>::iterator z;
4220 for (z = pmap.begin(); z != pmap.end(); ++z) {
4221 if ((*z).tv == &tv) {
4226 assert (z != pmap.end());
4229 npl = PlaylistFactory::create (pl->data_type(), *_session, "cutlist", true);
4237 boost::shared_ptr<Region> r = (*x)->region();
4238 boost::shared_ptr<Region> _xx;
4244 pl->remove_region (r);
4245 if (Config->get_edit_mode() == Ripple)
4246 pl->ripple (r->position(), -r->length(), boost::shared_ptr<Region>());
4250 _xx = RegionFactory::create (r);
4251 npl->add_region (_xx, r->position() - first_position);
4252 pl->remove_region (r);
4253 if (Config->get_edit_mode() == Ripple)
4254 pl->ripple (r->position(), -r->length(), boost::shared_ptr<Region>());
4258 /* copy region before adding, so we're not putting same object into two different playlists */
4259 npl->add_region (RegionFactory::create (r), r->position() - first_position);
4263 pl->remove_region (r);
4264 if (Config->get_edit_mode() == Ripple)
4265 pl->ripple (r->position(), -r->length(), boost::shared_ptr<Region>());
4274 list<boost::shared_ptr<Playlist> > foo;
4276 /* the pmap is in the same order as the tracks in which selected regions occured */
4278 for (vector<PlaylistMapping>::iterator i = pmap.begin(); i != pmap.end(); ++i) {
4281 foo.push_back ((*i).pl);
4286 cut_buffer->set (foo);
4290 _last_cut_copy_source_track = 0;
4292 _last_cut_copy_source_track = pmap.front().tv;
4296 for (FreezeList::iterator pl = freezelist.begin(); pl != freezelist.end(); ++pl) {
4299 /* We might have removed regions, which alters other regions' layering_index,
4300 so we need to do a recursive diff here.
4302 vector<Command*> cmds;
4303 (*pl)->rdiff (cmds);
4304 _session->add_commands (cmds);
4306 _session->add_command (new StatefulDiffCommand (*pl));
4311 Editor::cut_copy_ranges (CutCopyOp op)
4313 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4315 /* Sort the track selection now, so that it if is used, the playlists
4316 selected by the calls below to cut_copy_clear are in the order that
4317 their tracks appear in the editor. This makes things like paste
4318 of ranges work properly.
4321 sort_track_selection (ts);
4324 if (!entered_track) {
4327 ts.push_back (entered_track);
4330 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4331 (*i)->cut_copy_clear (*selection, op);
4336 Editor::paste (float times, bool from_context)
4338 DEBUG_TRACE (DEBUG::CutNPaste, "paste to preferred edit pos\n");
4340 paste_internal (get_preferred_edit_position (false, from_context), times);
4344 Editor::mouse_paste ()
4349 if (!mouse_frame (where, ignored)) {
4354 paste_internal (where, 1);
4358 Editor::paste_internal (framepos_t position, float times)
4360 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("apparent paste position is %1\n", position));
4362 if (cut_buffer->empty(internal_editing())) {
4366 if (position == max_framepos) {
4367 position = get_preferred_edit_position();
4368 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("preferred edit position is %1\n", position));
4371 if (position == last_paste_pos) {
4372 /* repeated paste in the same position */
4375 /* paste in new location, reset repeated paste state */
4377 last_paste_pos = position;
4380 /* get everything in the correct order */
4383 if (!selection->tracks.empty()) {
4384 /* If there is a track selection, paste into exactly those tracks and
4385 only those tracks. This allows the user to be explicit and override
4386 the below "do the reasonable thing" logic. */
4387 ts = selection->tracks.filter_to_unique_playlists ();
4388 sort_track_selection (ts);
4390 /* Figure out which track to base the paste at. */
4391 TimeAxisView* base_track = NULL;
4392 if (_edit_point == Editing::EditAtMouse && entered_track) {
4393 /* With the mouse edit point, paste onto the track under the mouse. */
4394 base_track = entered_track;
4395 } else if (_edit_point == Editing::EditAtMouse && entered_regionview) {
4396 /* With the mouse edit point, paste onto the track of the region under the mouse. */
4397 base_track = &entered_regionview->get_time_axis_view();
4398 } else if (_last_cut_copy_source_track) {
4399 /* Paste to the track that the cut/copy came from (see mantis #333). */
4400 base_track = _last_cut_copy_source_track;
4402 /* This is "impossible" since we've copied... well, do nothing. */
4406 /* Walk up to parent if necessary, so base track is a route. */
4407 while (base_track->get_parent()) {
4408 base_track = base_track->get_parent();
4411 /* Add base track and all tracks below it. The paste logic will select
4412 the appropriate object types from the cut buffer in relative order. */
4413 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4414 if ((*i)->order() >= base_track->order()) {
4419 /* Sort tracks so the nth track of type T will pick the nth object of type T. */
4420 sort_track_selection (ts);
4422 /* Add automation children of each track in order, for pasting several lines. */
4423 for (TrackViewList::iterator i = ts.begin(); i != ts.end();) {
4424 /* Add any automation children for pasting several lines */
4425 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*i++);
4430 typedef RouteTimeAxisView::AutomationTracks ATracks;
4431 const ATracks& atracks = rtv->automation_tracks();
4432 for (ATracks::const_iterator a = atracks.begin(); a != atracks.end(); ++a) {
4433 i = ts.insert(i, a->second.get());
4438 /* We now have a list of trackviews starting at base_track, including
4439 automation children, in the order shown in the editor, e.g. R1,
4440 R1.A1, R1.A2, R2, R2.A1, ... */
4443 if (ts.size() == 1 && cut_buffer->lines.size() == 1 &&
4444 dynamic_cast<AutomationTimeAxisView*>(ts.front())) {
4445 /* Only one line copied, and one automation track selected. Do a
4446 "greedy" paste from one automation type to another. */
4448 begin_reversible_command (Operations::paste);
4450 PasteContext ctx(paste_count, times, ItemCounts(), true);
4451 ts.front()->paste (position, *cut_buffer, ctx);
4453 commit_reversible_command ();
4455 } else if (internal_editing ()) {
4457 /* undo/redo is handled by individual tracks/regions */
4460 get_regions_at (rs, position, ts);
4462 PasteContext ctx(paste_count, times, ItemCounts(), false);
4463 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
4464 MidiRegionView* mrv = dynamic_cast<MidiRegionView*> (*r);
4466 mrv->paste (position, *cut_buffer, ctx);
4472 /* we do redo (do you do voodoo?) */
4474 begin_reversible_command (Operations::paste);
4476 PasteContext ctx(paste_count, times, ItemCounts(), false);
4477 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4478 (*i)->paste (position, *cut_buffer, ctx);
4481 commit_reversible_command ();
4486 Editor::duplicate_some_regions (RegionSelection& regions, float times)
4488 boost::shared_ptr<Playlist> playlist;
4489 RegionSelection sel = regions; // clear (below) may clear the argument list if its the current region selection
4490 RegionSelection foo;
4492 framepos_t const start_frame = regions.start ();
4493 framepos_t const end_frame = regions.end_frame ();
4495 begin_reversible_command (Operations::duplicate_region);
4497 selection->clear_regions ();
4499 for (RegionSelection::iterator i = sel.begin(); i != sel.end(); ++i) {
4501 boost::shared_ptr<Region> r ((*i)->region());
4503 TimeAxisView& tv = (*i)->get_time_axis_view();
4504 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (&tv);
4505 latest_regionviews.clear ();
4506 sigc::connection c = rtv->view()->RegionViewAdded.connect (sigc::mem_fun(*this, &Editor::collect_new_region_view));
4508 playlist = (*i)->region()->playlist();
4509 playlist->clear_changes ();
4510 playlist->duplicate (r, end_frame + (r->first_frame() - start_frame), times);
4511 _session->add_command(new StatefulDiffCommand (playlist));
4515 foo.insert (foo.end(), latest_regionviews.begin(), latest_regionviews.end());
4518 commit_reversible_command ();
4521 selection->set (foo);
4526 Editor::duplicate_selection (float times)
4528 if (selection->time.empty() || selection->tracks.empty()) {
4532 boost::shared_ptr<Playlist> playlist;
4533 vector<boost::shared_ptr<Region> > new_regions;
4534 vector<boost::shared_ptr<Region> >::iterator ri;
4536 create_region_from_selection (new_regions);
4538 if (new_regions.empty()) {
4542 begin_reversible_command (_("duplicate selection"));
4544 ri = new_regions.begin();
4546 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4548 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4549 if ((playlist = (*i)->playlist()) == 0) {
4552 playlist->clear_changes ();
4553 playlist->duplicate (*ri, selection->time[clicked_selection].end, times);
4554 _session->add_command (new StatefulDiffCommand (playlist));
4557 if (ri == new_regions.end()) {
4562 commit_reversible_command ();
4565 /** Reset all selected points to the relevant default value */
4567 Editor::reset_point_selection ()
4569 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
4570 ARDOUR::AutomationList::iterator j = (*i)->model ();
4571 (*j)->value = (*i)->line().the_list()->default_value ();
4576 Editor::center_playhead ()
4578 float const page = _visible_canvas_width * samples_per_pixel;
4579 center_screen_internal (playhead_cursor->current_frame (), page);
4583 Editor::center_edit_point ()
4585 float const page = _visible_canvas_width * samples_per_pixel;
4586 center_screen_internal (get_preferred_edit_position(), page);
4589 /** Caller must begin and commit a reversible command */
4591 Editor::clear_playlist (boost::shared_ptr<Playlist> playlist)
4593 playlist->clear_changes ();
4595 _session->add_command (new StatefulDiffCommand (playlist));
4599 Editor::nudge_track (bool use_edit, bool forwards)
4601 boost::shared_ptr<Playlist> playlist;
4602 framepos_t distance;
4603 framepos_t next_distance;
4607 start = get_preferred_edit_position();
4612 if ((distance = get_nudge_distance (start, next_distance)) == 0) {
4616 if (selection->tracks.empty()) {
4620 begin_reversible_command (_("nudge track"));
4622 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4624 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4626 if ((playlist = (*i)->playlist()) == 0) {
4630 playlist->clear_changes ();
4631 playlist->clear_owned_changes ();
4633 playlist->nudge_after (start, distance, forwards);
4635 vector<Command*> cmds;
4637 playlist->rdiff (cmds);
4638 _session->add_commands (cmds);
4640 _session->add_command (new StatefulDiffCommand (playlist));
4643 commit_reversible_command ();
4647 Editor::remove_last_capture ()
4649 vector<string> choices;
4656 if (Config->get_verify_remove_last_capture()) {
4657 prompt = _("Do you really want to destroy the last capture?"
4658 "\n(This is destructive and cannot be undone)");
4660 choices.push_back (_("No, do nothing."));
4661 choices.push_back (_("Yes, destroy it."));
4663 Gtkmm2ext::Choice prompter (_("Destroy last capture"), prompt, choices);
4665 if (prompter.run () == 1) {
4666 _session->remove_last_capture ();
4667 _regions->redisplay ();
4671 _session->remove_last_capture();
4672 _regions->redisplay ();
4677 Editor::normalize_region ()
4683 RegionSelection rs = get_regions_from_selection_and_entered ();
4689 NormalizeDialog dialog (rs.size() > 1);
4691 if (dialog.run () == RESPONSE_CANCEL) {
4695 set_canvas_cursor (_cursors->wait);
4698 /* XXX: should really only count audio regions here */
4699 int const regions = rs.size ();
4701 /* Make a list of the selected audio regions' maximum amplitudes, and also
4702 obtain the maximum amplitude of them all.
4704 list<double> max_amps;
4706 for (RegionSelection::const_iterator i = rs.begin(); i != rs.end(); ++i) {
4707 AudioRegionView const * arv = dynamic_cast<AudioRegionView const *> (*i);
4709 dialog.descend (1.0 / regions);
4710 double const a = arv->audio_region()->maximum_amplitude (&dialog);
4713 /* the user cancelled the operation */
4714 set_canvas_cursor (current_canvas_cursor);
4718 max_amps.push_back (a);
4719 max_amp = max (max_amp, a);
4724 begin_reversible_command (_("normalize"));
4726 list<double>::const_iterator a = max_amps.begin ();
4728 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
4729 AudioRegionView* const arv = dynamic_cast<AudioRegionView*> (*r);
4734 arv->region()->clear_changes ();
4736 double const amp = dialog.normalize_individually() ? *a : max_amp;
4738 arv->audio_region()->normalize (amp, dialog.target ());
4739 _session->add_command (new StatefulDiffCommand (arv->region()));
4744 commit_reversible_command ();
4745 set_canvas_cursor (current_canvas_cursor);
4750 Editor::reset_region_scale_amplitude ()
4756 RegionSelection rs = get_regions_from_selection_and_entered ();
4762 begin_reversible_command ("reset gain");
4764 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
4765 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
4768 arv->region()->clear_changes ();
4769 arv->audio_region()->set_scale_amplitude (1.0f);
4770 _session->add_command (new StatefulDiffCommand (arv->region()));
4773 commit_reversible_command ();
4777 Editor::adjust_region_gain (bool up)
4779 RegionSelection rs = get_regions_from_selection_and_entered ();
4781 if (!_session || rs.empty()) {
4785 begin_reversible_command ("adjust region gain");
4787 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
4788 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
4793 arv->region()->clear_changes ();
4795 double dB = accurate_coefficient_to_dB (arv->audio_region()->scale_amplitude ());
4803 arv->audio_region()->set_scale_amplitude (dB_to_coefficient (dB));
4804 _session->add_command (new StatefulDiffCommand (arv->region()));
4807 commit_reversible_command ();
4812 Editor::reverse_region ()
4818 Reverse rev (*_session);
4819 apply_filter (rev, _("reverse regions"));
4823 Editor::strip_region_silence ()
4829 RegionSelection rs = get_regions_from_selection_and_entered ();
4835 std::list<RegionView*> audio_only;
4837 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
4838 AudioRegionView* const arv = dynamic_cast<AudioRegionView*> (*i);
4840 audio_only.push_back (arv);
4844 StripSilenceDialog d (_session, audio_only);
4845 int const r = d.run ();
4849 if (r == Gtk::RESPONSE_OK) {
4850 ARDOUR::AudioIntervalMap silences;
4851 d.silences (silences);
4852 StripSilence s (*_session, silences, d.fade_length());
4853 apply_filter (s, _("strip silence"), &d);
4858 Editor::apply_midi_note_edit_op_to_region (MidiOperator& op, MidiRegionView& mrv)
4860 Evoral::Sequence<Evoral::MusicalTime>::Notes selected;
4861 mrv.selection_as_notelist (selected, true);
4863 vector<Evoral::Sequence<Evoral::MusicalTime>::Notes> v;
4864 v.push_back (selected);
4866 framepos_t pos_frames = mrv.midi_region()->position() - mrv.midi_region()->start();
4867 Evoral::MusicalTime pos_beats = _session->tempo_map().framewalk_to_beats(0, pos_frames);
4869 return op (mrv.midi_region()->model(), pos_beats, v);
4873 Editor::apply_midi_note_edit_op (MidiOperator& op)
4877 RegionSelection rs = get_regions_from_selection_and_entered ();
4883 begin_reversible_command (op.name ());
4885 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
4886 RegionSelection::iterator tmp = r;
4889 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*r);
4892 cmd = apply_midi_note_edit_op_to_region (op, *mrv);
4895 _session->add_command (cmd);
4902 commit_reversible_command ();
4906 Editor::fork_region ()
4908 RegionSelection rs = get_regions_from_selection_and_entered ();
4914 begin_reversible_command (_("Fork Region(s)"));
4916 set_canvas_cursor (_cursors->wait);
4919 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
4920 RegionSelection::iterator tmp = r;
4923 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*>(*r);
4927 boost::shared_ptr<Playlist> playlist = mrv->region()->playlist();
4928 boost::shared_ptr<MidiSource> new_source = _session->create_midi_source_by_stealing_name (mrv->midi_view()->track());
4929 boost::shared_ptr<MidiRegion> newregion = mrv->midi_region()->clone (new_source);
4931 playlist->clear_changes ();
4932 playlist->replace_region (mrv->region(), newregion, mrv->region()->position());
4933 _session->add_command(new StatefulDiffCommand (playlist));
4935 error << string_compose (_("Could not unlink %1"), mrv->region()->name()) << endmsg;
4942 commit_reversible_command ();
4944 set_canvas_cursor (current_canvas_cursor);
4948 Editor::quantize_region ()
4950 int selected_midi_region_cnt = 0;
4956 RegionSelection rs = get_regions_from_selection_and_entered ();
4962 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
4963 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*r);
4965 selected_midi_region_cnt++;
4969 if (selected_midi_region_cnt == 0) {
4973 QuantizeDialog* qd = new QuantizeDialog (*this);
4976 const int r = qd->run ();
4979 if (r == Gtk::RESPONSE_OK) {
4980 Quantize quant (qd->snap_start(), qd->snap_end(),
4981 qd->start_grid_size(), qd->end_grid_size(),
4982 qd->strength(), qd->swing(), qd->threshold());
4984 apply_midi_note_edit_op (quant);
4989 Editor::insert_patch_change (bool from_context)
4991 RegionSelection rs = get_regions_from_selection_and_entered ();
4997 const framepos_t p = get_preferred_edit_position (false, from_context);
4999 /* XXX: bit of a hack; use the MIDNAM from the first selected region;
5000 there may be more than one, but the PatchChangeDialog can only offer
5001 one set of patch menus.
5003 MidiRegionView* first = dynamic_cast<MidiRegionView*> (rs.front ());
5005 Evoral::PatchChange<Evoral::MusicalTime> empty (Evoral::MusicalTime(), 0, 0, 0);
5006 PatchChangeDialog d (0, _session, empty, first->instrument_info(), Gtk::Stock::ADD);
5008 if (d.run() == RESPONSE_CANCEL) {
5012 for (RegionSelection::iterator i = rs.begin (); i != rs.end(); ++i) {
5013 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*i);
5015 if (p >= mrv->region()->first_frame() && p <= mrv->region()->last_frame()) {
5016 mrv->add_patch_change (p - mrv->region()->position(), d.patch ());
5023 Editor::apply_filter (Filter& filter, string command, ProgressReporter* progress)
5025 RegionSelection rs = get_regions_from_selection_and_entered ();
5031 begin_reversible_command (command);
5033 set_canvas_cursor (_cursors->wait);
5037 int const N = rs.size ();
5039 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
5040 RegionSelection::iterator tmp = r;
5043 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
5045 boost::shared_ptr<Playlist> playlist = arv->region()->playlist();
5048 progress->descend (1.0 / N);
5051 if (arv->audio_region()->apply (filter, progress) == 0) {
5053 playlist->clear_changes ();
5054 playlist->clear_owned_changes ();
5056 if (filter.results.empty ()) {
5058 /* no regions returned; remove the old one */
5059 playlist->remove_region (arv->region ());
5063 std::vector<boost::shared_ptr<Region> >::iterator res = filter.results.begin ();
5065 /* first region replaces the old one */
5066 playlist->replace_region (arv->region(), *res, (*res)->position());
5070 while (res != filter.results.end()) {
5071 playlist->add_region (*res, (*res)->position());
5077 /* We might have removed regions, which alters other regions' layering_index,
5078 so we need to do a recursive diff here.
5080 vector<Command*> cmds;
5081 playlist->rdiff (cmds);
5082 _session->add_commands (cmds);
5084 _session->add_command(new StatefulDiffCommand (playlist));
5090 progress->ascend ();
5098 commit_reversible_command ();
5101 set_canvas_cursor (current_canvas_cursor);
5105 Editor::external_edit_region ()
5111 Editor::reset_region_gain_envelopes ()
5113 RegionSelection rs = get_regions_from_selection_and_entered ();
5115 if (!_session || rs.empty()) {
5119 _session->begin_reversible_command (_("reset region gain"));
5121 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5122 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
5124 boost::shared_ptr<AutomationList> alist (arv->audio_region()->envelope());
5125 XMLNode& before (alist->get_state());
5127 arv->audio_region()->set_default_envelope ();
5128 _session->add_command (new MementoCommand<AutomationList>(*arv->audio_region()->envelope().get(), &before, &alist->get_state()));
5132 _session->commit_reversible_command ();
5136 Editor::set_region_gain_visibility (RegionView* rv)
5138 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (rv);
5140 arv->update_envelope_visibility();
5145 Editor::set_gain_envelope_visibility ()
5151 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5152 AudioTimeAxisView* v = dynamic_cast<AudioTimeAxisView*>(*i);
5154 v->audio_view()->foreach_regionview (sigc::mem_fun (this, &Editor::set_region_gain_visibility));
5160 Editor::toggle_gain_envelope_active ()
5162 if (_ignore_region_action) {
5166 RegionSelection rs = get_regions_from_selection_and_entered ();
5168 if (!_session || rs.empty()) {
5172 _session->begin_reversible_command (_("region gain envelope active"));
5174 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5175 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
5177 arv->region()->clear_changes ();
5178 arv->audio_region()->set_envelope_active (!arv->audio_region()->envelope_active());
5179 _session->add_command (new StatefulDiffCommand (arv->region()));
5183 _session->commit_reversible_command ();
5187 Editor::toggle_region_lock ()
5189 if (_ignore_region_action) {
5193 RegionSelection rs = get_regions_from_selection_and_entered ();
5195 if (!_session || rs.empty()) {
5199 _session->begin_reversible_command (_("toggle region lock"));
5201 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5202 (*i)->region()->clear_changes ();
5203 (*i)->region()->set_locked (!(*i)->region()->locked());
5204 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5207 _session->commit_reversible_command ();
5211 Editor::toggle_region_video_lock ()
5213 if (_ignore_region_action) {
5217 RegionSelection rs = get_regions_from_selection_and_entered ();
5219 if (!_session || rs.empty()) {
5223 _session->begin_reversible_command (_("Toggle Video Lock"));
5225 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5226 (*i)->region()->clear_changes ();
5227 (*i)->region()->set_video_locked (!(*i)->region()->video_locked());
5228 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5231 _session->commit_reversible_command ();
5235 Editor::toggle_region_lock_style ()
5237 if (_ignore_region_action) {
5241 RegionSelection rs = get_regions_from_selection_and_entered ();
5243 if (!_session || rs.empty()) {
5247 _session->begin_reversible_command (_("region lock style"));
5249 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5250 (*i)->region()->clear_changes ();
5251 PositionLockStyle const ns = (*i)->region()->position_lock_style() == AudioTime ? MusicTime : AudioTime;
5252 (*i)->region()->set_position_lock_style (ns);
5253 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5256 _session->commit_reversible_command ();
5260 Editor::toggle_opaque_region ()
5262 if (_ignore_region_action) {
5266 RegionSelection rs = get_regions_from_selection_and_entered ();
5268 if (!_session || rs.empty()) {
5272 _session->begin_reversible_command (_("change region opacity"));
5274 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5275 (*i)->region()->clear_changes ();
5276 (*i)->region()->set_opaque (!(*i)->region()->opaque());
5277 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5280 _session->commit_reversible_command ();
5284 Editor::toggle_record_enable ()
5286 bool new_state = false;
5288 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5289 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5292 if (!rtav->is_track())
5296 new_state = !rtav->track()->record_enabled();
5300 rtav->track()->set_record_enabled (new_state, this);
5305 Editor::toggle_solo ()
5307 bool new_state = false;
5309 boost::shared_ptr<RouteList> rl (new RouteList);
5311 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5312 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5319 new_state = !rtav->route()->soloed ();
5323 rl->push_back (rtav->route());
5326 _session->set_solo (rl, new_state, Session::rt_cleanup, true);
5330 Editor::toggle_mute ()
5332 bool new_state = false;
5334 boost::shared_ptr<RouteList> rl (new RouteList);
5336 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5337 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5344 new_state = !rtav->route()->muted();
5348 rl->push_back (rtav->route());
5351 _session->set_mute (rl, new_state, Session::rt_cleanup, true);
5355 Editor::toggle_solo_isolate ()
5361 Editor::fade_range ()
5363 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
5365 begin_reversible_command (_("fade range"));
5367 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
5368 (*i)->fade_range (selection->time);
5371 commit_reversible_command ();
5376 Editor::set_fade_length (bool in)
5378 RegionSelection rs = get_regions_from_selection_and_entered ();
5384 /* we need a region to measure the offset from the start */
5386 RegionView* rv = rs.front ();
5388 framepos_t pos = get_preferred_edit_position();
5392 if (pos > rv->region()->last_frame() || pos < rv->region()->first_frame()) {
5393 /* edit point is outside the relevant region */
5398 if (pos <= rv->region()->position()) {
5402 len = pos - rv->region()->position();
5403 cmd = _("set fade in length");
5405 if (pos >= rv->region()->last_frame()) {
5409 len = rv->region()->last_frame() - pos;
5410 cmd = _("set fade out length");
5413 begin_reversible_command (cmd);
5415 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5416 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5422 boost::shared_ptr<AutomationList> alist;
5424 alist = tmp->audio_region()->fade_in();
5426 alist = tmp->audio_region()->fade_out();
5429 XMLNode &before = alist->get_state();
5432 tmp->audio_region()->set_fade_in_length (len);
5433 tmp->audio_region()->set_fade_in_active (true);
5435 tmp->audio_region()->set_fade_out_length (len);
5436 tmp->audio_region()->set_fade_out_active (true);
5439 XMLNode &after = alist->get_state();
5440 _session->add_command(new MementoCommand<AutomationList>(*alist, &before, &after));
5443 commit_reversible_command ();
5447 Editor::set_fade_in_shape (FadeShape shape)
5449 RegionSelection rs = get_regions_from_selection_and_entered ();
5455 begin_reversible_command (_("set fade in shape"));
5457 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5458 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5464 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_in();
5465 XMLNode &before = alist->get_state();
5467 tmp->audio_region()->set_fade_in_shape (shape);
5469 XMLNode &after = alist->get_state();
5470 _session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
5473 commit_reversible_command ();
5478 Editor::set_fade_out_shape (FadeShape shape)
5480 RegionSelection rs = get_regions_from_selection_and_entered ();
5486 begin_reversible_command (_("set fade out shape"));
5488 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5489 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5495 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_out();
5496 XMLNode &before = alist->get_state();
5498 tmp->audio_region()->set_fade_out_shape (shape);
5500 XMLNode &after = alist->get_state();
5501 _session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
5504 commit_reversible_command ();
5508 Editor::set_fade_in_active (bool yn)
5510 RegionSelection rs = get_regions_from_selection_and_entered ();
5516 begin_reversible_command (_("set fade in active"));
5518 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5519 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5526 boost::shared_ptr<AudioRegion> ar (tmp->audio_region());
5528 ar->clear_changes ();
5529 ar->set_fade_in_active (yn);
5530 _session->add_command (new StatefulDiffCommand (ar));
5533 commit_reversible_command ();
5537 Editor::set_fade_out_active (bool yn)
5539 RegionSelection rs = get_regions_from_selection_and_entered ();
5545 begin_reversible_command (_("set fade out active"));
5547 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5548 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5554 boost::shared_ptr<AudioRegion> ar (tmp->audio_region());
5556 ar->clear_changes ();
5557 ar->set_fade_out_active (yn);
5558 _session->add_command(new StatefulDiffCommand (ar));
5561 commit_reversible_command ();
5565 Editor::toggle_region_fades (int dir)
5567 if (_ignore_region_action) {
5571 boost::shared_ptr<AudioRegion> ar;
5574 RegionSelection rs = get_regions_from_selection_and_entered ();
5580 RegionSelection::iterator i;
5581 for (i = rs.begin(); i != rs.end(); ++i) {
5582 if ((ar = boost::dynamic_pointer_cast<AudioRegion>((*i)->region())) != 0) {
5584 yn = ar->fade_out_active ();
5586 yn = ar->fade_in_active ();
5592 if (i == rs.end()) {
5596 /* XXX should this undo-able? */
5598 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5599 if ((ar = boost::dynamic_pointer_cast<AudioRegion>((*i)->region())) == 0) {
5602 if (dir == 1 || dir == 0) {
5603 ar->set_fade_in_active (!yn);
5606 if (dir == -1 || dir == 0) {
5607 ar->set_fade_out_active (!yn);
5613 /** Update region fade visibility after its configuration has been changed */
5615 Editor::update_region_fade_visibility ()
5617 bool _fade_visibility = _session->config.get_show_region_fades ();
5619 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5620 AudioTimeAxisView* v = dynamic_cast<AudioTimeAxisView*>(*i);
5622 if (_fade_visibility) {
5623 v->audio_view()->show_all_fades ();
5625 v->audio_view()->hide_all_fades ();
5632 Editor::set_edit_point ()
5637 if (!mouse_frame (where, ignored)) {
5643 if (selection->markers.empty()) {
5645 mouse_add_new_marker (where);
5650 Location* loc = find_location_from_marker (selection->markers.front(), ignored);
5653 loc->move_to (where);
5659 Editor::set_playhead_cursor ()
5661 if (entered_marker) {
5662 _session->request_locate (entered_marker->position(), _session->transport_rolling());
5667 if (!mouse_frame (where, ignored)) {
5674 _session->request_locate (where, _session->transport_rolling());
5678 if ( Config->get_follow_edits() )
5679 cancel_time_selection();
5683 Editor::split_region ()
5685 if ( !selection->time.empty()) {
5686 separate_regions_between (selection->time);
5690 RegionSelection rs = get_regions_from_selection_and_edit_point ();
5692 framepos_t where = get_preferred_edit_position ();
5698 split_regions_at (where, rs);
5701 struct EditorOrderRouteSorter {
5702 bool operator() (boost::shared_ptr<Route> a, boost::shared_ptr<Route> b) {
5703 return a->order_key () < b->order_key ();
5708 Editor::select_next_route()
5710 if (selection->tracks.empty()) {
5711 selection->set (track_views.front());
5715 TimeAxisView* current = selection->tracks.front();
5719 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5720 if (*i == current) {
5722 if (i != track_views.end()) {
5725 current = (*(track_views.begin()));
5726 //selection->set (*(track_views.begin()));
5731 rui = dynamic_cast<RouteUI *>(current);
5732 } while ( current->hidden() || (rui != NULL && !rui->route()->active()));
5734 selection->set(current);
5736 ensure_time_axis_view_is_visible (*current, false);
5740 Editor::select_prev_route()
5742 if (selection->tracks.empty()) {
5743 selection->set (track_views.front());
5747 TimeAxisView* current = selection->tracks.front();
5751 for (TrackViewList::reverse_iterator i = track_views.rbegin(); i != track_views.rend(); ++i) {
5752 if (*i == current) {
5754 if (i != track_views.rend()) {
5757 current = *(track_views.rbegin());
5762 rui = dynamic_cast<RouteUI *>(current);
5763 } while ( current->hidden() || (rui != NULL && !rui->route()->active()));
5765 selection->set (current);
5767 ensure_time_axis_view_is_visible (*current, false);
5771 Editor::set_loop_from_selection (bool play)
5773 if (_session == 0 || selection->time.empty()) {
5777 framepos_t start = selection->time[clicked_selection].start;
5778 framepos_t end = selection->time[clicked_selection].end;
5780 set_loop_range (start, end, _("set loop range from selection"));
5783 _session->request_locate (start, true);
5784 _session->request_play_loop (true);
5789 Editor::set_loop_from_edit_range (bool play)
5791 if (_session == 0) {
5798 if (!get_edit_op_range (start, end)) {
5802 set_loop_range (start, end, _("set loop range from edit range"));
5805 _session->request_locate (start, true);
5806 _session->request_play_loop (true);
5811 Editor::set_loop_from_region (bool play)
5813 framepos_t start = max_framepos;
5816 RegionSelection rs = get_regions_from_selection_and_entered ();
5822 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5823 if ((*i)->region()->position() < start) {
5824 start = (*i)->region()->position();
5826 if ((*i)->region()->last_frame() + 1 > end) {
5827 end = (*i)->region()->last_frame() + 1;
5831 set_loop_range (start, end, _("set loop range from region"));
5834 _session->request_locate (start, true);
5835 _session->request_play_loop (true);
5840 Editor::set_punch_from_selection ()
5842 if (_session == 0 || selection->time.empty()) {
5846 framepos_t start = selection->time[clicked_selection].start;
5847 framepos_t end = selection->time[clicked_selection].end;
5849 set_punch_range (start, end, _("set punch range from selection"));
5853 Editor::set_punch_from_edit_range ()
5855 if (_session == 0) {
5862 if (!get_edit_op_range (start, end)) {
5866 set_punch_range (start, end, _("set punch range from edit range"));
5870 Editor::set_punch_from_region ()
5872 framepos_t start = max_framepos;
5875 RegionSelection rs = get_regions_from_selection_and_entered ();
5881 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5882 if ((*i)->region()->position() < start) {
5883 start = (*i)->region()->position();
5885 if ((*i)->region()->last_frame() + 1 > end) {
5886 end = (*i)->region()->last_frame() + 1;
5890 set_punch_range (start, end, _("set punch range from region"));
5894 Editor::pitch_shift_region ()
5896 RegionSelection rs = get_regions_from_selection_and_entered ();
5898 RegionSelection audio_rs;
5899 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5900 if (dynamic_cast<AudioRegionView*> (*i)) {
5901 audio_rs.push_back (*i);
5905 if (audio_rs.empty()) {
5909 pitch_shift (audio_rs, 1.2);
5913 Editor::transpose_region ()
5915 RegionSelection rs = get_regions_from_selection_and_entered ();
5917 list<MidiRegionView*> midi_region_views;
5918 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5919 MidiRegionView* mrv = dynamic_cast<MidiRegionView*> (*i);
5921 midi_region_views.push_back (mrv);
5926 int const r = d.run ();
5927 if (r != RESPONSE_ACCEPT) {
5931 for (list<MidiRegionView*>::iterator i = midi_region_views.begin(); i != midi_region_views.end(); ++i) {
5932 (*i)->midi_region()->transpose (d.semitones ());
5937 Editor::set_tempo_from_region ()
5939 RegionSelection rs = get_regions_from_selection_and_entered ();
5941 if (!_session || rs.empty()) {
5945 RegionView* rv = rs.front();
5947 define_one_bar (rv->region()->position(), rv->region()->last_frame() + 1);
5951 Editor::use_range_as_bar ()
5953 framepos_t start, end;
5954 if (get_edit_op_range (start, end)) {
5955 define_one_bar (start, end);
5960 Editor::define_one_bar (framepos_t start, framepos_t end)
5962 framepos_t length = end - start;
5964 const Meter& m (_session->tempo_map().meter_at (start));
5966 /* length = 1 bar */
5968 /* now we want frames per beat.
5969 we have frames per bar, and beats per bar, so ...
5972 /* XXXX METER MATH */
5974 double frames_per_beat = length / m.divisions_per_bar();
5976 /* beats per minute = */
5978 double beats_per_minute = (_session->frame_rate() * 60.0) / frames_per_beat;
5980 /* now decide whether to:
5982 (a) set global tempo
5983 (b) add a new tempo marker
5987 const TempoSection& t (_session->tempo_map().tempo_section_at (start));
5989 bool do_global = false;
5991 if ((_session->tempo_map().n_tempos() == 1) && (_session->tempo_map().n_meters() == 1)) {
5993 /* only 1 tempo & 1 meter: ask if the user wants to set the tempo
5994 at the start, or create a new marker
5997 vector<string> options;
5998 options.push_back (_("Cancel"));
5999 options.push_back (_("Add new marker"));
6000 options.push_back (_("Set global tempo"));
6003 _("Define one bar"),
6004 _("Do you want to set the global tempo or add a new tempo marker?"),
6008 c.set_default_response (2);
6024 /* more than 1 tempo and/or meter section already, go ahead do the "usual":
6025 if the marker is at the region starter, change it, otherwise add
6030 begin_reversible_command (_("set tempo from region"));
6031 XMLNode& before (_session->tempo_map().get_state());
6034 _session->tempo_map().change_initial_tempo (beats_per_minute, t.note_type());
6035 } else if (t.frame() == start) {
6036 _session->tempo_map().change_existing_tempo_at (start, beats_per_minute, t.note_type());
6038 Timecode::BBT_Time bbt;
6039 _session->tempo_map().bbt_time (start, bbt);
6040 _session->tempo_map().add_tempo (Tempo (beats_per_minute, t.note_type()), bbt);
6043 XMLNode& after (_session->tempo_map().get_state());
6045 _session->add_command (new MementoCommand<TempoMap>(_session->tempo_map(), &before, &after));
6046 commit_reversible_command ();
6050 Editor::split_region_at_transients ()
6052 AnalysisFeatureList positions;
6054 RegionSelection rs = get_regions_from_selection_and_entered ();
6056 if (!_session || rs.empty()) {
6060 _session->begin_reversible_command (_("split regions"));
6062 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ) {
6064 RegionSelection::iterator tmp;
6069 boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion> ((*i)->region());
6071 if (ar && (ar->get_transients (positions) == 0)) {
6072 split_region_at_points ((*i)->region(), positions, true);
6079 _session->commit_reversible_command ();
6084 Editor::split_region_at_points (boost::shared_ptr<Region> r, AnalysisFeatureList& positions, bool can_ferret, bool select_new)
6086 bool use_rhythmic_rodent = false;
6088 boost::shared_ptr<Playlist> pl = r->playlist();
6090 list<boost::shared_ptr<Region> > new_regions;
6096 if (positions.empty()) {
6101 if (positions.size() > 20 && can_ferret) {
6102 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);
6103 MessageDialog msg (msgstr,
6106 Gtk::BUTTONS_OK_CANCEL);
6109 msg.add_button (_("Call for the Ferret!"), RESPONSE_APPLY);
6110 msg.set_secondary_text (_("Press OK to continue with this split operation\nor ask the Ferret dialog to tune the analysis"));
6112 msg.set_secondary_text (_("Press OK to continue with this split operation"));
6115 msg.set_title (_("Excessive split?"));
6118 int response = msg.run();
6124 case RESPONSE_APPLY:
6125 use_rhythmic_rodent = true;
6132 if (use_rhythmic_rodent) {
6133 show_rhythm_ferret ();
6137 AnalysisFeatureList::const_iterator x;
6139 pl->clear_changes ();
6140 pl->clear_owned_changes ();
6142 x = positions.begin();
6144 if (x == positions.end()) {
6149 pl->remove_region (r);
6153 while (x != positions.end()) {
6155 /* deal with positons that are out of scope of present region bounds */
6156 if (*x <= 0 || *x > r->length()) {
6161 /* file start = original start + how far we from the initial position ?
6164 framepos_t file_start = r->start() + pos;
6166 /* length = next position - current position
6169 framepos_t len = (*x) - pos;
6171 /* XXX we do we really want to allow even single-sample regions?
6172 shouldn't we have some kind of lower limit on region size?
6181 if (RegionFactory::region_name (new_name, r->name())) {
6185 /* do NOT announce new regions 1 by one, just wait till they are all done */
6189 plist.add (ARDOUR::Properties::start, file_start);
6190 plist.add (ARDOUR::Properties::length, len);
6191 plist.add (ARDOUR::Properties::name, new_name);
6192 plist.add (ARDOUR::Properties::layer, 0);
6194 boost::shared_ptr<Region> nr = RegionFactory::create (r->sources(), plist, false);
6195 /* because we set annouce to false, manually add the new region to the
6198 RegionFactory::map_add (nr);
6200 pl->add_region (nr, r->position() + pos);
6203 new_regions.push_front(nr);
6212 RegionFactory::region_name (new_name, r->name());
6214 /* Add the final region */
6217 plist.add (ARDOUR::Properties::start, r->start() + pos);
6218 plist.add (ARDOUR::Properties::length, r->last_frame() - (r->position() + pos) + 1);
6219 plist.add (ARDOUR::Properties::name, new_name);
6220 plist.add (ARDOUR::Properties::layer, 0);
6222 boost::shared_ptr<Region> nr = RegionFactory::create (r->sources(), plist, false);
6223 /* because we set annouce to false, manually add the new region to the
6226 RegionFactory::map_add (nr);
6227 pl->add_region (nr, r->position() + pos);
6230 new_regions.push_front(nr);
6235 /* We might have removed regions, which alters other regions' layering_index,
6236 so we need to do a recursive diff here.
6238 vector<Command*> cmds;
6240 _session->add_commands (cmds);
6242 _session->add_command (new StatefulDiffCommand (pl));
6246 for (list<boost::shared_ptr<Region> >::iterator i = new_regions.begin(); i != new_regions.end(); ++i){
6247 set_selected_regionview_from_region_list ((*i), Selection::Add);
6253 Editor::place_transient()
6259 RegionSelection rs = get_regions_from_selection_and_edit_point ();
6265 framepos_t where = get_preferred_edit_position();
6267 _session->begin_reversible_command (_("place transient"));
6269 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6270 framepos_t position = (*r)->region()->position();
6271 (*r)->region()->add_transient(where - position);
6274 _session->commit_reversible_command ();
6278 Editor::remove_transient(ArdourCanvas::Item* item)
6284 ArdourCanvas::Line* _line = reinterpret_cast<ArdourCanvas::Line*> (item);
6287 AudioRegionView* _arv = reinterpret_cast<AudioRegionView*> (item->get_data ("regionview"));
6288 _arv->remove_transient (*(float*) _line->get_data ("position"));
6292 Editor::snap_regions_to_grid ()
6294 list <boost::shared_ptr<Playlist > > used_playlists;
6296 RegionSelection rs = get_regions_from_selection_and_entered ();
6298 if (!_session || rs.empty()) {
6302 _session->begin_reversible_command (_("snap regions to grid"));
6304 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6306 boost::shared_ptr<Playlist> pl = (*r)->region()->playlist();
6308 if (!pl->frozen()) {
6309 /* we haven't seen this playlist before */
6311 /* remember used playlists so we can thaw them later */
6312 used_playlists.push_back(pl);
6316 framepos_t start_frame = (*r)->region()->first_frame ();
6317 snap_to (start_frame);
6318 (*r)->region()->set_position (start_frame);
6321 while (used_playlists.size() > 0) {
6322 list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
6324 used_playlists.pop_front();
6327 _session->commit_reversible_command ();
6331 Editor::close_region_gaps ()
6333 list <boost::shared_ptr<Playlist > > used_playlists;
6335 RegionSelection rs = get_regions_from_selection_and_entered ();
6337 if (!_session || rs.empty()) {
6341 Dialog dialog (_("Close Region Gaps"));
6344 table.set_spacings (12);
6345 table.set_border_width (12);
6346 Label* l = manage (left_aligned_label (_("Crossfade length")));
6347 table.attach (*l, 0, 1, 0, 1);
6349 SpinButton spin_crossfade (1, 0);
6350 spin_crossfade.set_range (0, 15);
6351 spin_crossfade.set_increments (1, 1);
6352 spin_crossfade.set_value (5);
6353 table.attach (spin_crossfade, 1, 2, 0, 1);
6355 table.attach (*manage (new Label (_("ms"))), 2, 3, 0, 1);
6357 l = manage (left_aligned_label (_("Pull-back length")));
6358 table.attach (*l, 0, 1, 1, 2);
6360 SpinButton spin_pullback (1, 0);
6361 spin_pullback.set_range (0, 100);
6362 spin_pullback.set_increments (1, 1);
6363 spin_pullback.set_value(30);
6364 table.attach (spin_pullback, 1, 2, 1, 2);
6366 table.attach (*manage (new Label (_("ms"))), 2, 3, 1, 2);
6368 dialog.get_vbox()->pack_start (table);
6369 dialog.add_button (Stock::CANCEL, RESPONSE_CANCEL);
6370 dialog.add_button (_("Ok"), RESPONSE_ACCEPT);
6373 if (dialog.run () == RESPONSE_CANCEL) {
6377 framepos_t crossfade_len = spin_crossfade.get_value();
6378 framepos_t pull_back_frames = spin_pullback.get_value();
6380 crossfade_len = lrintf (crossfade_len * _session->frame_rate()/1000);
6381 pull_back_frames = lrintf (pull_back_frames * _session->frame_rate()/1000);
6383 /* Iterate over the region list and make adjacent regions overlap by crossfade_len_ms */
6385 _session->begin_reversible_command (_("close region gaps"));
6388 boost::shared_ptr<Region> last_region;
6390 rs.sort_by_position_and_track();
6392 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6394 boost::shared_ptr<Playlist> pl = (*r)->region()->playlist();
6396 if (!pl->frozen()) {
6397 /* we haven't seen this playlist before */
6399 /* remember used playlists so we can thaw them later */
6400 used_playlists.push_back(pl);
6404 framepos_t position = (*r)->region()->position();
6406 if (idx == 0 || position < last_region->position()){
6407 last_region = (*r)->region();
6412 (*r)->region()->trim_front( (position - pull_back_frames));
6413 last_region->trim_end( (position - pull_back_frames + crossfade_len));
6415 last_region = (*r)->region();
6420 while (used_playlists.size() > 0) {
6421 list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
6423 used_playlists.pop_front();
6426 _session->commit_reversible_command ();
6430 Editor::tab_to_transient (bool forward)
6432 AnalysisFeatureList positions;
6434 RegionSelection rs = get_regions_from_selection_and_entered ();
6440 framepos_t pos = _session->audible_frame ();
6442 if (!selection->tracks.empty()) {
6444 /* don't waste time searching for transients in duplicate playlists.
6447 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
6449 for (TrackViewList::iterator t = ts.begin(); t != ts.end(); ++t) {
6451 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*t);
6454 boost::shared_ptr<Track> tr = rtv->track();
6456 boost::shared_ptr<Playlist> pl = tr->playlist ();
6458 framepos_t result = pl->find_next_transient (pos, forward ? 1 : -1);
6461 positions.push_back (result);
6474 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6475 (*r)->region()->get_transients (positions);
6479 TransientDetector::cleanup_transients (positions, _session->frame_rate(), 3.0);
6482 AnalysisFeatureList::iterator x;
6484 for (x = positions.begin(); x != positions.end(); ++x) {
6490 if (x != positions.end ()) {
6491 _session->request_locate (*x);
6495 AnalysisFeatureList::reverse_iterator x;
6497 for (x = positions.rbegin(); x != positions.rend(); ++x) {
6503 if (x != positions.rend ()) {
6504 _session->request_locate (*x);
6510 Editor::playhead_forward_to_grid ()
6516 framepos_t pos = playhead_cursor->current_frame ();
6517 if (pos < max_framepos - 1) {
6519 snap_to_internal (pos, RoundUpAlways, false);
6520 _session->request_locate (pos);
6526 Editor::playhead_backward_to_grid ()
6532 framepos_t pos = playhead_cursor->current_frame ();
6535 snap_to_internal (pos, RoundDownAlways, false);
6536 _session->request_locate (pos);
6541 Editor::set_track_height (Height h)
6543 TrackSelection& ts (selection->tracks);
6545 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
6546 (*x)->set_height_enum (h);
6551 Editor::toggle_tracks_active ()
6553 TrackSelection& ts (selection->tracks);
6555 bool target = false;
6561 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
6562 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*x);
6566 target = !rtv->_route->active();
6569 rtv->_route->set_active (target, this);
6575 Editor::remove_tracks ()
6577 TrackSelection& ts (selection->tracks);
6583 vector<string> choices;
6587 const char* trackstr;
6589 vector<boost::shared_ptr<Route> > routes;
6590 bool special_bus = false;
6592 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
6593 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*x);
6597 if (rtv->is_track()) {
6602 routes.push_back (rtv->_route);
6604 if (rtv->route()->is_master() || rtv->route()->is_monitor()) {
6609 if (special_bus && !Config->get_allow_special_bus_removal()) {
6610 MessageDialog msg (_("That would be bad news ...."),
6614 msg.set_secondary_text (string_compose (_(
6615 "Removing the master or monitor bus is such a bad idea\n\
6616 that %1 is not going to allow it.\n\
6618 If you really want to do this sort of thing\n\
6619 edit your ardour.rc file to set the\n\
6620 \"allow-special-bus-removal\" option to be \"yes\""), PROGRAM_NAME));
6627 if (ntracks + nbusses == 0) {
6631 // XXX should be using gettext plural forms, maybe?
6633 trackstr = _("tracks");
6635 trackstr = _("track");
6639 busstr = _("busses");
6646 prompt = string_compose (_("Do you really want to remove %1 %2 and %3 %4?\n"
6647 "(You may also lose the playlists associated with the %2)\n\n"
6648 "This action cannot be undone, and the session file will be overwritten!"),
6649 ntracks, trackstr, nbusses, busstr);
6651 prompt = string_compose (_("Do you really want to remove %1 %2?\n"
6652 "(You may also lose the playlists associated with the %2)\n\n"
6653 "This action cannot be undone, and the session file will be overwritten!"),
6656 } else if (nbusses) {
6657 prompt = string_compose (_("Do you really want to remove %1 %2?\n\n"
6658 "This action cannot be undone, and the session file will be overwritten"),
6662 choices.push_back (_("No, do nothing."));
6663 if (ntracks + nbusses > 1) {
6664 choices.push_back (_("Yes, remove them."));
6666 choices.push_back (_("Yes, remove it."));
6671 title = string_compose (_("Remove %1"), trackstr);
6673 title = string_compose (_("Remove %1"), busstr);
6676 Choice prompter (title, prompt, choices);
6678 if (prompter.run () != 1) {
6683 Session::StateProtector sp (_session);
6684 DisplaySuspender ds;
6685 for (vector<boost::shared_ptr<Route> >::iterator x = routes.begin(); x != routes.end(); ++x) {
6686 _session->remove_route (*x);
6692 Editor::do_insert_time ()
6694 if (selection->tracks.empty()) {
6698 InsertTimeDialog d (*this);
6699 int response = d.run ();
6701 if (response != RESPONSE_OK) {
6705 if (d.distance() == 0) {
6709 InsertTimeOption opt = d.intersected_region_action ();
6712 get_preferred_edit_position(),
6718 d.move_glued_markers(),
6719 d.move_locked_markers(),
6725 Editor::insert_time (
6726 framepos_t pos, framecnt_t frames, InsertTimeOption opt,
6727 bool all_playlists, bool ignore_music_glue, bool markers_too, bool glued_markers_too, bool locked_markers_too, bool tempo_too
6730 bool commit = false;
6732 if (Config->get_edit_mode() == Lock) {
6736 begin_reversible_command (_("insert time"));
6738 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
6740 for (TrackViewList::iterator x = ts.begin(); x != ts.end(); ++x) {
6744 /* don't operate on any playlist more than once, which could
6745 * happen if "all playlists" is enabled, but there is more
6746 * than 1 track using playlists "from" a given track.
6749 set<boost::shared_ptr<Playlist> > pl;
6751 if (all_playlists) {
6752 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*x);
6754 vector<boost::shared_ptr<Playlist> > all = _session->playlists->playlists_for_track (rtav->track ());
6755 for (vector<boost::shared_ptr<Playlist> >::iterator p = all.begin(); p != all.end(); ++p) {
6760 if ((*x)->playlist ()) {
6761 pl.insert ((*x)->playlist ());
6765 for (set<boost::shared_ptr<Playlist> >::iterator i = pl.begin(); i != pl.end(); ++i) {
6767 (*i)->clear_changes ();
6768 (*i)->clear_owned_changes ();
6770 if (opt == SplitIntersected) {
6774 (*i)->shift (pos, frames, (opt == MoveIntersected), ignore_music_glue);
6776 vector<Command*> cmds;
6778 _session->add_commands (cmds);
6780 _session->add_command (new StatefulDiffCommand (*i));
6785 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*x);
6787 rtav->route ()->shift (pos, frames);
6795 XMLNode& before (_session->locations()->get_state());
6796 Locations::LocationList copy (_session->locations()->list());
6798 for (Locations::LocationList::iterator i = copy.begin(); i != copy.end(); ++i) {
6800 Locations::LocationList::const_iterator tmp;
6802 bool const was_locked = (*i)->locked ();
6803 if (locked_markers_too) {
6807 if ((*i)->position_lock_style() == AudioTime || glued_markers_too) {
6809 if ((*i)->start() >= pos) {
6810 (*i)->set_start ((*i)->start() + frames);
6811 if (!(*i)->is_mark()) {
6812 (*i)->set_end ((*i)->end() + frames);
6825 XMLNode& after (_session->locations()->get_state());
6826 _session->add_command (new MementoCommand<Locations>(*_session->locations(), &before, &after));
6831 _session->tempo_map().insert_time (pos, frames);
6835 commit_reversible_command ();
6840 Editor::fit_selected_tracks ()
6842 if (!selection->tracks.empty()) {
6843 fit_tracks (selection->tracks);
6847 /* no selected tracks - use tracks with selected regions */
6849 if (!selection->regions.empty()) {
6850 for (RegionSelection::iterator r = selection->regions.begin(); r != selection->regions.end(); ++r) {
6851 tvl.push_back (&(*r)->get_time_axis_view ());
6857 } else if (internal_editing()) {
6858 /* no selected tracks, or regions, but in internal edit mode, so follow the mouse and use
6861 if (entered_track) {
6862 tvl.push_back (entered_track);
6871 Editor::fit_tracks (TrackViewList & tracks)
6873 if (tracks.empty()) {
6877 uint32_t child_heights = 0;
6878 int visible_tracks = 0;
6880 for (TrackSelection::iterator t = tracks.begin(); t != tracks.end(); ++t) {
6882 if (!(*t)->marked_for_display()) {
6886 child_heights += (*t)->effective_height() - (*t)->current_height();
6890 /* compute the per-track height from:
6892 total canvas visible height -
6893 height that will be taken by visible children of selected
6894 tracks - height of the ruler/hscroll area
6896 uint32_t h = (uint32_t) floor ((trackviews_height() - child_heights) / visible_tracks);
6897 double first_y_pos = DBL_MAX;
6899 if (h < TimeAxisView::preset_height (HeightSmall)) {
6900 MessageDialog msg (*this, _("There are too many tracks to fit in the current window"));
6901 /* too small to be displayed */
6905 undo_visual_stack.push_back (current_visual_state (true));
6906 no_save_visual = true;
6908 /* build a list of all tracks, including children */
6911 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
6913 TimeAxisView::Children c = (*i)->get_child_list ();
6914 for (TimeAxisView::Children::iterator j = c.begin(); j != c.end(); ++j) {
6915 all.push_back (j->get());
6919 bool prev_was_selected = false;
6920 bool is_selected = tracks.contains (all.front());
6921 bool next_is_selected;
6923 for (TrackViewList::iterator t = all.begin(); t != all.end(); ++t) {
6925 TrackViewList::iterator next;
6930 if (next != all.end()) {
6931 next_is_selected = tracks.contains (*next);
6933 next_is_selected = false;
6936 if ((*t)->marked_for_display ()) {
6938 (*t)->set_height (h);
6939 first_y_pos = std::min ((*t)->y_position (), first_y_pos);
6941 if (prev_was_selected && next_is_selected) {
6942 hide_track_in_display (*t);
6947 prev_was_selected = is_selected;
6948 is_selected = next_is_selected;
6952 set the controls_layout height now, because waiting for its size
6953 request signal handler will cause the vertical adjustment setting to fail
6956 controls_layout.property_height () = _full_canvas_height;
6957 vertical_adjustment.set_value (first_y_pos);
6959 redo_visual_stack.push_back (current_visual_state (true));
6961 visible_tracks_selector.set_text (_("Sel"));
6965 Editor::save_visual_state (uint32_t n)
6967 while (visual_states.size() <= n) {
6968 visual_states.push_back (0);
6971 if (visual_states[n] != 0) {
6972 delete visual_states[n];
6975 visual_states[n] = current_visual_state (true);
6980 Editor::goto_visual_state (uint32_t n)
6982 if (visual_states.size() <= n) {
6986 if (visual_states[n] == 0) {
6990 use_visual_state (*visual_states[n]);
6994 Editor::start_visual_state_op (uint32_t n)
6996 save_visual_state (n);
6998 PopUp* pup = new PopUp (WIN_POS_MOUSE, 1000, true);
7000 snprintf (buf, sizeof (buf), _("Saved view %u"), n+1);
7001 pup->set_text (buf);
7006 Editor::cancel_visual_state_op (uint32_t n)
7008 goto_visual_state (n);
7012 Editor::toggle_region_mute ()
7014 if (_ignore_region_action) {
7018 RegionSelection rs = get_regions_from_selection_and_entered ();
7024 if (rs.size() > 1) {
7025 begin_reversible_command (_("mute regions"));
7027 begin_reversible_command (_("mute region"));
7030 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
7032 (*i)->region()->playlist()->clear_changes ();
7033 (*i)->region()->set_muted (!(*i)->region()->muted ());
7034 _session->add_command (new StatefulDiffCommand ((*i)->region()->playlist()));
7038 commit_reversible_command ();
7042 Editor::combine_regions ()
7044 /* foreach track with selected regions, take all selected regions
7045 and join them into a new region containing the subregions (as a
7049 typedef set<RouteTimeAxisView*> RTVS;
7052 if (selection->regions.empty()) {
7056 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
7057 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(&(*i)->get_time_axis_view());
7060 tracks.insert (rtv);
7064 begin_reversible_command (_("combine regions"));
7066 vector<RegionView*> new_selection;
7068 for (RTVS::iterator i = tracks.begin(); i != tracks.end(); ++i) {
7071 if ((rv = (*i)->combine_regions ()) != 0) {
7072 new_selection.push_back (rv);
7076 selection->clear_regions ();
7077 for (vector<RegionView*>::iterator i = new_selection.begin(); i != new_selection.end(); ++i) {
7078 selection->add (*i);
7081 commit_reversible_command ();
7085 Editor::uncombine_regions ()
7087 typedef set<RouteTimeAxisView*> RTVS;
7090 if (selection->regions.empty()) {
7094 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
7095 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(&(*i)->get_time_axis_view());
7098 tracks.insert (rtv);
7102 begin_reversible_command (_("uncombine regions"));
7104 for (RTVS::iterator i = tracks.begin(); i != tracks.end(); ++i) {
7105 (*i)->uncombine_regions ();
7108 commit_reversible_command ();
7112 Editor::toggle_midi_input_active (bool flip_others)
7115 boost::shared_ptr<RouteList> rl (new RouteList);
7117 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
7118 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
7124 boost::shared_ptr<MidiTrack> mt = rtav->midi_track();
7127 rl->push_back (rtav->route());
7128 onoff = !mt->input_active();
7132 _session->set_exclusive_input_active (rl, onoff, flip_others);
7139 lock_dialog = new Gtk::Dialog (string_compose (_("%1: Locked"), PROGRAM_NAME), true);
7141 Gtk::Image* padlock = manage (new Gtk::Image (ARDOUR_UI_UTILS::get_icon ("padlock_closed")));
7142 lock_dialog->get_vbox()->pack_start (*padlock);
7144 ArdourButton* b = manage (new ArdourButton);
7145 b->set_name ("lock button");
7146 b->set_text (_("Click to unlock"));
7147 b->signal_clicked.connect (sigc::mem_fun (*this, &Editor::unlock));
7148 lock_dialog->get_vbox()->pack_start (*b);
7150 lock_dialog->get_vbox()->show_all ();
7151 lock_dialog->set_size_request (200, 200);
7155 /* The global menu bar continues to be accessible to applications
7156 with modal dialogs, which means that we need to desensitize
7157 all items in the menu bar. Since those items are really just
7158 proxies for actions, that means disabling all actions.
7160 ActionManager::disable_all_actions ();
7162 lock_dialog->present ();
7168 lock_dialog->hide ();
7171 ActionManager::pop_action_state ();
7174 if (ARDOUR_UI::config()->get_lock_gui_after_seconds()) {
7175 start_lock_event_timing ();
7180 Editor::bring_in_callback (Gtk::Label* label, uint32_t n, uint32_t total, string name)
7182 Gtkmm2ext::UI::instance()->call_slot (invalidator (*this), boost::bind (&Editor::update_bring_in_message, this, label, n, total, name));
7186 Editor::update_bring_in_message (Gtk::Label* label, uint32_t n, uint32_t total, string name)
7188 label->set_text (string_compose ("Copying %1, %2 of %3", name, n, total));
7189 Gtkmm2ext::UI::instance()->flush_pending ();
7193 Editor::bring_all_sources_into_session ()
7200 ArdourDialog w (_("Moving embedded files into session folder"));
7201 w.get_vbox()->pack_start (msg);
7204 /* flush all pending GUI events because we're about to start copying
7208 Gtkmm2ext::UI::instance()->flush_pending ();
7212 _session->bring_all_sources_into_session (boost::bind (&Editor::bring_in_callback, this, &msg, _1, _2, _3));