2 Copyright (C) 2000-2004 Paul Davis
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 /* Note: public Editor methods are documented in public_editor.h */
30 #include "pbd/error.h"
31 #include "pbd/basename.h"
32 #include "pbd/pthread_utils.h"
33 #include "pbd/memento_command.h"
34 #include "pbd/unwind.h"
35 #include "pbd/whitespace.h"
36 #include "pbd/stateful_diff_command.h"
38 #include <gtkmm2ext/utils.h>
39 #include <gtkmm2ext/choice.h>
40 #include <gtkmm2ext/popup.h>
42 #include "ardour/audio_track.h"
43 #include "ardour/audioregion.h"
44 #include "ardour/dB.h"
45 #include "ardour/location.h"
46 #include "ardour/midi_region.h"
47 #include "ardour/operations.h"
48 #include "ardour/playlist_factory.h"
49 #include "ardour/quantize.h"
50 #include "ardour/region_factory.h"
51 #include "ardour/reverse.h"
52 #include "ardour/route_group.h"
53 #include "ardour/session.h"
54 #include "ardour/session_playlists.h"
55 #include "ardour/strip_silence.h"
56 #include "ardour/transient_detector.h"
57 #include "ardour/utils.h"
59 #include "ardour_ui.h"
62 #include "time_axis_view.h"
63 #include "route_time_axis.h"
64 #include "audio_time_axis.h"
65 #include "automation_time_axis.h"
66 #include "streamview.h"
67 #include "audio_streamview.h"
68 #include "audio_region_view.h"
69 #include "midi_region_view.h"
70 #include "rgb_macros.h"
71 #include "selection_templates.h"
72 #include "selection.h"
74 #include "gtk-custom-hruler.h"
75 #include "gui_thread.h"
78 #include "editor_drag.h"
79 #include "strip_silence_dialog.h"
80 #include "editor_routes.h"
81 #include "editor_regions.h"
82 #include "quantize_dialog.h"
83 #include "interthread_progress_window.h"
84 #include "insert_time_dialog.h"
85 #include "normalize_dialog.h"
86 #include "editor_cursors.h"
87 #include "mouse_cursors.h"
88 #include "patch_change_dialog.h"
89 #include "transpose_dialog.h"
94 using namespace ARDOUR;
97 using namespace Gtkmm2ext;
98 using namespace Editing;
99 using Gtkmm2ext::Keyboard;
101 /***********************************************************************
103 ***********************************************************************/
106 Editor::undo (uint32_t n)
108 if (_drags->active ()) {
118 Editor::redo (uint32_t n)
120 if (_drags->active ()) {
130 Editor::split_regions_at (framepos_t where, RegionSelection& regions)
134 list <boost::shared_ptr<Playlist > > used_playlists;
136 if (regions.empty()) {
140 begin_reversible_command (_("split"));
142 // if splitting a single region, and snap-to is using
143 // region boundaries, don't pay attention to them
145 if (regions.size() == 1) {
146 switch (_snap_type) {
147 case SnapToRegionStart:
148 case SnapToRegionSync:
149 case SnapToRegionEnd:
158 EditorFreeze(); /* Emit Signal */
161 for (RegionSelection::iterator a = regions.begin(); a != regions.end(); ) {
163 RegionSelection::iterator tmp;
165 /* XXX this test needs to be more complicated, to make sure we really
166 have something to split.
169 if (!(*a)->region()->covers (where)) {
177 boost::shared_ptr<Playlist> pl = (*a)->region()->playlist();
185 /* we haven't seen this playlist before */
187 /* remember used playlists so we can thaw them later */
188 used_playlists.push_back(pl);
193 pl->clear_changes ();
194 pl->split_region ((*a)->region(), where);
195 _session->add_command (new StatefulDiffCommand (pl));
201 while (used_playlists.size() > 0) {
202 list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
204 used_playlists.pop_front();
207 commit_reversible_command ();
210 EditorThaw(); /* Emit Signal */
214 /** Move one extreme of the current range selection. If more than one range is selected,
215 * the start of the earliest range or the end of the latest range is moved.
217 * @param move_end true to move the end of the current range selection, false to move
219 * @param next true to move the extreme to the next region boundary, false to move to
223 Editor::move_range_selection_start_or_end_to_region_boundary (bool move_end, bool next)
225 if (selection->time.start() == selection->time.end_frame()) {
229 framepos_t start = selection->time.start ();
230 framepos_t end = selection->time.end_frame ();
232 /* the position of the thing we may move */
233 framepos_t pos = move_end ? end : start;
234 int dir = next ? 1 : -1;
236 /* so we don't find the current region again */
237 if (dir > 0 || pos > 0) {
241 framepos_t const target = get_region_boundary (pos, dir, true, false);
256 begin_reversible_command (_("alter selection"));
257 selection->set_preserving_all_ranges (start, end);
258 commit_reversible_command ();
262 Editor::nudge_forward_release (GdkEventButton* ev)
264 if (ev->state & Keyboard::PrimaryModifier) {
265 nudge_forward (false, true);
267 nudge_forward (false, false);
273 Editor::nudge_backward_release (GdkEventButton* ev)
275 if (ev->state & Keyboard::PrimaryModifier) {
276 nudge_backward (false, true);
278 nudge_backward (false, false);
285 Editor::nudge_forward (bool next, bool force_playhead)
288 framepos_t next_distance;
294 RegionSelection rs = get_regions_from_selection_and_entered ();
296 if (!force_playhead && !rs.empty()) {
298 begin_reversible_command (_("nudge regions forward"));
300 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
301 boost::shared_ptr<Region> r ((*i)->region());
303 distance = get_nudge_distance (r->position(), next_distance);
306 distance = next_distance;
310 r->set_position (r->position() + distance);
311 _session->add_command (new StatefulDiffCommand (r));
314 commit_reversible_command ();
317 } else if (!force_playhead && !selection->markers.empty()) {
321 begin_reversible_command (_("nudge location forward"));
323 for (MarkerSelection::iterator i = selection->markers.begin(); i != selection->markers.end(); ++i) {
325 Location* loc = find_location_from_marker ((*i), is_start);
329 XMLNode& before (loc->get_state());
332 distance = get_nudge_distance (loc->start(), next_distance);
334 distance = next_distance;
336 if (max_framepos - distance > loc->start() + loc->length()) {
337 loc->set_start (loc->start() + distance);
339 loc->set_start (max_framepos - loc->length());
342 distance = get_nudge_distance (loc->end(), next_distance);
344 distance = next_distance;
346 if (max_framepos - distance > loc->end()) {
347 loc->set_end (loc->end() + distance);
349 loc->set_end (max_framepos);
352 XMLNode& after (loc->get_state());
353 _session->add_command (new MementoCommand<Location>(*loc, &before, &after));
357 commit_reversible_command ();
360 distance = get_nudge_distance (playhead_cursor->current_frame, next_distance);
361 _session->request_locate (playhead_cursor->current_frame + distance);
366 Editor::nudge_backward (bool next, bool force_playhead)
369 framepos_t next_distance;
375 RegionSelection rs = get_regions_from_selection_and_entered ();
377 if (!force_playhead && !rs.empty()) {
379 begin_reversible_command (_("nudge regions backward"));
381 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
382 boost::shared_ptr<Region> r ((*i)->region());
384 distance = get_nudge_distance (r->position(), next_distance);
387 distance = next_distance;
392 if (r->position() > distance) {
393 r->set_position (r->position() - distance);
397 _session->add_command (new StatefulDiffCommand (r));
400 commit_reversible_command ();
402 } else if (!force_playhead && !selection->markers.empty()) {
406 begin_reversible_command (_("nudge location forward"));
408 for (MarkerSelection::iterator i = selection->markers.begin(); i != selection->markers.end(); ++i) {
410 Location* loc = find_location_from_marker ((*i), is_start);
414 XMLNode& before (loc->get_state());
417 distance = get_nudge_distance (loc->start(), next_distance);
419 distance = next_distance;
421 if (distance < loc->start()) {
422 loc->set_start (loc->start() - distance);
427 distance = get_nudge_distance (loc->end(), next_distance);
430 distance = next_distance;
433 if (distance < loc->end() - loc->length()) {
434 loc->set_end (loc->end() - distance);
436 loc->set_end (loc->length());
440 XMLNode& after (loc->get_state());
441 _session->add_command (new MementoCommand<Location>(*loc, &before, &after));
445 commit_reversible_command ();
449 distance = get_nudge_distance (playhead_cursor->current_frame, next_distance);
451 if (playhead_cursor->current_frame > distance) {
452 _session->request_locate (playhead_cursor->current_frame - distance);
454 _session->goto_start();
460 Editor::nudge_forward_capture_offset ()
462 RegionSelection rs = get_regions_from_selection_and_entered ();
464 if (!_session || rs.empty()) {
468 begin_reversible_command (_("nudge forward"));
470 framepos_t const distance = _session->worst_output_latency();
472 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
473 boost::shared_ptr<Region> r ((*i)->region());
476 r->set_position (r->position() + distance);
477 _session->add_command(new StatefulDiffCommand (r));
480 commit_reversible_command ();
484 Editor::nudge_backward_capture_offset ()
486 RegionSelection rs = get_regions_from_selection_and_entered ();
488 if (!_session || rs.empty()) {
492 begin_reversible_command (_("nudge backward"));
494 framepos_t const distance = _session->worst_output_latency();
496 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
497 boost::shared_ptr<Region> r ((*i)->region());
501 if (r->position() > distance) {
502 r->set_position (r->position() - distance);
506 _session->add_command(new StatefulDiffCommand (r));
509 commit_reversible_command ();
515 Editor::move_to_start ()
517 _session->goto_start ();
521 Editor::move_to_end ()
524 _session->request_locate (_session->current_end_frame());
528 Editor::build_region_boundary_cache ()
531 vector<RegionPoint> interesting_points;
532 boost::shared_ptr<Region> r;
533 TrackViewList tracks;
536 region_boundary_cache.clear ();
542 switch (_snap_type) {
543 case SnapToRegionStart:
544 interesting_points.push_back (Start);
546 case SnapToRegionEnd:
547 interesting_points.push_back (End);
549 case SnapToRegionSync:
550 interesting_points.push_back (SyncPoint);
552 case SnapToRegionBoundary:
553 interesting_points.push_back (Start);
554 interesting_points.push_back (End);
557 fatal << string_compose (_("build_region_boundary_cache called with snap_type = %1"), _snap_type) << endmsg;
562 TimeAxisView *ontrack = 0;
565 if (!selection->tracks.empty()) {
566 tlist = selection->tracks.filter_to_unique_playlists ();
568 tlist = track_views.filter_to_unique_playlists ();
571 while (pos < _session->current_end_frame() && !at_end) {
574 framepos_t lpos = max_framepos;
576 for (vector<RegionPoint>::iterator p = interesting_points.begin(); p != interesting_points.end(); ++p) {
578 if ((r = find_next_region (pos, *p, 1, tlist, &ontrack)) == 0) {
579 if (*p == interesting_points.back()) {
582 /* move to next point type */
588 rpos = r->first_frame();
592 rpos = r->last_frame();
596 rpos = r->sync_position ();
604 RouteTimeAxisView *rtav;
606 if (ontrack != 0 && (rtav = dynamic_cast<RouteTimeAxisView*>(ontrack)) != 0 ) {
607 if (rtav->track() != 0) {
608 speed = rtav->track()->speed();
612 rpos = track_frame_to_session_frame (rpos, speed);
618 /* prevent duplicates, but we don't use set<> because we want to be able
622 vector<framepos_t>::iterator ri;
624 for (ri = region_boundary_cache.begin(); ri != region_boundary_cache.end(); ++ri) {
630 if (ri == region_boundary_cache.end()) {
631 region_boundary_cache.push_back (rpos);
638 /* finally sort to be sure that the order is correct */
640 sort (region_boundary_cache.begin(), region_boundary_cache.end());
643 boost::shared_ptr<Region>
644 Editor::find_next_region (framepos_t frame, RegionPoint point, int32_t dir, TrackViewList& tracks, TimeAxisView **ontrack)
646 TrackViewList::iterator i;
647 framepos_t closest = max_framepos;
648 boost::shared_ptr<Region> ret;
652 framepos_t track_frame;
653 RouteTimeAxisView *rtav;
655 for (i = tracks.begin(); i != tracks.end(); ++i) {
658 boost::shared_ptr<Region> r;
661 if ( (rtav = dynamic_cast<RouteTimeAxisView*>(*i)) != 0 ) {
662 if (rtav->track()!=0)
663 track_speed = rtav->track()->speed();
666 track_frame = session_frame_to_track_frame(frame, track_speed);
668 if ((r = (*i)->find_next_region (track_frame, point, dir)) == 0) {
674 rpos = r->first_frame ();
678 rpos = r->last_frame ();
682 rpos = r->sync_position ();
686 // rpos is a "track frame", converting it to "_session frame"
687 rpos = track_frame_to_session_frame(rpos, track_speed);
690 distance = rpos - frame;
692 distance = frame - rpos;
695 if (distance < closest) {
707 Editor::find_next_region_boundary (framepos_t pos, int32_t dir, const TrackViewList& tracks)
709 framecnt_t distance = max_framepos;
710 framepos_t current_nearest = -1;
712 for (TrackViewList::const_iterator i = tracks.begin(); i != tracks.end(); ++i) {
713 framepos_t contender;
716 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*i);
722 if ((contender = rtv->find_next_region_boundary (pos, dir)) < 0) {
726 d = ::llabs (pos - contender);
729 current_nearest = contender;
734 return current_nearest;
738 Editor::get_region_boundary (framepos_t pos, int32_t dir, bool with_selection, bool only_onscreen)
743 if (with_selection && Config->get_region_boundaries_from_selected_tracks()) {
745 if (!selection->tracks.empty()) {
747 target = find_next_region_boundary (pos, dir, selection->tracks);
751 if (only_onscreen || Config->get_region_boundaries_from_onscreen_tracks()) {
752 get_onscreen_tracks (tvl);
753 target = find_next_region_boundary (pos, dir, tvl);
755 target = find_next_region_boundary (pos, dir, track_views);
761 if (only_onscreen || Config->get_region_boundaries_from_onscreen_tracks()) {
762 get_onscreen_tracks (tvl);
763 target = find_next_region_boundary (pos, dir, tvl);
765 target = find_next_region_boundary (pos, dir, track_views);
773 Editor::cursor_to_region_boundary (bool with_selection, int32_t dir)
775 framepos_t pos = playhead_cursor->current_frame;
782 // so we don't find the current region again..
783 if (dir > 0 || pos > 0) {
787 if ((target = get_region_boundary (pos, dir, with_selection, false)) < 0) {
791 _session->request_locate (target);
795 Editor::cursor_to_next_region_boundary (bool with_selection)
797 cursor_to_region_boundary (with_selection, 1);
801 Editor::cursor_to_previous_region_boundary (bool with_selection)
803 cursor_to_region_boundary (with_selection, -1);
807 Editor::cursor_to_region_point (EditorCursor* cursor, RegionPoint point, int32_t dir)
809 boost::shared_ptr<Region> r;
810 framepos_t pos = cursor->current_frame;
816 TimeAxisView *ontrack = 0;
818 // so we don't find the current region again..
822 if (!selection->tracks.empty()) {
824 r = find_next_region (pos, point, dir, selection->tracks, &ontrack);
826 } else if (clicked_axisview) {
829 t.push_back (clicked_axisview);
831 r = find_next_region (pos, point, dir, t, &ontrack);
835 r = find_next_region (pos, point, dir, track_views, &ontrack);
844 pos = r->first_frame ();
848 pos = r->last_frame ();
852 pos = r->sync_position ();
857 RouteTimeAxisView *rtav;
859 if ( ontrack != 0 && (rtav = dynamic_cast<RouteTimeAxisView*>(ontrack)) != 0 ) {
860 if (rtav->track() != 0) {
861 speed = rtav->track()->speed();
865 pos = track_frame_to_session_frame(pos, speed);
867 if (cursor == playhead_cursor) {
868 _session->request_locate (pos);
870 cursor->set_position (pos);
875 Editor::cursor_to_next_region_point (EditorCursor* cursor, RegionPoint point)
877 cursor_to_region_point (cursor, point, 1);
881 Editor::cursor_to_previous_region_point (EditorCursor* cursor, RegionPoint point)
883 cursor_to_region_point (cursor, point, -1);
887 Editor::cursor_to_selection_start (EditorCursor *cursor)
891 switch (mouse_mode) {
893 if (!selection->regions.empty()) {
894 pos = selection->regions.start();
899 if (!selection->time.empty()) {
900 pos = selection->time.start ();
908 if (cursor == playhead_cursor) {
909 _session->request_locate (pos);
911 cursor->set_position (pos);
916 Editor::cursor_to_selection_end (EditorCursor *cursor)
920 switch (mouse_mode) {
922 if (!selection->regions.empty()) {
923 pos = selection->regions.end_frame();
928 if (!selection->time.empty()) {
929 pos = selection->time.end_frame ();
937 if (cursor == playhead_cursor) {
938 _session->request_locate (pos);
940 cursor->set_position (pos);
945 Editor::selected_marker_to_region_boundary (bool with_selection, int32_t dir)
955 if (selection->markers.empty()) {
959 if (!mouse_frame (mouse, ignored)) {
963 add_location_mark (mouse);
966 if ((loc = find_location_from_marker (selection->markers.front(), ignored)) == 0) {
970 framepos_t pos = loc->start();
972 // so we don't find the current region again..
973 if (dir > 0 || pos > 0) {
977 if ((target = get_region_boundary (pos, dir, with_selection, false)) < 0) {
981 loc->move_to (target);
985 Editor::selected_marker_to_next_region_boundary (bool with_selection)
987 selected_marker_to_region_boundary (with_selection, 1);
991 Editor::selected_marker_to_previous_region_boundary (bool with_selection)
993 selected_marker_to_region_boundary (with_selection, -1);
997 Editor::selected_marker_to_region_point (RegionPoint point, int32_t dir)
999 boost::shared_ptr<Region> r;
1004 if (!_session || selection->markers.empty()) {
1008 if ((loc = find_location_from_marker (selection->markers.front(), ignored)) == 0) {
1012 TimeAxisView *ontrack = 0;
1016 // so we don't find the current region again..
1020 if (!selection->tracks.empty()) {
1022 r = find_next_region (pos, point, dir, selection->tracks, &ontrack);
1026 r = find_next_region (pos, point, dir, track_views, &ontrack);
1035 pos = r->first_frame ();
1039 pos = r->last_frame ();
1043 pos = r->adjust_to_sync (r->first_frame());
1048 RouteTimeAxisView *rtav;
1050 if (ontrack != 0 && (rtav = dynamic_cast<RouteTimeAxisView*>(ontrack)) != 0) {
1051 if (rtav->track() != 0) {
1052 speed = rtav->track()->speed();
1056 pos = track_frame_to_session_frame(pos, speed);
1062 Editor::selected_marker_to_next_region_point (RegionPoint point)
1064 selected_marker_to_region_point (point, 1);
1068 Editor::selected_marker_to_previous_region_point (RegionPoint point)
1070 selected_marker_to_region_point (point, -1);
1074 Editor::selected_marker_to_selection_start ()
1080 if (!_session || selection->markers.empty()) {
1084 if ((loc = find_location_from_marker (selection->markers.front(), ignored)) == 0) {
1088 switch (mouse_mode) {
1090 if (!selection->regions.empty()) {
1091 pos = selection->regions.start();
1096 if (!selection->time.empty()) {
1097 pos = selection->time.start ();
1109 Editor::selected_marker_to_selection_end ()
1115 if (!_session || selection->markers.empty()) {
1119 if ((loc = find_location_from_marker (selection->markers.front(), ignored)) == 0) {
1123 switch (mouse_mode) {
1125 if (!selection->regions.empty()) {
1126 pos = selection->regions.end_frame();
1131 if (!selection->time.empty()) {
1132 pos = selection->time.end_frame ();
1144 Editor::scroll_playhead (bool forward)
1146 framepos_t pos = playhead_cursor->current_frame;
1147 framecnt_t delta = (framecnt_t) floor (current_page_frames() / 0.8);
1150 if (pos == max_framepos) {
1154 if (pos < max_framepos - delta) {
1173 _session->request_locate (pos);
1177 Editor::cursor_align (bool playhead_to_edit)
1183 if (playhead_to_edit) {
1185 if (selection->markers.empty()) {
1189 _session->request_locate (selection->markers.front()->position(), _session->transport_rolling());
1192 /* move selected markers to playhead */
1194 for (MarkerSelection::iterator i = selection->markers.begin(); i != selection->markers.end(); ++i) {
1197 Location* loc = find_location_from_marker (*i, ignored);
1199 if (loc->is_mark()) {
1200 loc->set_start (playhead_cursor->current_frame);
1202 loc->set (playhead_cursor->current_frame,
1203 playhead_cursor->current_frame + loc->length());
1210 Editor::scroll_backward (float pages)
1212 framepos_t const one_page = (framepos_t) rint (_canvas_width * frames_per_unit);
1213 framepos_t const cnt = (framepos_t) floor (pages * one_page);
1216 if (leftmost_frame < cnt) {
1219 frame = leftmost_frame - cnt;
1222 reset_x_origin (frame);
1226 Editor::scroll_forward (float pages)
1228 framepos_t const one_page = (framepos_t) rint (_canvas_width * frames_per_unit);
1229 framepos_t const cnt = (framepos_t) floor (pages * one_page);
1232 if (max_framepos - cnt < leftmost_frame) {
1233 frame = max_framepos - cnt;
1235 frame = leftmost_frame + cnt;
1238 reset_x_origin (frame);
1242 Editor::scroll_tracks_down ()
1244 double vert_value = vertical_adjustment.get_value() + vertical_adjustment.get_page_size();
1245 if (vert_value > vertical_adjustment.get_upper() - _canvas_height) {
1246 vert_value = vertical_adjustment.get_upper() - _canvas_height;
1249 vertical_adjustment.set_value (vert_value);
1253 Editor::scroll_tracks_up ()
1255 vertical_adjustment.set_value (vertical_adjustment.get_value() - vertical_adjustment.get_page_size());
1259 Editor::scroll_tracks_down_line ()
1261 double vert_value = vertical_adjustment.get_value() + 60;
1263 if (vert_value > vertical_adjustment.get_upper() - _canvas_height) {
1264 vert_value = vertical_adjustment.get_upper() - _canvas_height;
1267 vertical_adjustment.set_value (vert_value);
1271 Editor::scroll_tracks_up_line ()
1273 reset_y_origin (vertical_adjustment.get_value() - 60);
1279 Editor::tav_zoom_step (bool coarser)
1281 ENSURE_GUI_THREAD (*this, &Editor::temporal_zoom_step, coarser)
1283 _routes->suspend_redisplay ();
1285 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1286 TimeAxisView *tv = (static_cast<TimeAxisView*>(*i));
1287 tv->step_height (coarser);
1290 _routes->resume_redisplay ();
1294 Editor::temporal_zoom_step (bool coarser)
1296 ENSURE_GUI_THREAD (*this, &Editor::temporal_zoom_step, coarser)
1300 nfpu = frames_per_unit;
1305 nfpu = max(1.0,(nfpu/1.61803399));
1308 temporal_zoom (nfpu);
1312 Editor::temporal_zoom (gdouble fpu)
1314 if (!_session) return;
1316 framepos_t current_page = current_page_frames();
1317 framepos_t current_leftmost = leftmost_frame;
1318 framepos_t current_rightmost;
1319 framepos_t current_center;
1320 framepos_t new_page_size;
1321 framepos_t half_page_size;
1322 framepos_t leftmost_after_zoom = 0;
1324 bool in_track_canvas;
1328 /* XXX this limit is also in ::set_frames_per_unit() */
1330 if (frames_per_unit <= 1.0 && fpu <= frames_per_unit) {
1336 new_page_size = (framepos_t) floor (_canvas_width * nfpu);
1337 half_page_size = new_page_size / 2;
1339 switch (zoom_focus) {
1341 leftmost_after_zoom = current_leftmost;
1344 case ZoomFocusRight:
1345 current_rightmost = leftmost_frame + current_page;
1346 if (current_rightmost < new_page_size) {
1347 leftmost_after_zoom = 0;
1349 leftmost_after_zoom = current_rightmost - new_page_size;
1353 case ZoomFocusCenter:
1354 current_center = current_leftmost + (current_page/2);
1355 if (current_center < half_page_size) {
1356 leftmost_after_zoom = 0;
1358 leftmost_after_zoom = current_center - half_page_size;
1362 case ZoomFocusPlayhead:
1363 /* centre playhead */
1364 l = playhead_cursor->current_frame - (new_page_size * 0.5);
1367 leftmost_after_zoom = 0;
1368 } else if (l > max_framepos) {
1369 leftmost_after_zoom = max_framepos - new_page_size;
1371 leftmost_after_zoom = (framepos_t) l;
1375 case ZoomFocusMouse:
1376 /* try to keep the mouse over the same point in the display */
1378 if (!mouse_frame (where, in_track_canvas)) {
1379 /* use playhead instead */
1380 where = playhead_cursor->current_frame;
1382 if (where < half_page_size) {
1383 leftmost_after_zoom = 0;
1385 leftmost_after_zoom = where - half_page_size;
1390 l = - ((new_page_size * ((where - current_leftmost)/(double)current_page)) - where);
1393 leftmost_after_zoom = 0;
1394 } else if (l > max_framepos) {
1395 leftmost_after_zoom = max_framepos - new_page_size;
1397 leftmost_after_zoom = (framepos_t) l;
1404 /* try to keep the edit point in the same place */
1405 where = get_preferred_edit_position ();
1409 double l = - ((new_page_size * ((where - current_leftmost)/(double)current_page)) - where);
1412 leftmost_after_zoom = 0;
1413 } else if (l > max_framepos) {
1414 leftmost_after_zoom = max_framepos - new_page_size;
1416 leftmost_after_zoom = (framepos_t) l;
1420 /* edit point not defined */
1427 // leftmost_after_zoom = min (leftmost_after_zoom, _session->current_end_frame());
1429 reposition_and_zoom (leftmost_after_zoom, nfpu);
1433 Editor::temporal_zoom_region (bool both_axes)
1435 framepos_t start = max_framepos;
1437 set<TimeAxisView*> tracks;
1439 RegionSelection rs = get_regions_from_selection_and_entered ();
1445 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
1447 if ((*i)->region()->position() < start) {
1448 start = (*i)->region()->position();
1451 if ((*i)->region()->last_frame() + 1 > end) {
1452 end = (*i)->region()->last_frame() + 1;
1455 tracks.insert (&((*i)->get_time_axis_view()));
1458 /* now comes an "interesting" hack ... make sure we leave a little space
1459 at each end of the editor so that the zoom doesn't fit the region
1460 precisely to the screen.
1463 GdkScreen* screen = gdk_screen_get_default ();
1464 gint pixwidth = gdk_screen_get_width (screen);
1465 gint mmwidth = gdk_screen_get_width_mm (screen);
1466 double pix_per_mm = (double) pixwidth/ (double) mmwidth;
1467 double one_centimeter_in_pixels = pix_per_mm * 10.0;
1469 if ((start == 0 && end == 0) || end < start) {
1473 framepos_t range = end - start;
1474 double new_fpu = (double)range / (double)_canvas_width;
1475 framepos_t extra_samples = (framepos_t) floor (one_centimeter_in_pixels * new_fpu);
1477 if (start > extra_samples) {
1478 start -= extra_samples;
1483 if (max_framepos - extra_samples > end) {
1484 end += extra_samples;
1489 /* if we're zooming on both axes we need to save track heights etc.
1492 undo_visual_stack.push_back (current_visual_state (both_axes));
1494 PBD::Unwinder<bool> nsv (no_save_visual, true);
1496 temporal_zoom_by_frame (start, end);
1499 uint32_t per_track_height = (uint32_t) floor ((_canvas_height - canvas_timebars_vsize - 10.0) / tracks.size());
1501 /* set visible track heights appropriately */
1503 for (set<TimeAxisView*>::iterator t = tracks.begin(); t != tracks.end(); ++t) {
1504 (*t)->set_height (per_track_height);
1507 /* hide irrelevant tracks */
1509 _routes->suspend_redisplay ();
1511 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1512 if (find (tracks.begin(), tracks.end(), (*i)) == tracks.end()) {
1513 hide_track_in_display (*i);
1517 _routes->resume_redisplay ();
1519 vertical_adjustment.set_value (0.0);
1522 redo_visual_stack.push_back (current_visual_state (both_axes));
1526 Editor::zoom_to_region (bool both_axes)
1528 temporal_zoom_region (both_axes);
1532 Editor::temporal_zoom_selection ()
1534 if (!selection) return;
1536 if (selection->time.empty()) {
1540 framepos_t start = selection->time[clicked_selection].start;
1541 framepos_t end = selection->time[clicked_selection].end;
1543 temporal_zoom_by_frame (start, end);
1547 Editor::temporal_zoom_session ()
1549 ENSURE_GUI_THREAD (*this, &Editor::temporal_zoom_session)
1552 framecnt_t const l = _session->current_end_frame() - _session->current_start_frame();
1553 double s = _session->current_start_frame() - l * 0.01;
1557 framecnt_t const e = _session->current_end_frame() + l * 0.01;
1558 temporal_zoom_by_frame (framecnt_t (s), e);
1563 Editor::temporal_zoom_by_frame (framepos_t start, framepos_t end)
1565 if (!_session) return;
1567 if ((start == 0 && end == 0) || end < start) {
1571 framepos_t range = end - start;
1573 double new_fpu = (double)range / (double)_canvas_width;
1575 framepos_t new_page = (framepos_t) floor (_canvas_width * new_fpu);
1576 framepos_t middle = (framepos_t) floor( (double)start + ((double)range / 2.0f ));
1577 framepos_t new_leftmost = (framepos_t) floor( (double)middle - ((double)new_page/2.0f));
1579 if (new_leftmost > middle) {
1583 if (new_leftmost < 0) {
1587 reposition_and_zoom (new_leftmost, new_fpu);
1591 Editor::temporal_zoom_to_frame (bool coarser, framepos_t frame)
1596 double range_before = frame - leftmost_frame;
1599 new_fpu = frames_per_unit;
1602 new_fpu *= 1.61803399;
1603 range_before *= 1.61803399;
1605 new_fpu = max(1.0,(new_fpu/1.61803399));
1606 range_before /= 1.61803399;
1609 if (new_fpu == frames_per_unit) {
1613 framepos_t new_leftmost = frame - (framepos_t)range_before;
1615 if (new_leftmost > frame) {
1619 if (new_leftmost < 0) {
1623 reposition_and_zoom (new_leftmost, new_fpu);
1628 Editor::choose_new_marker_name(string &name) {
1630 if (!Config->get_name_new_markers()) {
1631 /* don't prompt user for a new name */
1635 ArdourPrompter dialog (true);
1637 dialog.set_prompt (_("New Name:"));
1639 dialog.set_title (_("New Location Marker"));
1641 dialog.set_name ("MarkNameWindow");
1642 dialog.set_size_request (250, -1);
1643 dialog.set_position (Gtk::WIN_POS_MOUSE);
1645 dialog.add_button (Stock::OK, RESPONSE_ACCEPT);
1646 dialog.set_initial_text (name);
1650 switch (dialog.run ()) {
1651 case RESPONSE_ACCEPT:
1657 dialog.get_result(name);
1664 Editor::add_location_from_selection ()
1668 if (selection->time.empty()) {
1672 if (_session == 0 || clicked_axisview == 0) {
1676 framepos_t start = selection->time[clicked_selection].start;
1677 framepos_t end = selection->time[clicked_selection].end;
1679 _session->locations()->next_available_name(rangename,"selection");
1680 Location *location = new Location (*_session, start, end, rangename, Location::IsRangeMarker);
1682 _session->begin_reversible_command (_("add marker"));
1683 XMLNode &before = _session->locations()->get_state();
1684 _session->locations()->add (location, true);
1685 XMLNode &after = _session->locations()->get_state();
1686 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
1687 _session->commit_reversible_command ();
1691 Editor::add_location_mark (framepos_t where)
1695 select_new_marker = true;
1697 _session->locations()->next_available_name(markername,"mark");
1698 if (!choose_new_marker_name(markername)) {
1701 Location *location = new Location (*_session, where, where, markername, Location::IsMark);
1702 _session->begin_reversible_command (_("add marker"));
1703 XMLNode &before = _session->locations()->get_state();
1704 _session->locations()->add (location, true);
1705 XMLNode &after = _session->locations()->get_state();
1706 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
1707 _session->commit_reversible_command ();
1711 Editor::add_location_from_playhead_cursor ()
1713 add_location_mark (_session->audible_frame());
1716 /** Add a range marker around each selected region */
1718 Editor::add_locations_from_region ()
1720 RegionSelection rs = get_regions_from_selection_and_entered ();
1726 _session->begin_reversible_command (selection->regions.size () > 1 ? _("add markers") : _("add marker"));
1727 XMLNode &before = _session->locations()->get_state();
1729 for (RegionSelection::iterator i = rs.begin (); i != rs.end (); ++i) {
1731 boost::shared_ptr<Region> region = (*i)->region ();
1733 Location *location = new Location (*_session, region->position(), region->last_frame(), region->name(), Location::IsRangeMarker);
1735 _session->locations()->add (location, true);
1738 XMLNode &after = _session->locations()->get_state();
1739 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
1740 _session->commit_reversible_command ();
1743 /** Add a single range marker around all selected regions */
1745 Editor::add_location_from_region ()
1747 RegionSelection rs = get_regions_from_selection_and_entered ();
1753 _session->begin_reversible_command (_("add marker"));
1754 XMLNode &before = _session->locations()->get_state();
1758 if (rs.size() > 1) {
1759 _session->locations()->next_available_name(markername, "regions");
1761 RegionView* rv = *(rs.begin());
1762 boost::shared_ptr<Region> region = rv->region();
1763 markername = region->name();
1766 if (!choose_new_marker_name(markername)) {
1770 // single range spanning all selected
1771 Location *location = new Location (*_session, selection->regions.start(), selection->regions.end_frame(), markername, Location::IsRangeMarker);
1772 _session->locations()->add (location, true);
1774 XMLNode &after = _session->locations()->get_state();
1775 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
1776 _session->commit_reversible_command ();
1782 Editor::jump_forward_to_mark ()
1788 Location *location = _session->locations()->first_location_after (playhead_cursor->current_frame);
1791 _session->request_locate (location->start(), _session->transport_rolling());
1793 _session->request_locate (_session->current_end_frame());
1798 Editor::jump_backward_to_mark ()
1804 Location *location = _session->locations()->first_location_before (playhead_cursor->current_frame);
1807 _session->request_locate (location->start(), _session->transport_rolling());
1809 _session->goto_start ();
1816 framepos_t const pos = _session->audible_frame ();
1819 _session->locations()->next_available_name (markername, "mark");
1821 if (!choose_new_marker_name (markername)) {
1825 _session->locations()->add (new Location (*_session, pos, 0, markername, Location::IsMark), true);
1829 Editor::clear_markers ()
1832 _session->begin_reversible_command (_("clear markers"));
1833 XMLNode &before = _session->locations()->get_state();
1834 _session->locations()->clear_markers ();
1835 XMLNode &after = _session->locations()->get_state();
1836 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
1837 _session->commit_reversible_command ();
1842 Editor::clear_ranges ()
1845 _session->begin_reversible_command (_("clear ranges"));
1846 XMLNode &before = _session->locations()->get_state();
1848 Location * looploc = _session->locations()->auto_loop_location();
1849 Location * punchloc = _session->locations()->auto_punch_location();
1850 Location * sessionloc = _session->locations()->session_range_location();
1852 _session->locations()->clear_ranges ();
1854 if (looploc) _session->locations()->add (looploc);
1855 if (punchloc) _session->locations()->add (punchloc);
1856 if (sessionloc) _session->locations()->add (sessionloc);
1858 XMLNode &after = _session->locations()->get_state();
1859 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
1860 _session->commit_reversible_command ();
1865 Editor::clear_locations ()
1867 _session->begin_reversible_command (_("clear locations"));
1868 XMLNode &before = _session->locations()->get_state();
1869 _session->locations()->clear ();
1870 XMLNode &after = _session->locations()->get_state();
1871 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
1872 _session->commit_reversible_command ();
1873 _session->locations()->clear ();
1877 Editor::unhide_markers ()
1879 for (LocationMarkerMap::iterator i = location_markers.begin(); i != location_markers.end(); ++i) {
1880 Location *l = (*i).first;
1881 if (l->is_hidden() && l->is_mark()) {
1882 l->set_hidden(false, this);
1888 Editor::unhide_ranges ()
1890 for (LocationMarkerMap::iterator i = location_markers.begin(); i != location_markers.end(); ++i) {
1891 Location *l = (*i).first;
1892 if (l->is_hidden() && l->is_range_marker()) {
1893 l->set_hidden(false, this);
1898 /* INSERT/REPLACE */
1901 Editor::insert_region_list_drag (boost::shared_ptr<Region> region, int x, int y)
1906 RouteTimeAxisView *rtv = 0;
1907 boost::shared_ptr<Playlist> playlist;
1909 track_canvas->window_to_world (x, y, wx, wy);
1912 event.type = GDK_BUTTON_RELEASE;
1913 event.button.x = wx;
1914 event.button.y = wy;
1916 where = event_frame (&event, &cx, &cy);
1918 if (where < leftmost_frame || where > leftmost_frame + current_page_frames()) {
1919 /* clearly outside canvas area */
1923 std::pair<TimeAxisView*, int> tv = trackview_by_y_position (cy);
1924 if (tv.first == 0) {
1928 if ((rtv = dynamic_cast<RouteTimeAxisView*> (tv.first)) == 0) {
1932 if ((playlist = rtv->playlist()) == 0) {
1938 begin_reversible_command (_("insert dragged region"));
1939 playlist->clear_changes ();
1940 playlist->add_region (RegionFactory::create (region, true), where, 1.0);
1941 _session->add_command(new StatefulDiffCommand (playlist));
1942 commit_reversible_command ();
1946 Editor::insert_route_list_drag (boost::shared_ptr<Route> route, int x, int y)
1950 RouteTimeAxisView *dest_rtv = 0;
1951 RouteTimeAxisView *source_rtv = 0;
1953 track_canvas->window_to_world (x, y, wx, wy);
1954 wx += horizontal_position ();
1955 wy += vertical_adjustment.get_value();
1958 event.type = GDK_BUTTON_RELEASE;
1959 event.button.x = wx;
1960 event.button.y = wy;
1962 event_frame (&event, &cx, &cy);
1964 std::pair<TimeAxisView*, int> const tv = trackview_by_y_position (cy);
1965 if (tv.first == 0) {
1969 if ((dest_rtv = dynamic_cast<RouteTimeAxisView*> (tv.first)) == 0) {
1973 /* use this drag source to add underlay to a track. But we really don't care
1974 about the Route, only the view of the route, so find it first */
1975 for(TrackViewList::iterator it = track_views.begin(); it != track_views.end(); ++it) {
1976 if((source_rtv = dynamic_cast<RouteTimeAxisView*>(*it)) == 0) {
1980 if(source_rtv->route() == route && source_rtv != dest_rtv) {
1981 dest_rtv->add_underlay(source_rtv->view());
1988 Editor::insert_region_list_selection (float times)
1990 RouteTimeAxisView *tv = 0;
1991 boost::shared_ptr<Playlist> playlist;
1993 if (clicked_routeview != 0) {
1994 tv = clicked_routeview;
1995 } else if (!selection->tracks.empty()) {
1996 if ((tv = dynamic_cast<RouteTimeAxisView*>(selection->tracks.front())) == 0) {
1999 } else if (entered_track != 0) {
2000 if ((tv = dynamic_cast<RouteTimeAxisView*>(entered_track)) == 0) {
2007 if ((playlist = tv->playlist()) == 0) {
2011 boost::shared_ptr<Region> region = _regions->get_single_selection ();
2016 begin_reversible_command (_("insert region"));
2017 playlist->clear_changes ();
2018 playlist->add_region ((RegionFactory::create (region, true)), get_preferred_edit_position(), times);
2019 _session->add_command(new StatefulDiffCommand (playlist));
2020 commit_reversible_command ();
2023 /* BUILT-IN EFFECTS */
2026 Editor::reverse_selection ()
2031 /* GAIN ENVELOPE EDITING */
2034 Editor::edit_envelope ()
2041 Editor::transition_to_rolling (bool fwd)
2047 if (_session->config.get_external_sync()) {
2048 switch (_session->config.get_sync_source()) {
2052 /* transport controlled by the master */
2057 if (_session->is_auditioning()) {
2058 _session->cancel_audition ();
2062 _session->request_transport_speed (fwd ? 1.0f : -1.0f);
2066 Editor::play_from_start ()
2068 _session->request_locate (_session->current_start_frame(), true);
2072 Editor::play_from_edit_point ()
2074 _session->request_locate (get_preferred_edit_position(), true);
2078 Editor::play_from_edit_point_and_return ()
2080 framepos_t start_frame;
2081 framepos_t return_frame;
2083 start_frame = get_preferred_edit_position (true);
2085 if (_session->transport_rolling()) {
2086 _session->request_locate (start_frame, false);
2090 /* don't reset the return frame if its already set */
2092 if ((return_frame = _session->requested_return_frame()) < 0) {
2093 return_frame = _session->audible_frame();
2096 if (start_frame >= 0) {
2097 _session->request_roll_at_and_return (start_frame, return_frame);
2102 Editor::play_selection ()
2104 if (selection->time.empty()) {
2108 _session->request_play_range (&selection->time, true);
2112 Editor::play_location (Location& location)
2114 if (location.start() <= location.end()) {
2118 _session->request_bounded_roll (location.start(), location.end());
2122 Editor::loop_location (Location& location)
2124 if (location.start() <= location.end()) {
2130 if ((tll = transport_loop_location()) != 0) {
2131 tll->set (location.start(), location.end());
2133 // enable looping, reposition and start rolling
2134 _session->request_play_loop (true);
2135 _session->request_locate (tll->start(), true);
2140 Editor::do_layer_operation (LayerOperation op)
2142 if (selection->regions.empty ()) {
2146 bool const multiple = selection->regions.size() > 1;
2150 begin_reversible_command (_("raise regions"));
2152 begin_reversible_command (_("raise region"));
2158 begin_reversible_command (_("raise regions to top"));
2160 begin_reversible_command (_("raise region to top"));
2166 begin_reversible_command (_("lower regions"));
2168 begin_reversible_command (_("lower region"));
2174 begin_reversible_command (_("lower regions to bottom"));
2176 begin_reversible_command (_("lower region"));
2181 set<boost::shared_ptr<Playlist> > playlists = selection->regions.playlists ();
2182 for (set<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
2183 (*i)->clear_owned_changes ();
2186 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
2187 boost::shared_ptr<Region> r = (*i)->region ();
2199 r->lower_to_bottom ();
2203 for (set<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
2204 vector<Command*> cmds;
2206 _session->add_commands (cmds);
2209 commit_reversible_command ();
2213 Editor::raise_region ()
2215 do_layer_operation (Raise);
2219 Editor::raise_region_to_top ()
2221 do_layer_operation (RaiseToTop);
2225 Editor::lower_region ()
2227 do_layer_operation (Lower);
2231 Editor::lower_region_to_bottom ()
2233 do_layer_operation (LowerToBottom);
2236 /** Show the region editor for the selected regions */
2238 Editor::show_region_properties ()
2240 selection->foreach_regionview (&RegionView::show_region_editor);
2243 /** Show the midi list editor for the selected MIDI regions */
2245 Editor::show_midi_list_editor ()
2247 selection->foreach_midi_regionview (&MidiRegionView::show_list_editor);
2251 Editor::rename_region ()
2253 RegionSelection rs = get_regions_from_selection_and_entered ();
2259 ArdourDialog d (*this, _("Rename Region"), true, false);
2261 Label label (_("New name:"));
2264 hbox.set_spacing (6);
2265 hbox.pack_start (label, false, false);
2266 hbox.pack_start (entry, true, true);
2268 d.get_vbox()->set_border_width (12);
2269 d.get_vbox()->pack_start (hbox, false, false);
2271 d.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
2272 d.add_button(Gtk::Stock::OK, Gtk::RESPONSE_OK);
2274 d.set_size_request (300, -1);
2275 d.set_position (Gtk::WIN_POS_MOUSE);
2277 entry.set_text (rs.front()->region()->name());
2278 entry.select_region (0, -1);
2280 entry.signal_activate().connect (sigc::bind (sigc::mem_fun (d, &Dialog::response), RESPONSE_OK));
2286 int const ret = d.run();
2290 if (ret != RESPONSE_OK) {
2294 std::string str = entry.get_text();
2295 strip_whitespace_edges (str);
2297 rs.front()->region()->set_name (str);
2298 _regions->redisplay ();
2303 Editor::audition_playlist_region_via_route (boost::shared_ptr<Region> region, Route& route)
2305 if (_session->is_auditioning()) {
2306 _session->cancel_audition ();
2309 // note: some potential for creativity here, because region doesn't
2310 // have to belong to the playlist that Route is handling
2312 // bool was_soloed = route.soloed();
2314 route.set_solo (true, this);
2316 _session->request_bounded_roll (region->position(), region->position() + region->length());
2318 /* XXX how to unset the solo state ? */
2321 /** Start an audition of the first selected region */
2323 Editor::play_edit_range ()
2325 framepos_t start, end;
2327 if (get_edit_op_range (start, end)) {
2328 _session->request_bounded_roll (start, end);
2333 Editor::play_selected_region ()
2335 framepos_t start = max_framepos;
2338 RegionSelection rs = get_regions_from_selection_and_entered ();
2344 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
2345 if ((*i)->region()->position() < start) {
2346 start = (*i)->region()->position();
2348 if ((*i)->region()->last_frame() + 1 > end) {
2349 end = (*i)->region()->last_frame() + 1;
2353 _session->request_bounded_roll (start, end);
2357 Editor::audition_playlist_region_standalone (boost::shared_ptr<Region> region)
2359 _session->audition_region (region);
2363 Editor::region_from_selection ()
2365 if (clicked_axisview == 0) {
2369 if (selection->time.empty()) {
2373 framepos_t start = selection->time[clicked_selection].start;
2374 framepos_t end = selection->time[clicked_selection].end;
2376 TrackViewList tracks = get_tracks_for_range_action ();
2378 framepos_t selection_cnt = end - start + 1;
2380 for (TrackSelection::iterator i = tracks.begin(); i != tracks.end(); ++i) {
2381 boost::shared_ptr<Region> current;
2382 boost::shared_ptr<Playlist> pl;
2383 framepos_t internal_start;
2386 if ((pl = (*i)->playlist()) == 0) {
2390 if ((current = pl->top_region_at (start)) == 0) {
2394 internal_start = start - current->position();
2395 RegionFactory::region_name (new_name, current->name(), true);
2399 plist.add (ARDOUR::Properties::start, current->start() + internal_start);
2400 plist.add (ARDOUR::Properties::length, selection_cnt);
2401 plist.add (ARDOUR::Properties::name, new_name);
2402 plist.add (ARDOUR::Properties::layer, 0);
2404 boost::shared_ptr<Region> region (RegionFactory::create (current, plist));
2409 Editor::create_region_from_selection (vector<boost::shared_ptr<Region> >& new_regions)
2411 if (selection->time.empty() || selection->tracks.empty()) {
2415 framepos_t start = selection->time[clicked_selection].start;
2416 framepos_t end = selection->time[clicked_selection].end;
2418 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
2419 sort_track_selection (ts);
2421 for (TrackSelection::iterator i = ts.begin(); i != ts.end(); ++i) {
2422 boost::shared_ptr<Region> current;
2423 boost::shared_ptr<Playlist> playlist;
2424 framepos_t internal_start;
2427 if ((playlist = (*i)->playlist()) == 0) {
2431 if ((current = playlist->top_region_at(start)) == 0) {
2435 internal_start = start - current->position();
2436 RegionFactory::region_name (new_name, current->name(), true);
2440 plist.add (ARDOUR::Properties::start, current->start() + internal_start);
2441 plist.add (ARDOUR::Properties::length, end - start + 1);
2442 plist.add (ARDOUR::Properties::name, new_name);
2444 new_regions.push_back (RegionFactory::create (current, plist));
2449 Editor::split_multichannel_region ()
2451 RegionSelection rs = get_regions_from_selection_and_entered ();
2457 vector< boost::shared_ptr<Region> > v;
2459 for (list<RegionView*>::iterator x = rs.begin(); x != rs.end(); ++x) {
2460 (*x)->region()->separate_by_channel (*_session, v);
2465 Editor::new_region_from_selection ()
2467 region_from_selection ();
2468 cancel_selection ();
2472 add_if_covered (RegionView* rv, const AudioRange* ar, RegionSelection* rs)
2474 switch (rv->region()->coverage (ar->start, ar->end - 1)) {
2483 * - selected tracks, or if there are none...
2484 * - tracks containing selected regions, or if there are none...
2489 Editor::get_tracks_for_range_action () const
2493 if (selection->tracks.empty()) {
2495 /* use tracks with selected regions */
2497 RegionSelection rs = selection->regions;
2499 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
2500 TimeAxisView* tv = &(*i)->get_time_axis_view();
2502 if (!t.contains (tv)) {
2508 /* no regions and no tracks: use all tracks */
2514 t = selection->tracks;
2517 return t.filter_to_unique_playlists();
2521 Editor::separate_regions_between (const TimeSelection& ts)
2523 bool in_command = false;
2524 boost::shared_ptr<Playlist> playlist;
2525 RegionSelection new_selection;
2527 TrackViewList tmptracks = get_tracks_for_range_action ();
2528 sort_track_selection (tmptracks);
2530 for (TrackSelection::iterator i = tmptracks.begin(); i != tmptracks.end(); ++i) {
2532 RouteTimeAxisView* rtv;
2534 if ((rtv = dynamic_cast<RouteTimeAxisView*> ((*i))) != 0) {
2536 if (rtv->is_track()) {
2538 /* no edits to destructive tracks */
2540 if (rtv->track()->destructive()) {
2544 if ((playlist = rtv->playlist()) != 0) {
2546 playlist->clear_changes ();
2548 /* XXX need to consider musical time selections here at some point */
2550 double speed = rtv->track()->speed();
2553 for (list<AudioRange>::const_iterator t = ts.begin(); t != ts.end(); ++t) {
2555 sigc::connection c = rtv->view()->RegionViewAdded.connect (
2556 sigc::mem_fun(*this, &Editor::collect_new_region_view));
2558 latest_regionviews.clear ();
2560 playlist->partition ((framepos_t)((*t).start * speed),
2561 (framepos_t)((*t).end * speed), false);
2565 if (!latest_regionviews.empty()) {
2567 rtv->view()->foreach_regionview (sigc::bind (
2568 sigc::ptr_fun (add_if_covered),
2569 &(*t), &new_selection));
2572 begin_reversible_command (_("separate"));
2576 /* pick up changes to existing regions */
2578 vector<Command*> cmds;
2579 playlist->rdiff (cmds);
2580 _session->add_commands (cmds);
2582 /* pick up changes to the playlist itself (adds/removes)
2585 _session->add_command(new StatefulDiffCommand (playlist));
2594 selection->set (new_selection);
2595 set_mouse_mode (MouseObject);
2597 commit_reversible_command ();
2601 struct PlaylistState {
2602 boost::shared_ptr<Playlist> playlist;
2606 /** Take tracks from get_tracks_for_range_action and cut any regions
2607 * on those tracks so that the tracks are empty over the time
2611 Editor::separate_region_from_selection ()
2613 /* preferentially use *all* ranges in the time selection if we're in range mode
2614 to allow discontiguous operation, since get_edit_op_range() currently
2615 returns a single range.
2618 if (mouse_mode == MouseRange && !selection->time.empty()) {
2620 separate_regions_between (selection->time);
2627 if (get_edit_op_range (start, end)) {
2629 AudioRange ar (start, end, 1);
2633 separate_regions_between (ts);
2639 Editor::separate_region_from_punch ()
2641 Location* loc = _session->locations()->auto_punch_location();
2643 separate_regions_using_location (*loc);
2648 Editor::separate_region_from_loop ()
2650 Location* loc = _session->locations()->auto_loop_location();
2652 separate_regions_using_location (*loc);
2657 Editor::separate_regions_using_location (Location& loc)
2659 if (loc.is_mark()) {
2663 AudioRange ar (loc.start(), loc.end(), 1);
2668 separate_regions_between (ts);
2671 /** Separate regions under the selected region */
2673 Editor::separate_under_selected_regions ()
2675 vector<PlaylistState> playlists;
2679 rs = get_regions_from_selection_and_entered();
2681 if (!_session || rs.empty()) {
2685 begin_reversible_command (_("separate region under"));
2687 list<boost::shared_ptr<Region> > regions_to_remove;
2689 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
2690 // we can't just remove the region(s) in this loop because
2691 // this removes them from the RegionSelection, and they thus
2692 // disappear from underneath the iterator, and the ++i above
2693 // SEGVs in a puzzling fashion.
2695 // so, first iterate over the regions to be removed from rs and
2696 // add them to the regions_to_remove list, and then
2697 // iterate over the list to actually remove them.
2699 regions_to_remove.push_back ((*i)->region());
2702 for (list<boost::shared_ptr<Region> >::iterator rl = regions_to_remove.begin(); rl != regions_to_remove.end(); ++rl) {
2704 boost::shared_ptr<Playlist> playlist = (*rl)->playlist();
2707 // is this check necessary?
2711 vector<PlaylistState>::iterator i;
2713 //only take state if this is a new playlist.
2714 for (i = playlists.begin(); i != playlists.end(); ++i) {
2715 if ((*i).playlist == playlist) {
2720 if (i == playlists.end()) {
2722 PlaylistState before;
2723 before.playlist = playlist;
2724 before.before = &playlist->get_state();
2726 playlist->freeze ();
2727 playlists.push_back(before);
2730 //Partition on the region bounds
2731 playlist->partition ((*rl)->first_frame() - 1, (*rl)->last_frame() + 1, true);
2733 //Re-add region that was just removed due to the partition operation
2734 playlist->add_region( (*rl), (*rl)->first_frame() );
2737 vector<PlaylistState>::iterator pl;
2739 for (pl = playlists.begin(); pl != playlists.end(); ++pl) {
2740 (*pl).playlist->thaw ();
2741 _session->add_command(new MementoCommand<Playlist>(*(*pl).playlist, (*pl).before, &(*pl).playlist->get_state()));
2744 commit_reversible_command ();
2748 Editor::crop_region_to_selection ()
2750 if (!selection->time.empty()) {
2752 crop_region_to (selection->time.start(), selection->time.end_frame());
2759 if (get_edit_op_range (start, end)) {
2760 crop_region_to (start, end);
2767 Editor::crop_region_to (framepos_t start, framepos_t end)
2769 vector<boost::shared_ptr<Playlist> > playlists;
2770 boost::shared_ptr<Playlist> playlist;
2773 if (selection->tracks.empty()) {
2774 ts = track_views.filter_to_unique_playlists();
2776 ts = selection->tracks.filter_to_unique_playlists ();
2779 sort_track_selection (ts);
2781 for (TrackSelection::iterator i = ts.begin(); i != ts.end(); ++i) {
2783 RouteTimeAxisView* rtv;
2785 if ((rtv = dynamic_cast<RouteTimeAxisView*> ((*i))) != 0) {
2787 boost::shared_ptr<Track> t = rtv->track();
2789 if (t != 0 && ! t->destructive()) {
2791 if ((playlist = rtv->playlist()) != 0) {
2792 playlists.push_back (playlist);
2798 if (playlists.empty()) {
2802 framepos_t the_start;
2806 begin_reversible_command (_("trim to selection"));
2808 for (vector<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
2810 boost::shared_ptr<Region> region;
2814 if ((region = (*i)->top_region_at(the_start)) == 0) {
2818 /* now adjust lengths to that we do the right thing
2819 if the selection extends beyond the region
2822 the_start = max (the_start, (framepos_t) region->position());
2823 if (max_framepos - the_start < region->length()) {
2824 the_end = the_start + region->length() - 1;
2826 the_end = max_framepos;
2828 the_end = min (end, the_end);
2829 cnt = the_end - the_start + 1;
2831 region->clear_changes ();
2832 region->trim_to (the_start, cnt);
2833 _session->add_command (new StatefulDiffCommand (region));
2836 commit_reversible_command ();
2840 Editor::region_fill_track ()
2842 RegionSelection rs = get_regions_from_selection_and_entered ();
2844 if (!_session || rs.empty()) {
2848 framepos_t const end = _session->current_end_frame ();
2850 begin_reversible_command (Operations::region_fill);
2852 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
2854 boost::shared_ptr<Region> region ((*i)->region());
2856 boost::shared_ptr<Playlist> pl = region->playlist();
2858 if (end <= region->last_frame()) {
2862 double times = (double) (end - region->last_frame()) / (double) region->length();
2868 pl->clear_changes ();
2869 pl->add_region (RegionFactory::create (region, true), region->last_frame(), times);
2870 _session->add_command (new StatefulDiffCommand (pl));
2873 commit_reversible_command ();
2877 Editor::region_fill_selection ()
2879 if (clicked_routeview == 0 || !clicked_routeview->is_audio_track()) {
2883 if (selection->time.empty()) {
2887 boost::shared_ptr<Region> region = _regions->get_single_selection ();
2892 framepos_t start = selection->time[clicked_selection].start;
2893 framepos_t end = selection->time[clicked_selection].end;
2895 boost::shared_ptr<Playlist> playlist;
2897 if (selection->tracks.empty()) {
2901 framepos_t selection_length = end - start;
2902 float times = (float)selection_length / region->length();
2904 begin_reversible_command (Operations::fill_selection);
2906 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
2908 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
2910 if ((playlist = (*i)->playlist()) == 0) {
2914 playlist->clear_changes ();
2915 playlist->add_region (RegionFactory::create (region, true), start, times);
2916 _session->add_command (new StatefulDiffCommand (playlist));
2919 commit_reversible_command ();
2923 Editor::set_region_sync_position ()
2925 set_sync_point (get_preferred_edit_position (), get_regions_from_selection_and_edit_point ());
2929 Editor::set_sync_point (framepos_t where, const RegionSelection& rs)
2931 bool in_command = false;
2933 for (RegionSelection::const_iterator r = rs.begin(); r != rs.end(); ++r) {
2935 if (!(*r)->region()->covers (where)) {
2939 boost::shared_ptr<Region> region ((*r)->region());
2942 begin_reversible_command (_("set sync point"));
2946 region->clear_changes ();
2947 region->set_sync_position (where);
2948 _session->add_command(new StatefulDiffCommand (region));
2952 commit_reversible_command ();
2956 /** Remove the sync positions of the selection */
2958 Editor::remove_region_sync ()
2960 RegionSelection rs = get_regions_from_selection_and_entered ();
2966 begin_reversible_command (_("remove region sync"));
2968 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
2970 (*i)->region()->clear_changes ();
2971 (*i)->region()->clear_sync_position ();
2972 _session->add_command(new StatefulDiffCommand ((*i)->region()));
2975 commit_reversible_command ();
2979 Editor::naturalize_region ()
2981 RegionSelection rs = get_regions_from_selection_and_entered ();
2987 if (rs.size() > 1) {
2988 begin_reversible_command (_("move regions to original position"));
2990 begin_reversible_command (_("move region to original position"));
2993 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
2994 (*i)->region()->clear_changes ();
2995 (*i)->region()->move_to_natural_position ();
2996 _session->add_command (new StatefulDiffCommand ((*i)->region()));
2999 commit_reversible_command ();
3003 Editor::align_regions (RegionPoint what)
3005 RegionSelection const rs = get_regions_from_selection_and_edit_point ();
3011 begin_reversible_command (_("align selection"));
3013 framepos_t const position = get_preferred_edit_position ();
3015 for (RegionSelection::const_iterator i = rs.begin(); i != rs.end(); ++i) {
3016 align_region_internal ((*i)->region(), what, position);
3019 commit_reversible_command ();
3022 struct RegionSortByTime {
3023 bool operator() (const RegionView* a, const RegionView* b) {
3024 return a->region()->position() < b->region()->position();
3029 Editor::align_regions_relative (RegionPoint point)
3031 RegionSelection const rs = get_regions_from_selection_and_edit_point ();
3037 framepos_t const position = get_preferred_edit_position ();
3039 framepos_t distance = 0;
3043 list<RegionView*> sorted;
3044 rs.by_position (sorted);
3046 boost::shared_ptr<Region> r ((*sorted.begin())->region());
3051 if (position > r->position()) {
3052 distance = position - r->position();
3054 distance = r->position() - position;
3060 if (position > r->last_frame()) {
3061 distance = position - r->last_frame();
3062 pos = r->position() + distance;
3064 distance = r->last_frame() - position;
3065 pos = r->position() - distance;
3071 pos = r->adjust_to_sync (position);
3072 if (pos > r->position()) {
3073 distance = pos - r->position();
3075 distance = r->position() - pos;
3081 if (pos == r->position()) {
3085 begin_reversible_command (_("align selection (relative)"));
3087 /* move first one specially */
3089 r->clear_changes ();
3090 r->set_position (pos);
3091 _session->add_command(new StatefulDiffCommand (r));
3093 /* move rest by the same amount */
3097 for (list<RegionView*>::iterator i = sorted.begin(); i != sorted.end(); ++i) {
3099 boost::shared_ptr<Region> region ((*i)->region());
3101 region->clear_changes ();
3104 region->set_position (region->position() + distance);
3106 region->set_position (region->position() - distance);
3109 _session->add_command(new StatefulDiffCommand (region));
3113 commit_reversible_command ();
3117 Editor::align_region (boost::shared_ptr<Region> region, RegionPoint point, framepos_t position)
3119 begin_reversible_command (_("align region"));
3120 align_region_internal (region, point, position);
3121 commit_reversible_command ();
3125 Editor::align_region_internal (boost::shared_ptr<Region> region, RegionPoint point, framepos_t position)
3127 region->clear_changes ();
3131 region->set_position (region->adjust_to_sync (position));
3135 if (position > region->length()) {
3136 region->set_position (position - region->length());
3141 region->set_position (position);
3145 _session->add_command(new StatefulDiffCommand (region));
3149 Editor::trim_region_front ()
3155 Editor::trim_region_back ()
3157 trim_region (false);
3161 Editor::trim_region (bool front)
3163 framepos_t where = get_preferred_edit_position();
3164 RegionSelection rs = get_regions_from_selection_and_edit_point ();
3166 cerr << "trim regions\n";
3169 cerr << " no regions\n";
3173 cerr << "where = " << where << endl;
3175 begin_reversible_command (front ? _("trim front") : _("trim back"));
3177 for (list<RegionView*>::const_iterator i = rs.by_layer().begin(); i != rs.by_layer().end(); ++i) {
3178 if (!(*i)->region()->locked()) {
3180 (*i)->region()->clear_changes ();
3183 (*i)->region()->trim_front (where);
3185 (*i)->region()->trim_end (where);
3188 _session->add_command (new StatefulDiffCommand ((*i)->region()));
3192 commit_reversible_command ();
3195 /** Trim the end of the selected regions to the position of the edit cursor */
3197 Editor::trim_region_to_loop ()
3199 Location* loc = _session->locations()->auto_loop_location();
3203 trim_region_to_location (*loc, _("trim to loop"));
3207 Editor::trim_region_to_punch ()
3209 Location* loc = _session->locations()->auto_punch_location();
3213 trim_region_to_location (*loc, _("trim to punch"));
3217 Editor::trim_region_to_location (const Location& loc, const char* str)
3219 RegionSelection rs = get_regions_from_selection_and_entered ();
3221 begin_reversible_command (str);
3223 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
3224 RegionView* rv = (*x);
3226 /* require region to span proposed trim */
3227 switch (rv->region()->coverage (loc.start(), loc.end())) {
3228 case OverlapInternal:
3234 RouteTimeAxisView* tav = dynamic_cast<RouteTimeAxisView*> (&rv->get_time_axis_view());
3243 if (tav->track() != 0) {
3244 speed = tav->track()->speed();
3247 start = session_frame_to_track_frame (loc.start(), speed);
3248 end = session_frame_to_track_frame (loc.end(), speed);
3250 rv->region()->clear_changes ();
3251 rv->region()->trim_to (start, (end - start));
3252 _session->add_command(new StatefulDiffCommand (rv->region()));
3255 commit_reversible_command ();
3259 Editor::trim_region_to_previous_region_end ()
3261 return trim_to_region(false);
3265 Editor::trim_region_to_next_region_start ()
3267 return trim_to_region(true);
3271 Editor::trim_to_region(bool forward)
3273 RegionSelection rs = get_regions_from_selection_and_entered ();
3275 begin_reversible_command (_("trim to region"));
3277 boost::shared_ptr<Region> next_region;
3279 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
3281 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*x);
3287 AudioTimeAxisView* atav = dynamic_cast<AudioTimeAxisView*> (&arv->get_time_axis_view());
3295 if (atav->track() != 0) {
3296 speed = atav->track()->speed();
3300 boost::shared_ptr<Region> region = arv->region();
3301 boost::shared_ptr<Playlist> playlist (region->playlist());
3303 region->clear_changes ();
3307 next_region = playlist->find_next_region (region->first_frame(), Start, 1);
3313 region->trim_end((framepos_t) ( (next_region->first_frame() - 1) * speed));
3314 arv->region_changed (PropertyChange (ARDOUR::Properties::length));
3318 next_region = playlist->find_next_region (region->first_frame(), Start, 0);
3324 region->trim_front((framepos_t) ((next_region->last_frame() + 1) * speed));
3326 arv->region_changed (ARDOUR::bounds_change);
3329 _session->add_command(new StatefulDiffCommand (region));
3332 commit_reversible_command ();
3336 Editor::unfreeze_route ()
3338 if (clicked_routeview == 0 || !clicked_routeview->is_track()) {
3342 clicked_routeview->track()->unfreeze ();
3346 Editor::_freeze_thread (void* arg)
3348 return static_cast<Editor*>(arg)->freeze_thread ();
3352 Editor::freeze_thread ()
3354 /* create event pool because we may need to talk to the session */
3355 SessionEvent::create_per_thread_pool ("freeze events", 64);
3356 /* create per-thread buffers for process() tree to use */
3357 current_interthread_info->process_thread.init ();
3359 clicked_routeview->audio_track()->freeze_me (*current_interthread_info);
3360 current_interthread_info->done = true;
3365 Editor::freeze_route ()
3371 /* stop transport before we start. this is important */
3373 _session->request_transport_speed (0.0);
3375 /* wait for just a little while, because the above call is asynchronous */
3379 if (clicked_routeview == 0 || !clicked_routeview->is_audio_track()) {
3383 if (!clicked_routeview->track()->bounceable (clicked_routeview->track()->main_outs(), true)) {
3385 _("This track/bus cannot be frozen because the signal adds or loses channels before reaching the outputs.\n"
3386 "This is typically caused by plugins that generate stereo output from mono input or vice versa.")
3388 d.set_title (_("Cannot freeze"));
3393 if (clicked_routeview->track()->has_external_redirects()) {
3394 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"
3395 "Freezing will only process the signal as far as the first send/insert/return."),
3396 clicked_routeview->track()->name()), true, MESSAGE_INFO, BUTTONS_NONE, true);
3398 d.add_button (_("Freeze anyway"), Gtk::RESPONSE_OK);
3399 d.add_button (_("Don't freeze"), Gtk::RESPONSE_CANCEL);
3400 d.set_title (_("Freeze Limits"));
3402 int response = d.run ();
3405 case Gtk::RESPONSE_CANCEL:
3412 InterThreadInfo itt;
3413 current_interthread_info = &itt;
3415 InterthreadProgressWindow ipw (current_interthread_info, _("Freeze"), _("Cancel Freeze"));
3417 pthread_create_and_store (X_("freezer"), &itt.thread, _freeze_thread, this);
3419 set_canvas_cursor (_cursors->wait);
3421 while (!itt.done && !itt.cancel) {
3422 gtk_main_iteration ();
3425 current_interthread_info = 0;
3426 set_canvas_cursor (current_canvas_cursor);
3430 Editor::bounce_range_selection (bool replace, bool enable_processing)
3432 if (selection->time.empty()) {
3436 TrackSelection views = selection->tracks;
3438 for (TrackViewList::iterator i = views.begin(); i != views.end(); ++i) {
3440 if (enable_processing) {
3442 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*i);
3444 if (rtv && rtv->track() && replace && enable_processing && !rtv->track()->bounceable (rtv->track()->main_outs(), false)) {
3446 _("You can't perform this operation because the processing of the signal "
3447 "will cause one or more of the tracks will end up with a region with more channels than this track has inputs.\n\n"
3448 "You can do this without processing, which is a different operation.")
3450 d.set_title (_("Cannot bounce"));
3457 framepos_t start = selection->time[clicked_selection].start;
3458 framepos_t end = selection->time[clicked_selection].end;
3459 framepos_t cnt = end - start + 1;
3461 begin_reversible_command (_("bounce range"));
3463 for (TrackViewList::iterator i = views.begin(); i != views.end(); ++i) {
3465 RouteTimeAxisView* rtv;
3467 if ((rtv = dynamic_cast<RouteTimeAxisView*> (*i)) == 0) {
3471 boost::shared_ptr<Playlist> playlist;
3473 if ((playlist = rtv->playlist()) == 0) {
3477 InterThreadInfo itt;
3479 playlist->clear_changes ();
3480 playlist->clear_owned_changes ();
3482 boost::shared_ptr<Region> r;
3484 if (enable_processing) {
3485 r = rtv->track()->bounce_range (start, start+cnt, itt, rtv->track()->main_outs(), false);
3487 r = rtv->track()->bounce_range (start, start+cnt, itt, boost::shared_ptr<Processor>(), false);
3495 list<AudioRange> ranges;
3496 ranges.push_back (AudioRange (start, start+cnt, 0));
3497 playlist->cut (ranges); // discard result
3498 playlist->add_region (r, start);
3501 vector<Command*> cmds;
3502 playlist->rdiff (cmds);
3503 _session->add_commands (cmds);
3505 _session->add_command (new StatefulDiffCommand (playlist));
3508 commit_reversible_command ();
3511 /** Delete selected regions, automation points or a time range */
3518 /** Cut selected regions, automation points or a time range */
3525 /** Copy selected regions, automation points or a time range */
3533 /** @return true if a Cut, Copy or Clear is possible */
3535 Editor::can_cut_copy () const
3537 switch (current_mouse_mode()) {
3540 if (!selection->regions.empty() || !selection->points.empty()) {
3546 if (!selection->time.empty()) {
3559 /** Cut, copy or clear selected regions, automation points or a time range.
3560 * @param op Operation (Cut, Copy or Clear)
3563 Editor::cut_copy (CutCopyOp op)
3565 /* only cancel selection if cut/copy is successful.*/
3571 opname = _("delete");
3580 opname = _("clear");
3584 /* if we're deleting something, and the mouse is still pressed,
3585 the thing we started a drag for will be gone when we release
3586 the mouse button(s). avoid this. see part 2 at the end of
3590 if (op == Delete || op == Cut || op == Clear) {
3591 if (_drags->active ()) {
3596 cut_buffer->clear ();
3598 if (entered_marker) {
3600 /* cut/delete op while pointing at a marker */
3603 Location* loc = find_location_from_marker (entered_marker, ignored);
3605 if (_session && loc) {
3606 Glib::signal_idle().connect (sigc::bind (sigc::mem_fun(*this, &Editor::really_remove_marker), loc));
3613 if (internal_editing()) {
3615 switch (current_mouse_mode()) {
3628 /* we only want to cut regions if some are selected */
3630 if (doing_object_stuff()) {
3631 rs = get_regions_from_selection ();
3632 if (!rs.empty() || !selection->points.empty()) {
3634 begin_reversible_command (opname + _(" objects"));
3637 cut_copy_regions (op, rs);
3639 if (op == Cut || op == Delete) {
3640 selection->clear_regions ();
3644 if (!selection->points.empty()) {
3645 cut_copy_points (op);
3647 if (op == Cut || op == Delete) {
3648 selection->clear_points ();
3651 commit_reversible_command ();
3654 if (!selection->time.empty() && (_join_object_range_state == JOIN_OBJECT_RANGE_NONE)) {
3655 /* don't cause suprises */
3660 if (doing_range_stuff()) {
3661 if (selection->time.empty()) {
3662 framepos_t start, end;
3663 if (!get_edit_op_range (start, end)) {
3666 selection->set (start, end);
3669 begin_reversible_command (opname + _(" range"));
3670 cut_copy_ranges (op);
3671 commit_reversible_command ();
3673 if (op == Cut || op == Delete) {
3674 selection->clear_time ();
3680 if (op == Delete || op == Cut || op == Clear) {
3685 /** Cut, copy or clear selected automation points.
3686 * @param op Operation (Cut, Copy or Clear)
3689 Editor::cut_copy_points (CutCopyOp op)
3691 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
3693 AutomationTimeAxisView* atv = dynamic_cast<AutomationTimeAxisView*>((*i).track);
3694 _last_cut_copy_source_track = atv;
3697 atv->cut_copy_clear_objects (selection->points, op);
3702 /** Cut, copy or clear selected automation points.
3703 * @param op Operation (Cut, Copy or Clear)
3706 Editor::cut_copy_midi (CutCopyOp op)
3708 for (MidiRegionSelection::iterator i = selection->midi_regions.begin(); i != selection->midi_regions.end(); ++i) {
3709 MidiRegionView* mrv = *i;
3710 mrv->cut_copy_clear (op);
3716 struct lt_playlist {
3717 bool operator () (const PlaylistState& a, const PlaylistState& b) {
3718 return a.playlist < b.playlist;
3722 struct PlaylistMapping {
3724 boost::shared_ptr<Playlist> pl;
3726 PlaylistMapping (TimeAxisView* tvp) : tv (tvp) {}
3729 /** Remove `clicked_regionview' */
3731 Editor::remove_clicked_region ()
3733 if (clicked_routeview == 0 || clicked_regionview == 0) {
3737 boost::shared_ptr<Playlist> playlist = clicked_routeview->playlist();
3739 begin_reversible_command (_("remove region"));
3740 playlist->clear_changes ();
3741 playlist->clear_owned_changes ();
3742 playlist->remove_region (clicked_regionview->region());
3744 /* We might have removed regions, which alters other regions' layering_index,
3745 so we need to do a recursive diff here.
3747 vector<Command*> cmds;
3748 playlist->rdiff (cmds);
3749 _session->add_commands (cmds);
3751 _session->add_command(new StatefulDiffCommand (playlist));
3752 commit_reversible_command ();
3756 /** Remove the selected regions */
3758 Editor::remove_selected_regions ()
3760 RegionSelection rs = get_regions_from_selection_and_entered ();
3762 if (!_session || rs.empty()) {
3766 begin_reversible_command (_("remove region"));
3768 list<boost::shared_ptr<Region> > regions_to_remove;
3770 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3771 // we can't just remove the region(s) in this loop because
3772 // this removes them from the RegionSelection, and they thus
3773 // disappear from underneath the iterator, and the ++i above
3774 // SEGVs in a puzzling fashion.
3776 // so, first iterate over the regions to be removed from rs and
3777 // add them to the regions_to_remove list, and then
3778 // iterate over the list to actually remove them.
3780 regions_to_remove.push_back ((*i)->region());
3783 vector<boost::shared_ptr<Playlist> > playlists;
3785 for (list<boost::shared_ptr<Region> >::iterator rl = regions_to_remove.begin(); rl != regions_to_remove.end(); ++rl) {
3787 boost::shared_ptr<Playlist> playlist = (*rl)->playlist();
3790 // is this check necessary?
3794 /* get_regions_from_selection_and_entered() guarantees that
3795 the playlists involved are unique, so there is no need
3799 playlists.push_back (playlist);
3801 playlist->clear_changes ();
3802 playlist->clear_owned_changes ();
3803 playlist->freeze ();
3804 playlist->remove_region (*rl);
3807 vector<boost::shared_ptr<Playlist> >::iterator pl;
3809 for (pl = playlists.begin(); pl != playlists.end(); ++pl) {
3812 /* We might have removed regions, which alters other regions' layering_index,
3813 so we need to do a recursive diff here.
3815 vector<Command*> cmds;
3816 (*pl)->rdiff (cmds);
3817 _session->add_commands (cmds);
3819 _session->add_command(new StatefulDiffCommand (*pl));
3822 commit_reversible_command ();
3825 /** Cut, copy or clear selected regions.
3826 * @param op Operation (Cut, Copy or Clear)
3829 Editor::cut_copy_regions (CutCopyOp op, RegionSelection& rs)
3831 /* we can't use a std::map here because the ordering is important, and we can't trivially sort
3832 a map when we want ordered access to both elements. i think.
3835 vector<PlaylistMapping> pmap;
3837 framepos_t first_position = max_framepos;
3839 typedef set<boost::shared_ptr<Playlist> > FreezeList;
3840 FreezeList freezelist;
3842 /* get ordering correct before we cut/copy */
3844 rs.sort_by_position_and_track ();
3846 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
3848 first_position = min ((framepos_t) (*x)->region()->position(), first_position);
3850 if (op == Cut || op == Clear || op == Delete) {
3851 boost::shared_ptr<Playlist> pl = (*x)->region()->playlist();
3854 FreezeList::iterator fl;
3856 // only take state if this is a new playlist.
3857 for (fl = freezelist.begin(); fl != freezelist.end(); ++fl) {
3863 if (fl == freezelist.end()) {
3864 pl->clear_changes();
3865 pl->clear_owned_changes ();
3867 freezelist.insert (pl);
3872 TimeAxisView* tv = &(*x)->get_time_axis_view();
3873 vector<PlaylistMapping>::iterator z;
3875 for (z = pmap.begin(); z != pmap.end(); ++z) {
3876 if ((*z).tv == tv) {
3881 if (z == pmap.end()) {
3882 pmap.push_back (PlaylistMapping (tv));
3886 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ) {
3888 boost::shared_ptr<Playlist> pl = (*x)->region()->playlist();
3891 /* region not yet associated with a playlist (e.g. unfinished
3898 TimeAxisView& tv = (*x)->get_time_axis_view();
3899 boost::shared_ptr<Playlist> npl;
3900 RegionSelection::iterator tmp;
3907 vector<PlaylistMapping>::iterator z;
3909 for (z = pmap.begin(); z != pmap.end(); ++z) {
3910 if ((*z).tv == &tv) {
3915 assert (z != pmap.end());
3918 npl = PlaylistFactory::create (pl->data_type(), *_session, "cutlist", true);
3926 boost::shared_ptr<Region> r = (*x)->region();
3927 boost::shared_ptr<Region> _xx;
3933 pl->remove_region (r);
3937 _xx = RegionFactory::create (r);
3938 npl->add_region (_xx, r->position() - first_position);
3939 pl->remove_region (r);
3943 /* copy region before adding, so we're not putting same object into two different playlists */
3944 npl->add_region (RegionFactory::create (r), r->position() - first_position);
3948 pl->remove_region (r);
3957 list<boost::shared_ptr<Playlist> > foo;
3959 /* the pmap is in the same order as the tracks in which selected regions occured */
3961 for (vector<PlaylistMapping>::iterator i = pmap.begin(); i != pmap.end(); ++i) {
3964 foo.push_back ((*i).pl);
3969 cut_buffer->set (foo);
3973 _last_cut_copy_source_track = 0;
3975 _last_cut_copy_source_track = pmap.front().tv;
3979 for (FreezeList::iterator pl = freezelist.begin(); pl != freezelist.end(); ++pl) {
3982 /* We might have removed regions, which alters other regions' layering_index,
3983 so we need to do a recursive diff here.
3985 vector<Command*> cmds;
3986 (*pl)->rdiff (cmds);
3987 _session->add_commands (cmds);
3989 _session->add_command (new StatefulDiffCommand (*pl));
3994 Editor::cut_copy_ranges (CutCopyOp op)
3996 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
3998 /* Sort the track selection now, so that it if is used, the playlists
3999 selected by the calls below to cut_copy_clear are in the order that
4000 their tracks appear in the editor. This makes things like paste
4001 of ranges work properly.
4004 sort_track_selection (ts);
4007 if (!entered_track) {
4010 ts.push_back (entered_track);
4013 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4014 (*i)->cut_copy_clear (*selection, op);
4019 Editor::paste (float times, bool from_context)
4021 DEBUG_TRACE (DEBUG::CutNPaste, "paste to preferred edit pos\n");
4023 paste_internal (get_preferred_edit_position (false, from_context), times);
4027 Editor::mouse_paste ()
4032 if (!mouse_frame (where, ignored)) {
4037 paste_internal (where, 1);
4041 Editor::paste_internal (framepos_t position, float times)
4043 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("apparent paste position is %1\n", position));
4045 if (internal_editing()) {
4046 if (cut_buffer->midi_notes.empty()) {
4050 if (cut_buffer->empty()) {
4055 if (position == max_framepos) {
4056 position = get_preferred_edit_position();
4057 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("preferred edit position is %1\n", position));
4061 TrackViewList::iterator i;
4064 /* get everything in the correct order */
4066 if (!selection->tracks.empty()) {
4067 /* there are some selected tracks, so paste to them */
4068 ts = selection->tracks.filter_to_unique_playlists ();
4069 sort_track_selection (ts);
4070 } else if (_last_cut_copy_source_track) {
4071 /* otherwise paste to the track that the cut/copy came from;
4072 see discussion in mantis #3333.
4074 ts.push_back (_last_cut_copy_source_track);
4077 if (internal_editing ()) {
4079 /* undo/redo is handled by individual tracks/regions */
4081 for (nth = 0, i = ts.begin(); i != ts.end(); ++i, ++nth) {
4084 RegionSelection::iterator r;
4085 MidiNoteSelection::iterator cb;
4087 get_regions_at (rs, position, ts);
4089 for (cb = cut_buffer->midi_notes.begin(), r = rs.begin();
4090 cb != cut_buffer->midi_notes.end() && r != rs.end(); ++r) {
4091 MidiRegionView* mrv = dynamic_cast<MidiRegionView*> (*r);
4093 mrv->paste (position, times, **cb);
4101 /* we do redo (do you do voodoo?) */
4103 begin_reversible_command (Operations::paste);
4105 for (nth = 0, i = ts.begin(); i != ts.end(); ++i, ++nth) {
4106 (*i)->paste (position, times, *cut_buffer, nth);
4109 commit_reversible_command ();
4114 Editor::duplicate_some_regions (RegionSelection& regions, float times)
4116 boost::shared_ptr<Playlist> playlist;
4117 RegionSelection sel = regions; // clear (below) may clear the argument list if its the current region selection
4118 RegionSelection foo;
4120 framepos_t const start_frame = regions.start ();
4121 framepos_t const end_frame = regions.end_frame ();
4123 begin_reversible_command (Operations::duplicate_region);
4125 selection->clear_regions ();
4127 for (RegionSelection::iterator i = sel.begin(); i != sel.end(); ++i) {
4129 boost::shared_ptr<Region> r ((*i)->region());
4131 TimeAxisView& tv = (*i)->get_time_axis_view();
4132 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (&tv);
4133 latest_regionviews.clear ();
4134 sigc::connection c = rtv->view()->RegionViewAdded.connect (sigc::mem_fun(*this, &Editor::collect_new_region_view));
4136 playlist = (*i)->region()->playlist();
4137 playlist->clear_changes ();
4138 playlist->duplicate (r, end_frame + (r->first_frame() - start_frame), times);
4139 _session->add_command(new StatefulDiffCommand (playlist));
4143 foo.insert (foo.end(), latest_regionviews.begin(), latest_regionviews.end());
4146 commit_reversible_command ();
4149 selection->set (foo);
4154 Editor::duplicate_selection (float times)
4156 if (selection->time.empty() || selection->tracks.empty()) {
4160 boost::shared_ptr<Playlist> playlist;
4161 vector<boost::shared_ptr<Region> > new_regions;
4162 vector<boost::shared_ptr<Region> >::iterator ri;
4164 create_region_from_selection (new_regions);
4166 if (new_regions.empty()) {
4170 begin_reversible_command (_("duplicate selection"));
4172 ri = new_regions.begin();
4174 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4176 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4177 if ((playlist = (*i)->playlist()) == 0) {
4180 playlist->clear_changes ();
4181 playlist->duplicate (*ri, selection->time[clicked_selection].end, times);
4182 _session->add_command (new StatefulDiffCommand (playlist));
4185 if (ri == new_regions.end()) {
4190 commit_reversible_command ();
4194 Editor::reset_point_selection ()
4196 /* reset all selected points to the relevant default value */
4198 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
4200 AutomationTimeAxisView* atv = dynamic_cast<AutomationTimeAxisView*>((*i).track);
4203 atv->reset_objects (selection->points);
4209 Editor::center_playhead ()
4211 float page = _canvas_width * frames_per_unit;
4212 center_screen_internal (playhead_cursor->current_frame, page);
4216 Editor::center_edit_point ()
4218 float page = _canvas_width * frames_per_unit;
4219 center_screen_internal (get_preferred_edit_position(), page);
4222 /** Caller must begin and commit a reversible command */
4224 Editor::clear_playlist (boost::shared_ptr<Playlist> playlist)
4226 playlist->clear_changes ();
4228 _session->add_command (new StatefulDiffCommand (playlist));
4232 Editor::nudge_track (bool use_edit, bool forwards)
4234 boost::shared_ptr<Playlist> playlist;
4235 framepos_t distance;
4236 framepos_t next_distance;
4240 start = get_preferred_edit_position();
4245 if ((distance = get_nudge_distance (start, next_distance)) == 0) {
4249 if (selection->tracks.empty()) {
4253 begin_reversible_command (_("nudge track"));
4255 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4257 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4259 if ((playlist = (*i)->playlist()) == 0) {
4263 playlist->clear_changes ();
4264 playlist->clear_owned_changes ();
4266 playlist->nudge_after (start, distance, forwards);
4268 vector<Command*> cmds;
4270 playlist->rdiff (cmds);
4271 _session->add_commands (cmds);
4273 _session->add_command (new StatefulDiffCommand (playlist));
4276 commit_reversible_command ();
4280 Editor::remove_last_capture ()
4282 vector<string> choices;
4289 if (Config->get_verify_remove_last_capture()) {
4290 prompt = _("Do you really want to destroy the last capture?"
4291 "\n(This is destructive and cannot be undone)");
4293 choices.push_back (_("No, do nothing."));
4294 choices.push_back (_("Yes, destroy it."));
4296 Gtkmm2ext::Choice prompter (_("Destroy last capture"), prompt, choices);
4298 if (prompter.run () == 1) {
4299 _session->remove_last_capture ();
4300 _regions->redisplay ();
4304 _session->remove_last_capture();
4305 _regions->redisplay ();
4310 Editor::normalize_region ()
4316 RegionSelection rs = get_regions_from_selection_and_entered ();
4322 NormalizeDialog dialog (rs.size() > 1);
4324 if (dialog.run () == RESPONSE_CANCEL) {
4328 set_canvas_cursor (_cursors->wait);
4331 /* XXX: should really only count audio regions here */
4332 int const regions = rs.size ();
4334 /* Make a list of the selected audio regions' maximum amplitudes, and also
4335 obtain the maximum amplitude of them all.
4337 list<double> max_amps;
4339 for (RegionSelection::const_iterator i = rs.begin(); i != rs.end(); ++i) {
4340 AudioRegionView const * arv = dynamic_cast<AudioRegionView const *> (*i);
4342 dialog.descend (1.0 / regions);
4343 double const a = arv->audio_region()->maximum_amplitude (&dialog);
4346 /* the user cancelled the operation */
4347 set_canvas_cursor (current_canvas_cursor);
4351 max_amps.push_back (a);
4352 max_amp = max (max_amp, a);
4357 begin_reversible_command (_("normalize"));
4359 list<double>::const_iterator a = max_amps.begin ();
4361 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
4362 AudioRegionView* const arv = dynamic_cast<AudioRegionView*> (*r);
4367 arv->region()->clear_changes ();
4369 double const amp = dialog.normalize_individually() ? *a : max_amp;
4371 arv->audio_region()->normalize (amp, dialog.target ());
4372 _session->add_command (new StatefulDiffCommand (arv->region()));
4377 commit_reversible_command ();
4378 set_canvas_cursor (current_canvas_cursor);
4383 Editor::reset_region_scale_amplitude ()
4389 RegionSelection rs = get_regions_from_selection_and_entered ();
4395 begin_reversible_command ("reset gain");
4397 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
4398 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
4401 arv->region()->clear_changes ();
4402 arv->audio_region()->set_scale_amplitude (1.0f);
4403 _session->add_command (new StatefulDiffCommand (arv->region()));
4406 commit_reversible_command ();
4410 Editor::adjust_region_gain (bool up)
4412 RegionSelection rs = get_regions_from_selection_and_entered ();
4414 if (!_session || rs.empty()) {
4418 begin_reversible_command ("adjust region gain");
4420 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
4421 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
4426 arv->region()->clear_changes ();
4428 double dB = accurate_coefficient_to_dB (arv->audio_region()->scale_amplitude ());
4436 arv->audio_region()->set_scale_amplitude (dB_to_coefficient (dB));
4437 _session->add_command (new StatefulDiffCommand (arv->region()));
4440 commit_reversible_command ();
4445 Editor::reverse_region ()
4451 Reverse rev (*_session);
4452 apply_filter (rev, _("reverse regions"));
4456 Editor::strip_region_silence ()
4462 RegionSelection rs = get_regions_from_selection_and_entered ();
4468 std::list<RegionView*> audio_only;
4470 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
4471 AudioRegionView* const arv = dynamic_cast<AudioRegionView*> (*i);
4473 audio_only.push_back (arv);
4477 StripSilenceDialog d (_session, audio_only);
4478 int const r = d.run ();
4482 if (r == Gtk::RESPONSE_OK) {
4483 ARDOUR::AudioIntervalMap silences;
4484 d.silences (silences);
4485 StripSilence s (*_session, silences, d.fade_length());
4486 apply_filter (s, _("strip silence"), &d);
4491 Editor::apply_midi_note_edit_op_to_region (MidiOperator& op, MidiRegionView& mrv)
4493 Evoral::Sequence<Evoral::MusicalTime>::Notes selected;
4494 mrv.selection_as_notelist (selected, true);
4496 vector<Evoral::Sequence<Evoral::MusicalTime>::Notes> v;
4497 v.push_back (selected);
4499 framepos_t pos_frames = mrv.midi_region()->position();
4500 double pos_beats = _session->tempo_map().framewalk_to_beats(0, pos_frames);
4502 return op (mrv.midi_region()->model(), pos_beats, v);
4506 Editor::apply_midi_note_edit_op (MidiOperator& op)
4510 RegionSelection rs = get_regions_from_selection_and_entered ();
4516 begin_reversible_command (op.name ());
4518 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
4519 RegionSelection::iterator tmp = r;
4522 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*r);
4525 cmd = apply_midi_note_edit_op_to_region (op, *mrv);
4528 _session->add_command (cmd);
4535 commit_reversible_command ();
4539 Editor::fork_region ()
4541 RegionSelection rs = get_regions_from_selection_and_entered ();
4547 begin_reversible_command (_("Fork Region(s)"));
4549 set_canvas_cursor (_cursors->wait);
4552 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
4553 RegionSelection::iterator tmp = r;
4556 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*>(*r);
4559 boost::shared_ptr<Playlist> playlist = mrv->region()->playlist();
4560 boost::shared_ptr<MidiRegion> newregion = mrv->midi_region()->clone ();
4562 playlist->clear_changes ();
4563 playlist->replace_region (mrv->region(), newregion, mrv->region()->position());
4564 _session->add_command(new StatefulDiffCommand (playlist));
4570 commit_reversible_command ();
4572 set_canvas_cursor (current_canvas_cursor);
4576 Editor::quantize_region ()
4578 int selected_midi_region_cnt = 0;
4584 RegionSelection rs = get_regions_from_selection_and_entered ();
4590 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
4591 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*r);
4593 selected_midi_region_cnt++;
4597 if (selected_midi_region_cnt == 0) {
4601 QuantizeDialog* qd = new QuantizeDialog (*this);
4604 const int r = qd->run ();
4607 if (r == Gtk::RESPONSE_OK) {
4608 Quantize quant (*_session, Plain,
4609 qd->snap_start(), qd->snap_end(),
4610 qd->start_grid_size(), qd->end_grid_size(),
4611 qd->strength(), qd->swing(), qd->threshold());
4613 apply_midi_note_edit_op (quant);
4618 Editor::insert_patch_change (bool from_context)
4620 RegionSelection rs = get_regions_from_selection_and_entered ();
4626 const framepos_t p = get_preferred_edit_position (false, from_context);
4628 Evoral::PatchChange<Evoral::MusicalTime> empty (0, 0, 0, 0);
4629 PatchChangeDialog d (0, _session, empty, Gtk::Stock::ADD);
4631 if (d.run() == RESPONSE_CANCEL) {
4635 for (RegionSelection::iterator i = rs.begin (); i != rs.end(); ++i) {
4636 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*i);
4638 if (p >= mrv->region()->first_frame() && p <= mrv->region()->last_frame()) {
4639 mrv->add_patch_change (p - mrv->region()->position(), d.patch ());
4646 Editor::apply_filter (Filter& filter, string command, ProgressReporter* progress)
4648 RegionSelection rs = get_regions_from_selection_and_entered ();
4654 begin_reversible_command (command);
4656 set_canvas_cursor (_cursors->wait);
4660 int const N = rs.size ();
4662 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
4663 RegionSelection::iterator tmp = r;
4666 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
4668 boost::shared_ptr<Playlist> playlist = arv->region()->playlist();
4671 progress->descend (1.0 / N);
4674 if (arv->audio_region()->apply (filter, progress) == 0) {
4676 playlist->clear_changes ();
4677 playlist->clear_owned_changes ();
4679 if (filter.results.empty ()) {
4681 /* no regions returned; remove the old one */
4682 playlist->remove_region (arv->region ());
4686 std::vector<boost::shared_ptr<Region> >::iterator res = filter.results.begin ();
4688 /* first region replaces the old one */
4689 playlist->replace_region (arv->region(), *res, (*res)->position());
4693 while (res != filter.results.end()) {
4694 playlist->add_region (*res, (*res)->position());
4700 /* We might have removed regions, which alters other regions' layering_index,
4701 so we need to do a recursive diff here.
4703 vector<Command*> cmds;
4704 playlist->rdiff (cmds);
4705 _session->add_commands (cmds);
4707 _session->add_command(new StatefulDiffCommand (playlist));
4713 progress->ascend ();
4721 commit_reversible_command ();
4724 set_canvas_cursor (current_canvas_cursor);
4728 Editor::external_edit_region ()
4734 Editor::reset_region_gain_envelopes ()
4736 RegionSelection rs = get_regions_from_selection_and_entered ();
4738 if (!_session || rs.empty()) {
4742 _session->begin_reversible_command (_("reset region gain"));
4744 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
4745 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
4747 boost::shared_ptr<AutomationList> alist (arv->audio_region()->envelope());
4748 XMLNode& before (alist->get_state());
4750 arv->audio_region()->set_default_envelope ();
4751 _session->add_command (new MementoCommand<AutomationList>(*arv->audio_region()->envelope().get(), &before, &alist->get_state()));
4755 _session->commit_reversible_command ();
4759 Editor::set_region_gain_visibility (RegionView* rv, bool yn)
4761 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (rv);
4763 arv->set_envelope_visible (yn);
4768 Editor::set_gain_envelope_visibility (bool yn)
4774 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4775 AudioTimeAxisView* v = dynamic_cast<AudioTimeAxisView*>(*i);
4777 v->audio_view()->foreach_regionview (sigc::bind (sigc::mem_fun (this, &Editor::set_region_gain_visibility), yn));
4783 Editor::toggle_gain_envelope_active ()
4785 if (_ignore_region_action) {
4789 RegionSelection rs = get_regions_from_selection_and_entered ();
4791 if (!_session || rs.empty()) {
4795 _session->begin_reversible_command (_("region gain envelope active"));
4797 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
4798 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
4800 arv->region()->clear_changes ();
4801 arv->audio_region()->set_envelope_active (!arv->audio_region()->envelope_active());
4802 _session->add_command (new StatefulDiffCommand (arv->region()));
4806 _session->commit_reversible_command ();
4810 Editor::toggle_region_lock ()
4812 if (_ignore_region_action) {
4816 RegionSelection rs = get_regions_from_selection_and_entered ();
4818 if (!_session || rs.empty()) {
4822 _session->begin_reversible_command (_("toggle region lock"));
4824 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
4825 (*i)->region()->clear_changes ();
4826 (*i)->region()->set_locked (!(*i)->region()->locked());
4827 _session->add_command (new StatefulDiffCommand ((*i)->region()));
4830 _session->commit_reversible_command ();
4834 Editor::toggle_region_lock_style ()
4836 if (_ignore_region_action) {
4840 RegionSelection rs = get_regions_from_selection_and_entered ();
4842 if (!_session || rs.empty()) {
4846 _session->begin_reversible_command (_("region lock style"));
4848 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
4849 (*i)->region()->clear_changes ();
4850 PositionLockStyle const ns = (*i)->region()->position_lock_style() == AudioTime ? MusicTime : AudioTime;
4851 (*i)->region()->set_position_lock_style (ns);
4852 _session->add_command (new StatefulDiffCommand ((*i)->region()));
4855 _session->commit_reversible_command ();
4859 Editor::toggle_opaque_region ()
4861 if (_ignore_region_action) {
4865 RegionSelection rs = get_regions_from_selection_and_entered ();
4867 if (!_session || rs.empty()) {
4871 _session->begin_reversible_command (_("change region opacity"));
4873 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
4874 (*i)->region()->clear_changes ();
4875 (*i)->region()->set_opaque (!(*i)->region()->opaque());
4876 _session->add_command (new StatefulDiffCommand ((*i)->region()));
4879 _session->commit_reversible_command ();
4883 Editor::toggle_record_enable ()
4885 bool new_state = false;
4887 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4888 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
4891 if (!rtav->is_track())
4895 new_state = !rtav->track()->record_enabled();
4899 rtav->track()->set_record_enabled (new_state, this);
4904 Editor::toggle_solo ()
4906 bool new_state = false;
4908 boost::shared_ptr<RouteList> rl (new RouteList);
4910 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4911 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
4918 new_state = !rtav->route()->soloed ();
4922 rl->push_back (rtav->route());
4925 _session->set_solo (rl, new_state, Session::rt_cleanup, true);
4929 Editor::toggle_mute ()
4931 bool new_state = false;
4933 boost::shared_ptr<RouteList> rl (new RouteList);
4935 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4936 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
4943 new_state = !rtav->route()->muted();
4947 rl->push_back (rtav->route());
4950 _session->set_mute (rl, new_state, Session::rt_cleanup, true);
4954 Editor::toggle_solo_isolate ()
4959 Editor::set_fade_length (bool in)
4961 RegionSelection rs = get_regions_from_selection_and_entered ();
4967 /* we need a region to measure the offset from the start */
4969 RegionView* rv = rs.front ();
4971 framepos_t pos = get_preferred_edit_position();
4975 if (pos > rv->region()->last_frame() || pos < rv->region()->first_frame()) {
4976 /* edit point is outside the relevant region */
4981 if (pos <= rv->region()->position()) {
4985 len = pos - rv->region()->position();
4986 cmd = _("set fade in length");
4988 if (pos >= rv->region()->last_frame()) {
4992 len = rv->region()->last_frame() - pos;
4993 cmd = _("set fade out length");
4996 begin_reversible_command (cmd);
4998 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
4999 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5005 boost::shared_ptr<AutomationList> alist;
5007 alist = tmp->audio_region()->fade_in();
5009 alist = tmp->audio_region()->fade_out();
5012 XMLNode &before = alist->get_state();
5015 tmp->audio_region()->set_fade_in_length (len);
5016 tmp->audio_region()->set_fade_in_active (true);
5018 tmp->audio_region()->set_fade_out_length (len);
5019 tmp->audio_region()->set_fade_out_active (true);
5022 XMLNode &after = alist->get_state();
5023 _session->add_command(new MementoCommand<AutomationList>(*alist, &before, &after));
5026 commit_reversible_command ();
5030 Editor::set_fade_in_shape (FadeShape shape)
5032 RegionSelection rs = get_regions_from_selection_and_entered ();
5038 begin_reversible_command (_("set fade in shape"));
5040 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5041 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5047 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_in();
5048 XMLNode &before = alist->get_state();
5050 tmp->audio_region()->set_fade_in_shape (shape);
5052 XMLNode &after = alist->get_state();
5053 _session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
5056 commit_reversible_command ();
5061 Editor::set_fade_out_shape (FadeShape shape)
5063 RegionSelection rs = get_regions_from_selection_and_entered ();
5069 begin_reversible_command (_("set fade out shape"));
5071 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5072 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5078 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_out();
5079 XMLNode &before = alist->get_state();
5081 tmp->audio_region()->set_fade_out_shape (shape);
5083 XMLNode &after = alist->get_state();
5084 _session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
5087 commit_reversible_command ();
5091 Editor::set_fade_in_active (bool yn)
5093 RegionSelection rs = get_regions_from_selection_and_entered ();
5099 begin_reversible_command (_("set fade in active"));
5101 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5102 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5109 boost::shared_ptr<AudioRegion> ar (tmp->audio_region());
5111 ar->clear_changes ();
5112 ar->set_fade_in_active (yn);
5113 _session->add_command (new StatefulDiffCommand (ar));
5116 commit_reversible_command ();
5120 Editor::set_fade_out_active (bool yn)
5122 RegionSelection rs = get_regions_from_selection_and_entered ();
5128 begin_reversible_command (_("set fade out active"));
5130 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5131 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5137 boost::shared_ptr<AudioRegion> ar (tmp->audio_region());
5139 ar->clear_changes ();
5140 ar->set_fade_out_active (yn);
5141 _session->add_command(new StatefulDiffCommand (ar));
5144 commit_reversible_command ();
5148 Editor::toggle_region_fades (int dir)
5150 boost::shared_ptr<AudioRegion> ar;
5153 RegionSelection rs = get_regions_from_selection_and_entered ();
5159 RegionSelection::iterator i;
5160 for (i = rs.begin(); i != rs.end(); ++i) {
5161 if ((ar = boost::dynamic_pointer_cast<AudioRegion>((*i)->region())) != 0) {
5163 yn = ar->fade_out_active ();
5165 yn = ar->fade_in_active ();
5171 if (i == rs.end()) {
5175 /* XXX should this undo-able? */
5177 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5178 if ((ar = boost::dynamic_pointer_cast<AudioRegion>((*i)->region())) == 0) {
5181 if (dir == 1 || dir == 0) {
5182 ar->set_fade_in_active (!yn);
5185 if (dir == -1 || dir == 0) {
5186 ar->set_fade_out_active (!yn);
5192 /** Update region fade visibility after its configuration has been changed */
5194 Editor::update_region_fade_visibility ()
5196 bool _fade_visibility = _session->config.get_show_region_fades ();
5198 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5199 AudioTimeAxisView* v = dynamic_cast<AudioTimeAxisView*>(*i);
5201 if (_fade_visibility) {
5202 v->audio_view()->show_all_fades ();
5204 v->audio_view()->hide_all_fades ();
5210 /** Update crossfade visibility after its configuration has been changed */
5212 Editor::update_xfade_visibility ()
5214 _xfade_visibility = _session->config.get_xfades_visible ();
5216 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5217 AudioTimeAxisView* v = dynamic_cast<AudioTimeAxisView*>(*i);
5219 if (_xfade_visibility) {
5220 v->show_all_xfades ();
5222 v->hide_all_xfades ();
5229 Editor::set_edit_point ()
5234 if (!mouse_frame (where, ignored)) {
5240 if (selection->markers.empty()) {
5242 mouse_add_new_marker (where);
5247 Location* loc = find_location_from_marker (selection->markers.front(), ignored);
5250 loc->move_to (where);
5256 Editor::set_playhead_cursor ()
5258 if (entered_marker) {
5259 _session->request_locate (entered_marker->position(), _session->transport_rolling());
5264 if (!mouse_frame (where, ignored)) {
5271 _session->request_locate (where, _session->transport_rolling());
5277 Editor::split_region ()
5279 if (((mouse_mode == MouseRange) ||
5280 (mouse_mode != MouseObject && _join_object_range_state == JOIN_OBJECT_RANGE_RANGE)) &&
5281 !selection->time.empty()) {
5282 separate_regions_between (selection->time);
5286 RegionSelection rs = get_regions_from_selection_and_edit_point ();
5288 framepos_t where = get_preferred_edit_position ();
5294 split_regions_at (where, rs);
5298 Editor::ensure_entered_track_selected (bool op_really_wants_one_track_if_none_are_selected)
5300 if (entered_track && mouse_mode == MouseObject) {
5301 if (!selection->tracks.empty()) {
5302 if (!selection->selected (entered_track)) {
5303 selection->add (entered_track);
5306 /* there is no selection, but this operation requires/prefers selected objects */
5308 if (op_really_wants_one_track_if_none_are_selected) {
5309 selection->set (entered_track);
5315 struct EditorOrderRouteSorter {
5316 bool operator() (boost::shared_ptr<Route> a, boost::shared_ptr<Route> b) {
5317 /* use of ">" forces the correct sort order */
5318 return a->order_key ("editor") < b->order_key ("editor");
5323 Editor::select_next_route()
5325 if (selection->tracks.empty()) {
5326 selection->set (track_views.front());
5330 TimeAxisView* current = selection->tracks.front();
5334 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5335 if (*i == current) {
5337 if (i != track_views.end()) {
5340 current = (*(track_views.begin()));
5341 //selection->set (*(track_views.begin()));
5346 rui = dynamic_cast<RouteUI *>(current);
5347 } while ( current->hidden() || (rui != NULL && !rui->route()->active()));
5349 selection->set(current);
5351 ensure_track_visible(current);
5355 Editor::select_prev_route()
5357 if (selection->tracks.empty()) {
5358 selection->set (track_views.front());
5362 TimeAxisView* current = selection->tracks.front();
5366 for (TrackViewList::reverse_iterator i = track_views.rbegin(); i != track_views.rend(); ++i) {
5367 if (*i == current) {
5369 if (i != track_views.rend()) {
5372 current = *(track_views.rbegin());
5377 rui = dynamic_cast<RouteUI *>(current);
5378 } while ( current->hidden() || (rui != NULL && !rui->route()->active()));
5380 selection->set (current);
5382 ensure_track_visible(current);
5386 Editor::ensure_track_visible(TimeAxisView *track)
5388 if (track->hidden())
5391 double const current_view_min_y = vertical_adjustment.get_value();
5392 double const current_view_max_y = vertical_adjustment.get_value() + vertical_adjustment.get_page_size() - canvas_timebars_vsize;
5394 double const track_min_y = track->y_position ();
5395 double const track_max_y = track->y_position () + track->effective_height ();
5397 if (track_min_y >= current_view_min_y &&
5398 track_max_y <= current_view_max_y) {
5404 if (track_min_y < current_view_min_y) {
5405 // Track is above the current view
5406 new_value = track_min_y;
5408 // Track is below the current view
5409 new_value = track->y_position () + track->effective_height() + canvas_timebars_vsize - vertical_adjustment.get_page_size();
5412 vertical_adjustment.set_value(new_value);
5416 Editor::set_loop_from_selection (bool play)
5418 if (_session == 0 || selection->time.empty()) {
5422 framepos_t start = selection->time[clicked_selection].start;
5423 framepos_t end = selection->time[clicked_selection].end;
5425 set_loop_range (start, end, _("set loop range from selection"));
5428 _session->request_play_loop (true);
5429 _session->request_locate (start, true);
5434 Editor::set_loop_from_edit_range (bool play)
5436 if (_session == 0) {
5443 if (!get_edit_op_range (start, end)) {
5447 set_loop_range (start, end, _("set loop range from edit range"));
5450 _session->request_play_loop (true);
5451 _session->request_locate (start, true);
5456 Editor::set_loop_from_region (bool play)
5458 framepos_t start = max_framepos;
5461 RegionSelection rs = get_regions_from_selection_and_entered ();
5467 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5468 if ((*i)->region()->position() < start) {
5469 start = (*i)->region()->position();
5471 if ((*i)->region()->last_frame() + 1 > end) {
5472 end = (*i)->region()->last_frame() + 1;
5476 set_loop_range (start, end, _("set loop range from region"));
5479 _session->request_play_loop (true);
5480 _session->request_locate (start, true);
5485 Editor::set_punch_from_selection ()
5487 if (_session == 0 || selection->time.empty()) {
5491 framepos_t start = selection->time[clicked_selection].start;
5492 framepos_t end = selection->time[clicked_selection].end;
5494 set_punch_range (start, end, _("set punch range from selection"));
5498 Editor::set_punch_from_edit_range ()
5500 if (_session == 0) {
5507 if (!get_edit_op_range (start, end)) {
5511 set_punch_range (start, end, _("set punch range from edit range"));
5515 Editor::set_punch_from_region ()
5517 framepos_t start = max_framepos;
5520 RegionSelection rs = get_regions_from_selection_and_entered ();
5526 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5527 if ((*i)->region()->position() < start) {
5528 start = (*i)->region()->position();
5530 if ((*i)->region()->last_frame() + 1 > end) {
5531 end = (*i)->region()->last_frame() + 1;
5535 set_punch_range (start, end, _("set punch range from region"));
5539 Editor::pitch_shift_region ()
5541 RegionSelection rs = get_regions_from_selection_and_entered ();
5543 RegionSelection audio_rs;
5544 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5545 if (dynamic_cast<AudioRegionView*> (*i)) {
5546 audio_rs.push_back (*i);
5550 if (audio_rs.empty()) {
5554 pitch_shift (audio_rs, 1.2);
5558 Editor::transpose_region ()
5560 RegionSelection rs = get_regions_from_selection_and_entered ();
5562 list<MidiRegionView*> midi_region_views;
5563 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5564 MidiRegionView* mrv = dynamic_cast<MidiRegionView*> (*i);
5566 midi_region_views.push_back (mrv);
5571 int const r = d.run ();
5572 if (r != RESPONSE_ACCEPT) {
5576 for (list<MidiRegionView*>::iterator i = midi_region_views.begin(); i != midi_region_views.end(); ++i) {
5577 (*i)->midi_region()->transpose (d.semitones ());
5582 Editor::set_tempo_from_region ()
5584 RegionSelection rs = get_regions_from_selection_and_entered ();
5586 if (!_session || rs.empty()) {
5590 RegionView* rv = rs.front();
5592 define_one_bar (rv->region()->position(), rv->region()->last_frame() + 1);
5596 Editor::use_range_as_bar ()
5598 framepos_t start, end;
5599 if (get_edit_op_range (start, end)) {
5600 define_one_bar (start, end);
5605 Editor::define_one_bar (framepos_t start, framepos_t end)
5607 framepos_t length = end - start;
5609 const Meter& m (_session->tempo_map().meter_at (start));
5611 /* length = 1 bar */
5613 /* now we want frames per beat.
5614 we have frames per bar, and beats per bar, so ...
5617 /* XXXX METER MATH */
5619 double frames_per_beat = length / m.divisions_per_bar();
5621 /* beats per minute = */
5623 double beats_per_minute = (_session->frame_rate() * 60.0) / frames_per_beat;
5625 /* now decide whether to:
5627 (a) set global tempo
5628 (b) add a new tempo marker
5632 const TempoSection& t (_session->tempo_map().tempo_section_at (start));
5634 bool do_global = false;
5636 if ((_session->tempo_map().n_tempos() == 1) && (_session->tempo_map().n_meters() == 1)) {
5638 /* only 1 tempo & 1 meter: ask if the user wants to set the tempo
5639 at the start, or create a new marker
5642 vector<string> options;
5643 options.push_back (_("Cancel"));
5644 options.push_back (_("Add new marker"));
5645 options.push_back (_("Set global tempo"));
5648 _("Define one bar"),
5649 _("Do you want to set the global tempo or add a new tempo marker?"),
5653 c.set_default_response (2);
5669 /* more than 1 tempo and/or meter section already, go ahead do the "usual":
5670 if the marker is at the region starter, change it, otherwise add
5675 begin_reversible_command (_("set tempo from region"));
5676 XMLNode& before (_session->tempo_map().get_state());
5679 _session->tempo_map().change_initial_tempo (beats_per_minute, t.note_type());
5680 } else if (t.frame() == start) {
5681 _session->tempo_map().change_existing_tempo_at (start, beats_per_minute, t.note_type());
5683 _session->tempo_map().add_tempo (Tempo (beats_per_minute, t.note_type()), start);
5686 XMLNode& after (_session->tempo_map().get_state());
5688 _session->add_command (new MementoCommand<TempoMap>(_session->tempo_map(), &before, &after));
5689 commit_reversible_command ();
5693 Editor::split_region_at_transients ()
5695 AnalysisFeatureList positions;
5697 RegionSelection rs = get_regions_from_selection_and_entered ();
5699 if (!_session || rs.empty()) {
5703 _session->begin_reversible_command (_("split regions"));
5705 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ) {
5707 RegionSelection::iterator tmp;
5712 boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion> ((*i)->region());
5714 if (ar && (ar->get_transients (positions) == 0)) {
5715 split_region_at_points ((*i)->region(), positions, true);
5722 _session->commit_reversible_command ();
5727 Editor::split_region_at_points (boost::shared_ptr<Region> r, AnalysisFeatureList& positions, bool can_ferret, bool select_new)
5729 bool use_rhythmic_rodent = false;
5731 boost::shared_ptr<Playlist> pl = r->playlist();
5733 list<boost::shared_ptr<Region> > new_regions;
5739 if (positions.empty()) {
5744 if (positions.size() > 20 && can_ferret) {
5745 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);
5746 MessageDialog msg (msgstr,
5749 Gtk::BUTTONS_OK_CANCEL);
5752 msg.add_button (_("Call for the Ferret!"), RESPONSE_APPLY);
5753 msg.set_secondary_text (_("Press OK to continue with this split operation\nor ask the Ferret dialog to tune the analysis"));
5755 msg.set_secondary_text (_("Press OK to continue with this split operation"));
5758 msg.set_title (_("Excessive split?"));
5761 int response = msg.run();
5767 case RESPONSE_APPLY:
5768 use_rhythmic_rodent = true;
5775 if (use_rhythmic_rodent) {
5776 show_rhythm_ferret ();
5780 AnalysisFeatureList::const_iterator x;
5782 pl->clear_changes ();
5783 pl->clear_owned_changes ();
5785 x = positions.begin();
5787 if (x == positions.end()) {
5792 pl->remove_region (r);
5796 while (x != positions.end()) {
5798 /* deal with positons that are out of scope of present region bounds */
5799 if (*x <= 0 || *x > r->length()) {
5804 /* file start = original start + how far we from the initial position ?
5807 framepos_t file_start = r->start() + pos;
5809 /* length = next position - current position
5812 framepos_t len = (*x) - pos;
5814 /* XXX we do we really want to allow even single-sample regions?
5815 shouldn't we have some kind of lower limit on region size?
5824 if (RegionFactory::region_name (new_name, r->name())) {
5828 /* do NOT announce new regions 1 by one, just wait till they are all done */
5832 plist.add (ARDOUR::Properties::start, file_start);
5833 plist.add (ARDOUR::Properties::length, len);
5834 plist.add (ARDOUR::Properties::name, new_name);
5835 plist.add (ARDOUR::Properties::layer, 0);
5837 boost::shared_ptr<Region> nr = RegionFactory::create (r->sources(), plist, false);
5839 pl->add_region (nr, r->position() + pos);
5842 new_regions.push_front(nr);
5851 RegionFactory::region_name (new_name, r->name());
5853 /* Add the final region */
5856 plist.add (ARDOUR::Properties::start, r->start() + pos);
5857 plist.add (ARDOUR::Properties::length, r->last_frame() - (r->position() + pos) + 1);
5858 plist.add (ARDOUR::Properties::name, new_name);
5859 plist.add (ARDOUR::Properties::layer, 0);
5861 boost::shared_ptr<Region> nr = RegionFactory::create (r->sources(), plist, false);
5862 pl->add_region (nr, r->position() + pos);
5865 new_regions.push_front(nr);
5870 /* We might have removed regions, which alters other regions' layering_index,
5871 so we need to do a recursive diff here.
5873 vector<Command*> cmds;
5875 _session->add_commands (cmds);
5877 _session->add_command (new StatefulDiffCommand (pl));
5881 for (list<boost::shared_ptr<Region> >::iterator i = new_regions.begin(); i != new_regions.end(); ++i){
5882 set_selected_regionview_from_region_list ((*i), Selection::Add);
5888 Editor::place_transient()
5894 RegionSelection rs = get_regions_from_selection_and_edit_point ();
5900 framepos_t where = get_preferred_edit_position();
5902 _session->begin_reversible_command (_("place transient"));
5904 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
5905 framepos_t position = (*r)->region()->position();
5906 (*r)->region()->add_transient(where - position);
5909 _session->commit_reversible_command ();
5913 Editor::remove_transient(ArdourCanvas::Item* item)
5919 ArdourCanvas::Line* _line = reinterpret_cast<ArdourCanvas::Line*> (item);
5922 AudioRegionView* _arv = reinterpret_cast<AudioRegionView*> (item->get_data ("regionview"));
5923 _arv->remove_transient (*(float*) _line->get_data ("position"));
5927 Editor::snap_regions_to_grid ()
5929 list <boost::shared_ptr<Playlist > > used_playlists;
5931 RegionSelection rs = get_regions_from_selection_and_entered ();
5933 if (!_session || rs.empty()) {
5937 _session->begin_reversible_command (_("snap regions to grid"));
5939 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
5941 boost::shared_ptr<Playlist> pl = (*r)->region()->playlist();
5943 if (!pl->frozen()) {
5944 /* we haven't seen this playlist before */
5946 /* remember used playlists so we can thaw them later */
5947 used_playlists.push_back(pl);
5951 framepos_t start_frame = (*r)->region()->first_frame ();
5952 snap_to (start_frame);
5953 (*r)->region()->set_position (start_frame);
5956 while (used_playlists.size() > 0) {
5957 list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
5959 used_playlists.pop_front();
5962 _session->commit_reversible_command ();
5966 Editor::close_region_gaps ()
5968 list <boost::shared_ptr<Playlist > > used_playlists;
5970 RegionSelection rs = get_regions_from_selection_and_entered ();
5972 if (!_session || rs.empty()) {
5976 Dialog dialog (_("Close Region Gaps"));
5979 table.set_spacings (12);
5980 table.set_border_width (12);
5981 Label* l = manage (new Label (_("Crossfade length")));
5982 l->set_alignment (0, 0.5);
5983 table.attach (*l, 0, 1, 0, 1);
5985 SpinButton spin_crossfade (1, 0);
5986 spin_crossfade.set_range (0, 15);
5987 spin_crossfade.set_increments (1, 1);
5988 spin_crossfade.set_value (5);
5989 table.attach (spin_crossfade, 1, 2, 0, 1);
5991 table.attach (*manage (new Label (_("ms"))), 2, 3, 0, 1);
5993 l = manage (new Label (_("Pull-back length")));
5994 l->set_alignment (0, 0.5);
5995 table.attach (*l, 0, 1, 1, 2);
5997 SpinButton spin_pullback (1, 0);
5998 spin_pullback.set_range (0, 100);
5999 spin_pullback.set_increments (1, 1);
6000 spin_pullback.set_value(30);
6001 table.attach (spin_pullback, 1, 2, 1, 2);
6003 table.attach (*manage (new Label (_("ms"))), 2, 3, 1, 2);
6005 dialog.get_vbox()->pack_start (table);
6006 dialog.add_button (Stock::CANCEL, RESPONSE_CANCEL);
6007 dialog.add_button (_("Ok"), RESPONSE_ACCEPT);
6010 if (dialog.run () == RESPONSE_CANCEL) {
6014 framepos_t crossfade_len = spin_crossfade.get_value();
6015 framepos_t pull_back_frames = spin_pullback.get_value();
6017 crossfade_len = lrintf (crossfade_len * _session->frame_rate()/1000);
6018 pull_back_frames = lrintf (pull_back_frames * _session->frame_rate()/1000);
6020 /* Iterate over the region list and make adjacent regions overlap by crossfade_len_ms */
6022 _session->begin_reversible_command (_("close region gaps"));
6025 boost::shared_ptr<Region> last_region;
6027 rs.sort_by_position_and_track();
6029 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6031 boost::shared_ptr<Playlist> pl = (*r)->region()->playlist();
6033 if (!pl->frozen()) {
6034 /* we haven't seen this playlist before */
6036 /* remember used playlists so we can thaw them later */
6037 used_playlists.push_back(pl);
6041 framepos_t position = (*r)->region()->position();
6043 if (idx == 0 || position < last_region->position()){
6044 last_region = (*r)->region();
6049 (*r)->region()->trim_front( (position - pull_back_frames));
6050 last_region->trim_end( (position - pull_back_frames + crossfade_len));
6052 last_region = (*r)->region();
6057 while (used_playlists.size() > 0) {
6058 list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
6060 used_playlists.pop_front();
6063 _session->commit_reversible_command ();
6067 Editor::tab_to_transient (bool forward)
6069 AnalysisFeatureList positions;
6071 RegionSelection rs = get_regions_from_selection_and_entered ();
6077 framepos_t pos = _session->audible_frame ();
6079 if (!selection->tracks.empty()) {
6081 /* don't waste time searching for transients in duplicate playlists.
6084 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
6086 for (TrackViewList::iterator t = ts.begin(); t != ts.end(); ++t) {
6088 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*t);
6091 boost::shared_ptr<Track> tr = rtv->track();
6093 boost::shared_ptr<Playlist> pl = tr->playlist ();
6095 framepos_t result = pl->find_next_transient (pos, forward ? 1 : -1);
6098 positions.push_back (result);
6111 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6112 (*r)->region()->get_transients (positions);
6116 TransientDetector::cleanup_transients (positions, _session->frame_rate(), 3.0);
6119 AnalysisFeatureList::iterator x;
6121 for (x = positions.begin(); x != positions.end(); ++x) {
6127 if (x != positions.end ()) {
6128 _session->request_locate (*x);
6132 AnalysisFeatureList::reverse_iterator x;
6134 for (x = positions.rbegin(); x != positions.rend(); ++x) {
6140 if (x != positions.rend ()) {
6141 _session->request_locate (*x);
6147 Editor::playhead_forward_to_grid ()
6149 if (!_session) return;
6150 framepos_t pos = playhead_cursor->current_frame;
6151 if (pos < max_framepos - 1) {
6153 snap_to_internal (pos, 1, false);
6154 _session->request_locate (pos);
6160 Editor::playhead_backward_to_grid ()
6162 if (!_session) return;
6163 framepos_t pos = playhead_cursor->current_frame;
6166 snap_to_internal (pos, -1, false);
6167 _session->request_locate (pos);
6172 Editor::set_track_height (Height h)
6174 TrackSelection& ts (selection->tracks);
6176 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
6177 (*x)->set_height_enum (h);
6182 Editor::toggle_tracks_active ()
6184 TrackSelection& ts (selection->tracks);
6186 bool target = false;
6192 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
6193 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*x);
6197 target = !rtv->_route->active();
6200 rtv->_route->set_active (target, this);
6206 Editor::remove_tracks ()
6208 TrackSelection& ts (selection->tracks);
6214 vector<string> choices;
6218 const char* trackstr;
6220 vector<boost::shared_ptr<Route> > routes;
6221 bool special_bus = false;
6223 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
6224 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*x);
6226 if (rtv->is_track()) {
6232 routes.push_back (rtv->_route);
6234 if (rtv->route()->is_master() || rtv->route()->is_monitor()) {
6239 if (special_bus && !Config->get_allow_special_bus_removal()) {
6240 MessageDialog msg (_("That would be bad news ...."),
6244 msg.set_secondary_text (string_compose (_(
6245 "Removing the master or monitor bus is such a bad idea\n\
6246 that %1 is not going to allow it.\n\
6248 If you really want to do this sort of thing\n\
6249 edit your ardour.rc file to set the\n\
6250 \"allow-special-bus-removal\" option to be \"yes\""), PROGRAM_NAME));
6257 if (ntracks + nbusses == 0) {
6262 trackstr = _("tracks");
6264 trackstr = _("track");
6268 busstr = _("busses");
6275 prompt = string_compose (_("Do you really want to remove %1 %2 and %3 %4?\n"
6276 "(You may also lose the playlists associated with the %2)\n\n"
6277 "This action cannot be undone, and the session file will be overwritten!"),
6278 ntracks, trackstr, nbusses, busstr);
6280 prompt = string_compose (_("Do you really want to remove %1 %2?\n"
6281 "(You may also lose the playlists associated with the %2)\n\n"
6282 "This action cannot be undone, and the session file will be overwritten!"),
6285 } else if (nbusses) {
6286 prompt = string_compose (_("Do you really want to remove %1 %2?\n\n"
6287 "This action cannot be undon, and the session file will be overwritten"),
6291 choices.push_back (_("No, do nothing."));
6292 if (ntracks + nbusses > 1) {
6293 choices.push_back (_("Yes, remove them."));
6295 choices.push_back (_("Yes, remove it."));
6300 title = string_compose (_("Remove %1"), trackstr);
6302 title = string_compose (_("Remove %1"), busstr);
6305 Choice prompter (title, prompt, choices);
6307 if (prompter.run () != 1) {
6311 for (vector<boost::shared_ptr<Route> >::iterator x = routes.begin(); x != routes.end(); ++x) {
6312 _session->remove_route (*x);
6317 Editor::do_insert_time ()
6319 if (selection->tracks.empty()) {
6323 InsertTimeDialog d (*this);
6324 int response = d.run ();
6326 if (response != RESPONSE_OK) {
6330 if (d.distance() == 0) {
6334 InsertTimeOption opt = d.intersected_region_action ();
6337 get_preferred_edit_position(),
6343 d.move_glued_markers(),
6344 d.move_locked_markers(),
6350 Editor::insert_time (
6351 framepos_t pos, framecnt_t frames, InsertTimeOption opt,
6352 bool all_playlists, bool ignore_music_glue, bool markers_too, bool glued_markers_too, bool locked_markers_too, bool tempo_too
6355 bool commit = false;
6357 if (Config->get_edit_mode() == Lock) {
6361 begin_reversible_command (_("insert time"));
6363 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
6365 for (TrackViewList::iterator x = ts.begin(); x != ts.end(); ++x) {
6369 /* don't operate on any playlist more than once, which could
6370 * happen if "all playlists" is enabled, but there is more
6371 * than 1 track using playlists "from" a given track.
6374 set<boost::shared_ptr<Playlist> > pl;
6376 if (all_playlists) {
6377 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*x);
6379 vector<boost::shared_ptr<Playlist> > all = _session->playlists->playlists_for_track (rtav->track ());
6380 for (vector<boost::shared_ptr<Playlist> >::iterator p = all.begin(); p != all.end(); ++p) {
6385 if ((*x)->playlist ()) {
6386 pl.insert ((*x)->playlist ());
6390 for (set<boost::shared_ptr<Playlist> >::iterator i = pl.begin(); i != pl.end(); ++i) {
6392 (*i)->clear_changes ();
6393 (*i)->clear_owned_changes ();
6395 if (opt == SplitIntersected) {
6399 (*i)->shift (pos, frames, (opt == MoveIntersected), ignore_music_glue);
6401 vector<Command*> cmds;
6403 _session->add_commands (cmds);
6405 _session->add_command (new StatefulDiffCommand (*i));
6410 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*x);
6412 rtav->route ()->shift (pos, frames);
6420 XMLNode& before (_session->locations()->get_state());
6421 Locations::LocationList copy (_session->locations()->list());
6423 for (Locations::LocationList::iterator i = copy.begin(); i != copy.end(); ++i) {
6425 Locations::LocationList::const_iterator tmp;
6427 bool const was_locked = (*i)->locked ();
6428 if (locked_markers_too) {
6432 if ((*i)->position_lock_style() == AudioTime || glued_markers_too) {
6434 if ((*i)->start() >= pos) {
6435 (*i)->set_start ((*i)->start() + frames);
6436 if (!(*i)->is_mark()) {
6437 (*i)->set_end ((*i)->end() + frames);
6450 XMLNode& after (_session->locations()->get_state());
6451 _session->add_command (new MementoCommand<Locations>(*_session->locations(), &before, &after));
6456 _session->tempo_map().insert_time (pos, frames);
6460 commit_reversible_command ();
6465 Editor::fit_selected_tracks ()
6467 if (!selection->tracks.empty()) {
6468 fit_tracks (selection->tracks);
6472 /* no selected tracks - use tracks with selected regions */
6474 if (!selection->regions.empty()) {
6475 for (RegionSelection::iterator r = selection->regions.begin(); r != selection->regions.end(); ++r) {
6476 tvl.push_back (&(*r)->get_time_axis_view ());
6482 } else if (internal_editing()) {
6483 /* no selected tracks, or regions, but in internal edit mode, so follow the mouse and use
6486 if (entered_track) {
6487 tvl.push_back (entered_track);
6495 Editor::fit_tracks (TrackViewList & tracks)
6497 if (tracks.empty()) {
6501 uint32_t child_heights = 0;
6502 int visible_tracks = 0;
6504 for (TrackSelection::iterator t = tracks.begin(); t != tracks.end(); ++t) {
6506 if (!(*t)->marked_for_display()) {
6510 child_heights += (*t)->effective_height() - (*t)->current_height();
6514 uint32_t h = (uint32_t) floor ((_canvas_height - child_heights - canvas_timebars_vsize) / visible_tracks);
6515 double first_y_pos = DBL_MAX;
6517 if (h < TimeAxisView::preset_height (HeightSmall)) {
6518 MessageDialog msg (*this, _("There are too many tracks to fit in the current window"));
6519 /* too small to be displayed */
6523 undo_visual_stack.push_back (current_visual_state (true));
6524 no_save_visual = true;
6526 /* build a list of all tracks, including children */
6529 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
6531 TimeAxisView::Children c = (*i)->get_child_list ();
6532 for (TimeAxisView::Children::iterator j = c.begin(); j != c.end(); ++j) {
6533 all.push_back (j->get());
6537 /* operate on all tracks, hide unselected ones that are in the middle of selected ones */
6539 bool prev_was_selected = false;
6540 bool is_selected = tracks.contains (all.front());
6541 bool next_is_selected;
6543 for (TrackViewList::iterator t = all.begin(); t != all.end(); ++t) {
6545 TrackViewList::iterator next;
6550 if (next != all.end()) {
6551 next_is_selected = tracks.contains (*next);
6553 next_is_selected = false;
6556 if ((*t)->marked_for_display ()) {
6558 (*t)->set_height (h);
6559 first_y_pos = std::min ((*t)->y_position (), first_y_pos);
6561 if (prev_was_selected && next_is_selected) {
6562 hide_track_in_display (*t);
6567 prev_was_selected = is_selected;
6568 is_selected = next_is_selected;
6572 set the controls_layout height now, because waiting for its size
6573 request signal handler will cause the vertical adjustment setting to fail
6576 controls_layout.property_height () = full_canvas_height - canvas_timebars_vsize;
6577 vertical_adjustment.set_value (first_y_pos);
6579 redo_visual_stack.push_back (current_visual_state (true));
6583 Editor::save_visual_state (uint32_t n)
6585 while (visual_states.size() <= n) {
6586 visual_states.push_back (0);
6589 if (visual_states[n] != 0) {
6590 delete visual_states[n];
6593 visual_states[n] = current_visual_state (true);
6598 Editor::goto_visual_state (uint32_t n)
6600 if (visual_states.size() <= n) {
6604 if (visual_states[n] == 0) {
6608 use_visual_state (*visual_states[n]);
6612 Editor::start_visual_state_op (uint32_t n)
6614 save_visual_state (n);
6616 PopUp* pup = new PopUp (WIN_POS_MOUSE, 1000, true);
6618 snprintf (buf, sizeof (buf), _("Saved view %u"), n+1);
6619 pup->set_text (buf);
6624 Editor::cancel_visual_state_op (uint32_t n)
6626 goto_visual_state (n);
6630 Editor::toggle_region_mute ()
6632 if (_ignore_region_action) {
6636 RegionSelection rs = get_regions_from_selection_and_entered ();
6642 if (rs.size() > 1) {
6643 begin_reversible_command (_("mute regions"));
6645 begin_reversible_command (_("mute region"));
6648 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
6650 (*i)->region()->playlist()->clear_changes ();
6651 (*i)->region()->set_muted (!(*i)->region()->muted ());
6652 _session->add_command (new StatefulDiffCommand ((*i)->region()->playlist()));
6656 commit_reversible_command ();
6660 Editor::combine_regions ()
6662 /* foreach track with selected regions, take all selected regions
6663 and join them into a new region containing the subregions (as a
6667 typedef set<RouteTimeAxisView*> RTVS;
6670 if (selection->regions.empty()) {
6674 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
6675 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(&(*i)->get_time_axis_view());
6678 tracks.insert (rtv);
6682 begin_reversible_command (_("combine regions"));
6684 vector<RegionView*> new_selection;
6686 for (RTVS::iterator i = tracks.begin(); i != tracks.end(); ++i) {
6689 if ((rv = (*i)->combine_regions ()) != 0) {
6690 new_selection.push_back (rv);
6694 selection->clear_regions ();
6695 for (vector<RegionView*>::iterator i = new_selection.begin(); i != new_selection.end(); ++i) {
6696 selection->add (*i);
6699 commit_reversible_command ();
6703 Editor::uncombine_regions ()
6705 typedef set<RouteTimeAxisView*> RTVS;
6708 if (selection->regions.empty()) {
6712 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
6713 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(&(*i)->get_time_axis_view());
6716 tracks.insert (rtv);
6720 begin_reversible_command (_("uncombine regions"));
6722 for (RTVS::iterator i = tracks.begin(); i != tracks.end(); ++i) {
6723 (*i)->uncombine_regions ();
6726 commit_reversible_command ();