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 _routes->suspend_redisplay ();
1285 if (selection->tracks.empty()) {
1288 ts = &selection->tracks;
1291 for (TrackViewList::iterator i = ts->begin(); i != ts->end(); ++i) {
1292 TimeAxisView *tv = (static_cast<TimeAxisView*>(*i));
1293 tv->step_height (coarser);
1296 _routes->resume_redisplay ();
1300 Editor::tav_zoom_smooth (bool coarser, bool force_all)
1302 _routes->suspend_redisplay ();
1306 if (selection->tracks.empty() || force_all) {
1309 ts = &selection->tracks;
1312 for (TrackViewList::iterator i = ts->begin(); i != ts->end(); ++i) {
1313 TimeAxisView *tv = (static_cast<TimeAxisView*>(*i));
1314 uint32_t h = tv->current_height ();
1319 if (h >= TimeAxisView::preset_height (HeightSmall)) {
1324 tv->set_height (h + 5);
1328 _routes->resume_redisplay ();
1332 Editor::temporal_zoom_step (bool coarser)
1334 ENSURE_GUI_THREAD (*this, &Editor::temporal_zoom_step, coarser)
1338 nfpu = frames_per_unit;
1343 nfpu = max(1.0,(nfpu/1.61803399));
1346 temporal_zoom (nfpu);
1350 Editor::temporal_zoom (gdouble fpu)
1352 if (!_session) return;
1354 framepos_t current_page = current_page_frames();
1355 framepos_t current_leftmost = leftmost_frame;
1356 framepos_t current_rightmost;
1357 framepos_t current_center;
1358 framepos_t new_page_size;
1359 framepos_t half_page_size;
1360 framepos_t leftmost_after_zoom = 0;
1362 bool in_track_canvas;
1366 /* XXX this limit is also in ::set_frames_per_unit() */
1368 if (frames_per_unit <= 1.0 && fpu <= frames_per_unit) {
1374 new_page_size = (framepos_t) floor (_canvas_width * nfpu);
1375 half_page_size = new_page_size / 2;
1377 switch (zoom_focus) {
1379 leftmost_after_zoom = current_leftmost;
1382 case ZoomFocusRight:
1383 current_rightmost = leftmost_frame + current_page;
1384 if (current_rightmost < new_page_size) {
1385 leftmost_after_zoom = 0;
1387 leftmost_after_zoom = current_rightmost - new_page_size;
1391 case ZoomFocusCenter:
1392 current_center = current_leftmost + (current_page/2);
1393 if (current_center < half_page_size) {
1394 leftmost_after_zoom = 0;
1396 leftmost_after_zoom = current_center - half_page_size;
1400 case ZoomFocusPlayhead:
1401 /* centre playhead */
1402 l = playhead_cursor->current_frame - (new_page_size * 0.5);
1405 leftmost_after_zoom = 0;
1406 } else if (l > max_framepos) {
1407 leftmost_after_zoom = max_framepos - new_page_size;
1409 leftmost_after_zoom = (framepos_t) l;
1413 case ZoomFocusMouse:
1414 /* try to keep the mouse over the same point in the display */
1416 if (!mouse_frame (where, in_track_canvas)) {
1417 /* use playhead instead */
1418 where = playhead_cursor->current_frame;
1420 if (where < half_page_size) {
1421 leftmost_after_zoom = 0;
1423 leftmost_after_zoom = where - half_page_size;
1428 l = - ((new_page_size * ((where - current_leftmost)/(double)current_page)) - where);
1431 leftmost_after_zoom = 0;
1432 } else if (l > max_framepos) {
1433 leftmost_after_zoom = max_framepos - new_page_size;
1435 leftmost_after_zoom = (framepos_t) l;
1442 /* try to keep the edit point in the same place */
1443 where = get_preferred_edit_position ();
1447 double l = - ((new_page_size * ((where - current_leftmost)/(double)current_page)) - where);
1450 leftmost_after_zoom = 0;
1451 } else if (l > max_framepos) {
1452 leftmost_after_zoom = max_framepos - new_page_size;
1454 leftmost_after_zoom = (framepos_t) l;
1458 /* edit point not defined */
1465 // leftmost_after_zoom = min (leftmost_after_zoom, _session->current_end_frame());
1467 reposition_and_zoom (leftmost_after_zoom, nfpu);
1471 Editor::temporal_zoom_region (bool both_axes)
1473 framepos_t start = max_framepos;
1475 set<TimeAxisView*> tracks;
1477 RegionSelection rs = get_regions_from_selection_and_entered ();
1483 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
1485 if ((*i)->region()->position() < start) {
1486 start = (*i)->region()->position();
1489 if ((*i)->region()->last_frame() + 1 > end) {
1490 end = (*i)->region()->last_frame() + 1;
1493 tracks.insert (&((*i)->get_time_axis_view()));
1496 /* now comes an "interesting" hack ... make sure we leave a little space
1497 at each end of the editor so that the zoom doesn't fit the region
1498 precisely to the screen.
1501 GdkScreen* screen = gdk_screen_get_default ();
1502 gint pixwidth = gdk_screen_get_width (screen);
1503 gint mmwidth = gdk_screen_get_width_mm (screen);
1504 double pix_per_mm = (double) pixwidth/ (double) mmwidth;
1505 double one_centimeter_in_pixels = pix_per_mm * 10.0;
1507 if ((start == 0 && end == 0) || end < start) {
1511 framepos_t range = end - start;
1512 double new_fpu = (double)range / (double)_canvas_width;
1513 framepos_t extra_samples = (framepos_t) floor (one_centimeter_in_pixels * new_fpu);
1515 if (start > extra_samples) {
1516 start -= extra_samples;
1521 if (max_framepos - extra_samples > end) {
1522 end += extra_samples;
1527 /* if we're zooming on both axes we need to save track heights etc.
1530 undo_visual_stack.push_back (current_visual_state (both_axes));
1532 PBD::Unwinder<bool> nsv (no_save_visual, true);
1534 temporal_zoom_by_frame (start, end);
1537 uint32_t per_track_height = (uint32_t) floor ((_canvas_height - canvas_timebars_vsize - 10.0) / tracks.size());
1539 /* set visible track heights appropriately */
1541 for (set<TimeAxisView*>::iterator t = tracks.begin(); t != tracks.end(); ++t) {
1542 (*t)->set_height (per_track_height);
1545 /* hide irrelevant tracks */
1547 _routes->suspend_redisplay ();
1549 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1550 if (find (tracks.begin(), tracks.end(), (*i)) == tracks.end()) {
1551 hide_track_in_display (*i);
1555 _routes->resume_redisplay ();
1557 vertical_adjustment.set_value (0.0);
1560 redo_visual_stack.push_back (current_visual_state (both_axes));
1564 Editor::zoom_to_region (bool both_axes)
1566 temporal_zoom_region (both_axes);
1570 Editor::temporal_zoom_selection ()
1572 if (!selection) return;
1574 if (selection->time.empty()) {
1578 framepos_t start = selection->time[clicked_selection].start;
1579 framepos_t end = selection->time[clicked_selection].end;
1581 temporal_zoom_by_frame (start, end);
1585 Editor::temporal_zoom_session ()
1587 ENSURE_GUI_THREAD (*this, &Editor::temporal_zoom_session)
1590 framecnt_t const l = _session->current_end_frame() - _session->current_start_frame();
1591 double s = _session->current_start_frame() - l * 0.01;
1595 framecnt_t const e = _session->current_end_frame() + l * 0.01;
1596 temporal_zoom_by_frame (framecnt_t (s), e);
1601 Editor::temporal_zoom_by_frame (framepos_t start, framepos_t end)
1603 if (!_session) return;
1605 if ((start == 0 && end == 0) || end < start) {
1609 framepos_t range = end - start;
1611 double new_fpu = (double)range / (double)_canvas_width;
1613 framepos_t new_page = (framepos_t) floor (_canvas_width * new_fpu);
1614 framepos_t middle = (framepos_t) floor( (double)start + ((double)range / 2.0f ));
1615 framepos_t new_leftmost = (framepos_t) floor( (double)middle - ((double)new_page/2.0f));
1617 if (new_leftmost > middle) {
1621 if (new_leftmost < 0) {
1625 reposition_and_zoom (new_leftmost, new_fpu);
1629 Editor::temporal_zoom_to_frame (bool coarser, framepos_t frame)
1634 double range_before = frame - leftmost_frame;
1637 new_fpu = frames_per_unit;
1640 new_fpu *= 1.61803399;
1641 range_before *= 1.61803399;
1643 new_fpu = max(1.0,(new_fpu/1.61803399));
1644 range_before /= 1.61803399;
1647 if (new_fpu == frames_per_unit) {
1651 framepos_t new_leftmost = frame - (framepos_t)range_before;
1653 if (new_leftmost > frame) {
1657 if (new_leftmost < 0) {
1661 reposition_and_zoom (new_leftmost, new_fpu);
1666 Editor::choose_new_marker_name(string &name) {
1668 if (!Config->get_name_new_markers()) {
1669 /* don't prompt user for a new name */
1673 ArdourPrompter dialog (true);
1675 dialog.set_prompt (_("New Name:"));
1677 dialog.set_title (_("New Location Marker"));
1679 dialog.set_name ("MarkNameWindow");
1680 dialog.set_size_request (250, -1);
1681 dialog.set_position (Gtk::WIN_POS_MOUSE);
1683 dialog.add_button (Stock::OK, RESPONSE_ACCEPT);
1684 dialog.set_initial_text (name);
1688 switch (dialog.run ()) {
1689 case RESPONSE_ACCEPT:
1695 dialog.get_result(name);
1702 Editor::add_location_from_selection ()
1706 if (selection->time.empty()) {
1710 if (_session == 0 || clicked_axisview == 0) {
1714 framepos_t start = selection->time[clicked_selection].start;
1715 framepos_t end = selection->time[clicked_selection].end;
1717 _session->locations()->next_available_name(rangename,"selection");
1718 Location *location = new Location (*_session, start, end, rangename, Location::IsRangeMarker);
1720 _session->begin_reversible_command (_("add marker"));
1721 XMLNode &before = _session->locations()->get_state();
1722 _session->locations()->add (location, true);
1723 XMLNode &after = _session->locations()->get_state();
1724 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
1725 _session->commit_reversible_command ();
1729 Editor::add_location_mark (framepos_t where)
1733 select_new_marker = true;
1735 _session->locations()->next_available_name(markername,"mark");
1736 if (!choose_new_marker_name(markername)) {
1739 Location *location = new Location (*_session, where, where, markername, Location::IsMark);
1740 _session->begin_reversible_command (_("add marker"));
1741 XMLNode &before = _session->locations()->get_state();
1742 _session->locations()->add (location, true);
1743 XMLNode &after = _session->locations()->get_state();
1744 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
1745 _session->commit_reversible_command ();
1749 Editor::add_location_from_playhead_cursor ()
1751 add_location_mark (_session->audible_frame());
1754 /** Add a range marker around each selected region */
1756 Editor::add_locations_from_region ()
1758 RegionSelection rs = get_regions_from_selection_and_entered ();
1764 _session->begin_reversible_command (selection->regions.size () > 1 ? _("add markers") : _("add marker"));
1765 XMLNode &before = _session->locations()->get_state();
1767 for (RegionSelection::iterator i = rs.begin (); i != rs.end (); ++i) {
1769 boost::shared_ptr<Region> region = (*i)->region ();
1771 Location *location = new Location (*_session, region->position(), region->last_frame(), region->name(), Location::IsRangeMarker);
1773 _session->locations()->add (location, true);
1776 XMLNode &after = _session->locations()->get_state();
1777 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
1778 _session->commit_reversible_command ();
1781 /** Add a single range marker around all selected regions */
1783 Editor::add_location_from_region ()
1785 RegionSelection rs = get_regions_from_selection_and_entered ();
1791 _session->begin_reversible_command (_("add marker"));
1792 XMLNode &before = _session->locations()->get_state();
1796 if (rs.size() > 1) {
1797 _session->locations()->next_available_name(markername, "regions");
1799 RegionView* rv = *(rs.begin());
1800 boost::shared_ptr<Region> region = rv->region();
1801 markername = region->name();
1804 if (!choose_new_marker_name(markername)) {
1808 // single range spanning all selected
1809 Location *location = new Location (*_session, selection->regions.start(), selection->regions.end_frame(), markername, Location::IsRangeMarker);
1810 _session->locations()->add (location, true);
1812 XMLNode &after = _session->locations()->get_state();
1813 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
1814 _session->commit_reversible_command ();
1820 Editor::jump_forward_to_mark ()
1826 Location *location = _session->locations()->first_location_after (playhead_cursor->current_frame);
1829 _session->request_locate (location->start(), _session->transport_rolling());
1831 _session->request_locate (_session->current_end_frame());
1836 Editor::jump_backward_to_mark ()
1842 Location *location = _session->locations()->first_location_before (playhead_cursor->current_frame);
1845 _session->request_locate (location->start(), _session->transport_rolling());
1847 _session->goto_start ();
1854 framepos_t const pos = _session->audible_frame ();
1857 _session->locations()->next_available_name (markername, "mark");
1859 if (!choose_new_marker_name (markername)) {
1863 _session->locations()->add (new Location (*_session, pos, 0, markername, Location::IsMark), true);
1867 Editor::clear_markers ()
1870 _session->begin_reversible_command (_("clear markers"));
1871 XMLNode &before = _session->locations()->get_state();
1872 _session->locations()->clear_markers ();
1873 XMLNode &after = _session->locations()->get_state();
1874 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
1875 _session->commit_reversible_command ();
1880 Editor::clear_ranges ()
1883 _session->begin_reversible_command (_("clear ranges"));
1884 XMLNode &before = _session->locations()->get_state();
1886 Location * looploc = _session->locations()->auto_loop_location();
1887 Location * punchloc = _session->locations()->auto_punch_location();
1888 Location * sessionloc = _session->locations()->session_range_location();
1890 _session->locations()->clear_ranges ();
1892 if (looploc) _session->locations()->add (looploc);
1893 if (punchloc) _session->locations()->add (punchloc);
1894 if (sessionloc) _session->locations()->add (sessionloc);
1896 XMLNode &after = _session->locations()->get_state();
1897 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
1898 _session->commit_reversible_command ();
1903 Editor::clear_locations ()
1905 _session->begin_reversible_command (_("clear locations"));
1906 XMLNode &before = _session->locations()->get_state();
1907 _session->locations()->clear ();
1908 XMLNode &after = _session->locations()->get_state();
1909 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
1910 _session->commit_reversible_command ();
1911 _session->locations()->clear ();
1915 Editor::unhide_markers ()
1917 for (LocationMarkerMap::iterator i = location_markers.begin(); i != location_markers.end(); ++i) {
1918 Location *l = (*i).first;
1919 if (l->is_hidden() && l->is_mark()) {
1920 l->set_hidden(false, this);
1926 Editor::unhide_ranges ()
1928 for (LocationMarkerMap::iterator i = location_markers.begin(); i != location_markers.end(); ++i) {
1929 Location *l = (*i).first;
1930 if (l->is_hidden() && l->is_range_marker()) {
1931 l->set_hidden(false, this);
1936 /* INSERT/REPLACE */
1939 Editor::insert_region_list_drag (boost::shared_ptr<Region> region, int x, int y)
1944 RouteTimeAxisView *rtv = 0;
1945 boost::shared_ptr<Playlist> playlist;
1947 track_canvas->window_to_world (x, y, wx, wy);
1950 event.type = GDK_BUTTON_RELEASE;
1951 event.button.x = wx;
1952 event.button.y = wy;
1954 where = event_frame (&event, &cx, &cy);
1956 if (where < leftmost_frame || where > leftmost_frame + current_page_frames()) {
1957 /* clearly outside canvas area */
1961 std::pair<TimeAxisView*, int> tv = trackview_by_y_position (cy);
1962 if (tv.first == 0) {
1966 if ((rtv = dynamic_cast<RouteTimeAxisView*> (tv.first)) == 0) {
1970 if ((playlist = rtv->playlist()) == 0) {
1976 begin_reversible_command (_("insert dragged region"));
1977 playlist->clear_changes ();
1978 playlist->add_region (RegionFactory::create (region, true), where, 1.0);
1979 _session->add_command(new StatefulDiffCommand (playlist));
1980 commit_reversible_command ();
1984 Editor::insert_route_list_drag (boost::shared_ptr<Route> route, int x, int y)
1988 RouteTimeAxisView *dest_rtv = 0;
1989 RouteTimeAxisView *source_rtv = 0;
1991 track_canvas->window_to_world (x, y, wx, wy);
1992 wx += horizontal_position ();
1993 wy += vertical_adjustment.get_value();
1996 event.type = GDK_BUTTON_RELEASE;
1997 event.button.x = wx;
1998 event.button.y = wy;
2000 event_frame (&event, &cx, &cy);
2002 std::pair<TimeAxisView*, int> const tv = trackview_by_y_position (cy);
2003 if (tv.first == 0) {
2007 if ((dest_rtv = dynamic_cast<RouteTimeAxisView*> (tv.first)) == 0) {
2011 /* use this drag source to add underlay to a track. But we really don't care
2012 about the Route, only the view of the route, so find it first */
2013 for(TrackViewList::iterator it = track_views.begin(); it != track_views.end(); ++it) {
2014 if((source_rtv = dynamic_cast<RouteTimeAxisView*>(*it)) == 0) {
2018 if(source_rtv->route() == route && source_rtv != dest_rtv) {
2019 dest_rtv->add_underlay(source_rtv->view());
2026 Editor::insert_region_list_selection (float times)
2028 RouteTimeAxisView *tv = 0;
2029 boost::shared_ptr<Playlist> playlist;
2031 if (clicked_routeview != 0) {
2032 tv = clicked_routeview;
2033 } else if (!selection->tracks.empty()) {
2034 if ((tv = dynamic_cast<RouteTimeAxisView*>(selection->tracks.front())) == 0) {
2037 } else if (entered_track != 0) {
2038 if ((tv = dynamic_cast<RouteTimeAxisView*>(entered_track)) == 0) {
2045 if ((playlist = tv->playlist()) == 0) {
2049 boost::shared_ptr<Region> region = _regions->get_single_selection ();
2054 begin_reversible_command (_("insert region"));
2055 playlist->clear_changes ();
2056 playlist->add_region ((RegionFactory::create (region, true)), get_preferred_edit_position(), times);
2057 _session->add_command(new StatefulDiffCommand (playlist));
2058 commit_reversible_command ();
2061 /* BUILT-IN EFFECTS */
2064 Editor::reverse_selection ()
2069 /* GAIN ENVELOPE EDITING */
2072 Editor::edit_envelope ()
2079 Editor::transition_to_rolling (bool fwd)
2085 if (_session->config.get_external_sync()) {
2086 switch (_session->config.get_sync_source()) {
2090 /* transport controlled by the master */
2095 if (_session->is_auditioning()) {
2096 _session->cancel_audition ();
2100 _session->request_transport_speed (fwd ? 1.0f : -1.0f);
2104 Editor::play_from_start ()
2106 _session->request_locate (_session->current_start_frame(), true);
2110 Editor::play_from_edit_point ()
2112 _session->request_locate (get_preferred_edit_position(), true);
2116 Editor::play_from_edit_point_and_return ()
2118 framepos_t start_frame;
2119 framepos_t return_frame;
2121 start_frame = get_preferred_edit_position (true);
2123 if (_session->transport_rolling()) {
2124 _session->request_locate (start_frame, false);
2128 /* don't reset the return frame if its already set */
2130 if ((return_frame = _session->requested_return_frame()) < 0) {
2131 return_frame = _session->audible_frame();
2134 if (start_frame >= 0) {
2135 _session->request_roll_at_and_return (start_frame, return_frame);
2140 Editor::play_selection ()
2142 if (selection->time.empty()) {
2146 _session->request_play_range (&selection->time, true);
2150 Editor::play_location (Location& location)
2152 if (location.start() <= location.end()) {
2156 _session->request_bounded_roll (location.start(), location.end());
2160 Editor::loop_location (Location& location)
2162 if (location.start() <= location.end()) {
2168 if ((tll = transport_loop_location()) != 0) {
2169 tll->set (location.start(), location.end());
2171 // enable looping, reposition and start rolling
2172 _session->request_play_loop (true);
2173 _session->request_locate (tll->start(), true);
2178 Editor::do_layer_operation (LayerOperation op)
2180 if (selection->regions.empty ()) {
2184 bool const multiple = selection->regions.size() > 1;
2188 begin_reversible_command (_("raise regions"));
2190 begin_reversible_command (_("raise region"));
2196 begin_reversible_command (_("raise regions to top"));
2198 begin_reversible_command (_("raise region to top"));
2204 begin_reversible_command (_("lower regions"));
2206 begin_reversible_command (_("lower region"));
2212 begin_reversible_command (_("lower regions to bottom"));
2214 begin_reversible_command (_("lower region"));
2219 set<boost::shared_ptr<Playlist> > playlists = selection->regions.playlists ();
2220 for (set<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
2221 (*i)->clear_owned_changes ();
2224 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
2225 boost::shared_ptr<Region> r = (*i)->region ();
2237 r->lower_to_bottom ();
2241 for (set<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
2242 vector<Command*> cmds;
2244 _session->add_commands (cmds);
2247 commit_reversible_command ();
2251 Editor::raise_region ()
2253 do_layer_operation (Raise);
2257 Editor::raise_region_to_top ()
2259 do_layer_operation (RaiseToTop);
2263 Editor::lower_region ()
2265 do_layer_operation (Lower);
2269 Editor::lower_region_to_bottom ()
2271 do_layer_operation (LowerToBottom);
2274 /** Show the region editor for the selected regions */
2276 Editor::show_region_properties ()
2278 selection->foreach_regionview (&RegionView::show_region_editor);
2281 /** Show the midi list editor for the selected MIDI regions */
2283 Editor::show_midi_list_editor ()
2285 selection->foreach_midi_regionview (&MidiRegionView::show_list_editor);
2289 Editor::rename_region ()
2291 RegionSelection rs = get_regions_from_selection_and_entered ();
2297 ArdourDialog d (*this, _("Rename Region"), true, false);
2299 Label label (_("New name:"));
2302 hbox.set_spacing (6);
2303 hbox.pack_start (label, false, false);
2304 hbox.pack_start (entry, true, true);
2306 d.get_vbox()->set_border_width (12);
2307 d.get_vbox()->pack_start (hbox, false, false);
2309 d.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
2310 d.add_button(Gtk::Stock::OK, Gtk::RESPONSE_OK);
2312 d.set_size_request (300, -1);
2313 d.set_position (Gtk::WIN_POS_MOUSE);
2315 entry.set_text (rs.front()->region()->name());
2316 entry.select_region (0, -1);
2318 entry.signal_activate().connect (sigc::bind (sigc::mem_fun (d, &Dialog::response), RESPONSE_OK));
2324 int const ret = d.run();
2328 if (ret != RESPONSE_OK) {
2332 std::string str = entry.get_text();
2333 strip_whitespace_edges (str);
2335 rs.front()->region()->set_name (str);
2336 _regions->redisplay ();
2341 Editor::audition_playlist_region_via_route (boost::shared_ptr<Region> region, Route& route)
2343 if (_session->is_auditioning()) {
2344 _session->cancel_audition ();
2347 // note: some potential for creativity here, because region doesn't
2348 // have to belong to the playlist that Route is handling
2350 // bool was_soloed = route.soloed();
2352 route.set_solo (true, this);
2354 _session->request_bounded_roll (region->position(), region->position() + region->length());
2356 /* XXX how to unset the solo state ? */
2359 /** Start an audition of the first selected region */
2361 Editor::play_edit_range ()
2363 framepos_t start, end;
2365 if (get_edit_op_range (start, end)) {
2366 _session->request_bounded_roll (start, end);
2371 Editor::play_selected_region ()
2373 framepos_t start = max_framepos;
2376 RegionSelection rs = get_regions_from_selection_and_entered ();
2382 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
2383 if ((*i)->region()->position() < start) {
2384 start = (*i)->region()->position();
2386 if ((*i)->region()->last_frame() + 1 > end) {
2387 end = (*i)->region()->last_frame() + 1;
2391 _session->request_bounded_roll (start, end);
2395 Editor::audition_playlist_region_standalone (boost::shared_ptr<Region> region)
2397 _session->audition_region (region);
2401 Editor::region_from_selection ()
2403 if (clicked_axisview == 0) {
2407 if (selection->time.empty()) {
2411 framepos_t start = selection->time[clicked_selection].start;
2412 framepos_t end = selection->time[clicked_selection].end;
2414 TrackViewList tracks = get_tracks_for_range_action ();
2416 framepos_t selection_cnt = end - start + 1;
2418 for (TrackSelection::iterator i = tracks.begin(); i != tracks.end(); ++i) {
2419 boost::shared_ptr<Region> current;
2420 boost::shared_ptr<Playlist> pl;
2421 framepos_t internal_start;
2424 if ((pl = (*i)->playlist()) == 0) {
2428 if ((current = pl->top_region_at (start)) == 0) {
2432 internal_start = start - current->position();
2433 RegionFactory::region_name (new_name, current->name(), true);
2437 plist.add (ARDOUR::Properties::start, current->start() + internal_start);
2438 plist.add (ARDOUR::Properties::length, selection_cnt);
2439 plist.add (ARDOUR::Properties::name, new_name);
2440 plist.add (ARDOUR::Properties::layer, 0);
2442 boost::shared_ptr<Region> region (RegionFactory::create (current, plist));
2447 Editor::create_region_from_selection (vector<boost::shared_ptr<Region> >& new_regions)
2449 if (selection->time.empty() || selection->tracks.empty()) {
2453 framepos_t start = selection->time[clicked_selection].start;
2454 framepos_t end = selection->time[clicked_selection].end;
2456 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
2457 sort_track_selection (ts);
2459 for (TrackSelection::iterator i = ts.begin(); i != ts.end(); ++i) {
2460 boost::shared_ptr<Region> current;
2461 boost::shared_ptr<Playlist> playlist;
2462 framepos_t internal_start;
2465 if ((playlist = (*i)->playlist()) == 0) {
2469 if ((current = playlist->top_region_at(start)) == 0) {
2473 internal_start = start - current->position();
2474 RegionFactory::region_name (new_name, current->name(), true);
2478 plist.add (ARDOUR::Properties::start, current->start() + internal_start);
2479 plist.add (ARDOUR::Properties::length, end - start + 1);
2480 plist.add (ARDOUR::Properties::name, new_name);
2482 new_regions.push_back (RegionFactory::create (current, plist));
2487 Editor::split_multichannel_region ()
2489 RegionSelection rs = get_regions_from_selection_and_entered ();
2495 vector< boost::shared_ptr<Region> > v;
2497 for (list<RegionView*>::iterator x = rs.begin(); x != rs.end(); ++x) {
2498 (*x)->region()->separate_by_channel (*_session, v);
2503 Editor::new_region_from_selection ()
2505 region_from_selection ();
2506 cancel_selection ();
2510 add_if_covered (RegionView* rv, const AudioRange* ar, RegionSelection* rs)
2512 switch (rv->region()->coverage (ar->start, ar->end - 1)) {
2513 case Evoral::OverlapNone:
2521 * - selected tracks, or if there are none...
2522 * - tracks containing selected regions, or if there are none...
2527 Editor::get_tracks_for_range_action () const
2531 if (selection->tracks.empty()) {
2533 /* use tracks with selected regions */
2535 RegionSelection rs = selection->regions;
2537 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
2538 TimeAxisView* tv = &(*i)->get_time_axis_view();
2540 if (!t.contains (tv)) {
2546 /* no regions and no tracks: use all tracks */
2552 t = selection->tracks;
2555 return t.filter_to_unique_playlists();
2559 Editor::separate_regions_between (const TimeSelection& ts)
2561 bool in_command = false;
2562 boost::shared_ptr<Playlist> playlist;
2563 RegionSelection new_selection;
2565 TrackViewList tmptracks = get_tracks_for_range_action ();
2566 sort_track_selection (tmptracks);
2568 for (TrackSelection::iterator i = tmptracks.begin(); i != tmptracks.end(); ++i) {
2570 RouteTimeAxisView* rtv;
2572 if ((rtv = dynamic_cast<RouteTimeAxisView*> ((*i))) != 0) {
2574 if (rtv->is_track()) {
2576 /* no edits to destructive tracks */
2578 if (rtv->track()->destructive()) {
2582 if ((playlist = rtv->playlist()) != 0) {
2584 playlist->clear_changes ();
2586 /* XXX need to consider musical time selections here at some point */
2588 double speed = rtv->track()->speed();
2591 for (list<AudioRange>::const_iterator t = ts.begin(); t != ts.end(); ++t) {
2593 sigc::connection c = rtv->view()->RegionViewAdded.connect (
2594 sigc::mem_fun(*this, &Editor::collect_new_region_view));
2596 latest_regionviews.clear ();
2598 playlist->partition ((framepos_t)((*t).start * speed),
2599 (framepos_t)((*t).end * speed), false);
2603 if (!latest_regionviews.empty()) {
2605 rtv->view()->foreach_regionview (sigc::bind (
2606 sigc::ptr_fun (add_if_covered),
2607 &(*t), &new_selection));
2610 begin_reversible_command (_("separate"));
2614 /* pick up changes to existing regions */
2616 vector<Command*> cmds;
2617 playlist->rdiff (cmds);
2618 _session->add_commands (cmds);
2620 /* pick up changes to the playlist itself (adds/removes)
2623 _session->add_command(new StatefulDiffCommand (playlist));
2632 selection->set (new_selection);
2633 set_mouse_mode (MouseObject);
2635 commit_reversible_command ();
2639 struct PlaylistState {
2640 boost::shared_ptr<Playlist> playlist;
2644 /** Take tracks from get_tracks_for_range_action and cut any regions
2645 * on those tracks so that the tracks are empty over the time
2649 Editor::separate_region_from_selection ()
2651 /* preferentially use *all* ranges in the time selection if we're in range mode
2652 to allow discontiguous operation, since get_edit_op_range() currently
2653 returns a single range.
2656 if (mouse_mode == MouseRange && !selection->time.empty()) {
2658 separate_regions_between (selection->time);
2665 if (get_edit_op_range (start, end)) {
2667 AudioRange ar (start, end, 1);
2671 separate_regions_between (ts);
2677 Editor::separate_region_from_punch ()
2679 Location* loc = _session->locations()->auto_punch_location();
2681 separate_regions_using_location (*loc);
2686 Editor::separate_region_from_loop ()
2688 Location* loc = _session->locations()->auto_loop_location();
2690 separate_regions_using_location (*loc);
2695 Editor::separate_regions_using_location (Location& loc)
2697 if (loc.is_mark()) {
2701 AudioRange ar (loc.start(), loc.end(), 1);
2706 separate_regions_between (ts);
2709 /** Separate regions under the selected region */
2711 Editor::separate_under_selected_regions ()
2713 vector<PlaylistState> playlists;
2717 rs = get_regions_from_selection_and_entered();
2719 if (!_session || rs.empty()) {
2723 begin_reversible_command (_("separate region under"));
2725 list<boost::shared_ptr<Region> > regions_to_remove;
2727 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
2728 // we can't just remove the region(s) in this loop because
2729 // this removes them from the RegionSelection, and they thus
2730 // disappear from underneath the iterator, and the ++i above
2731 // SEGVs in a puzzling fashion.
2733 // so, first iterate over the regions to be removed from rs and
2734 // add them to the regions_to_remove list, and then
2735 // iterate over the list to actually remove them.
2737 regions_to_remove.push_back ((*i)->region());
2740 for (list<boost::shared_ptr<Region> >::iterator rl = regions_to_remove.begin(); rl != regions_to_remove.end(); ++rl) {
2742 boost::shared_ptr<Playlist> playlist = (*rl)->playlist();
2745 // is this check necessary?
2749 vector<PlaylistState>::iterator i;
2751 //only take state if this is a new playlist.
2752 for (i = playlists.begin(); i != playlists.end(); ++i) {
2753 if ((*i).playlist == playlist) {
2758 if (i == playlists.end()) {
2760 PlaylistState before;
2761 before.playlist = playlist;
2762 before.before = &playlist->get_state();
2764 playlist->freeze ();
2765 playlists.push_back(before);
2768 //Partition on the region bounds
2769 playlist->partition ((*rl)->first_frame() - 1, (*rl)->last_frame() + 1, true);
2771 //Re-add region that was just removed due to the partition operation
2772 playlist->add_region( (*rl), (*rl)->first_frame() );
2775 vector<PlaylistState>::iterator pl;
2777 for (pl = playlists.begin(); pl != playlists.end(); ++pl) {
2778 (*pl).playlist->thaw ();
2779 _session->add_command(new MementoCommand<Playlist>(*(*pl).playlist, (*pl).before, &(*pl).playlist->get_state()));
2782 commit_reversible_command ();
2786 Editor::crop_region_to_selection ()
2788 if (!selection->time.empty()) {
2790 crop_region_to (selection->time.start(), selection->time.end_frame());
2797 if (get_edit_op_range (start, end)) {
2798 crop_region_to (start, end);
2805 Editor::crop_region_to (framepos_t start, framepos_t end)
2807 vector<boost::shared_ptr<Playlist> > playlists;
2808 boost::shared_ptr<Playlist> playlist;
2811 if (selection->tracks.empty()) {
2812 ts = track_views.filter_to_unique_playlists();
2814 ts = selection->tracks.filter_to_unique_playlists ();
2817 sort_track_selection (ts);
2819 for (TrackSelection::iterator i = ts.begin(); i != ts.end(); ++i) {
2821 RouteTimeAxisView* rtv;
2823 if ((rtv = dynamic_cast<RouteTimeAxisView*> ((*i))) != 0) {
2825 boost::shared_ptr<Track> t = rtv->track();
2827 if (t != 0 && ! t->destructive()) {
2829 if ((playlist = rtv->playlist()) != 0) {
2830 playlists.push_back (playlist);
2836 if (playlists.empty()) {
2840 framepos_t the_start;
2844 begin_reversible_command (_("trim to selection"));
2846 for (vector<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
2848 boost::shared_ptr<Region> region;
2852 if ((region = (*i)->top_region_at(the_start)) == 0) {
2856 /* now adjust lengths to that we do the right thing
2857 if the selection extends beyond the region
2860 the_start = max (the_start, (framepos_t) region->position());
2861 if (max_framepos - the_start < region->length()) {
2862 the_end = the_start + region->length() - 1;
2864 the_end = max_framepos;
2866 the_end = min (end, the_end);
2867 cnt = the_end - the_start + 1;
2869 region->clear_changes ();
2870 region->trim_to (the_start, cnt);
2871 _session->add_command (new StatefulDiffCommand (region));
2874 commit_reversible_command ();
2878 Editor::region_fill_track ()
2880 RegionSelection rs = get_regions_from_selection_and_entered ();
2882 if (!_session || rs.empty()) {
2886 framepos_t const end = _session->current_end_frame ();
2888 begin_reversible_command (Operations::region_fill);
2890 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
2892 boost::shared_ptr<Region> region ((*i)->region());
2894 boost::shared_ptr<Playlist> pl = region->playlist();
2896 if (end <= region->last_frame()) {
2900 double times = (double) (end - region->last_frame()) / (double) region->length();
2906 pl->clear_changes ();
2907 pl->add_region (RegionFactory::create (region, true), region->last_frame(), times);
2908 _session->add_command (new StatefulDiffCommand (pl));
2911 commit_reversible_command ();
2915 Editor::region_fill_selection ()
2917 if (clicked_routeview == 0 || !clicked_routeview->is_audio_track()) {
2921 if (selection->time.empty()) {
2925 boost::shared_ptr<Region> region = _regions->get_single_selection ();
2930 framepos_t start = selection->time[clicked_selection].start;
2931 framepos_t end = selection->time[clicked_selection].end;
2933 boost::shared_ptr<Playlist> playlist;
2935 if (selection->tracks.empty()) {
2939 framepos_t selection_length = end - start;
2940 float times = (float)selection_length / region->length();
2942 begin_reversible_command (Operations::fill_selection);
2944 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
2946 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
2948 if ((playlist = (*i)->playlist()) == 0) {
2952 playlist->clear_changes ();
2953 playlist->add_region (RegionFactory::create (region, true), start, times);
2954 _session->add_command (new StatefulDiffCommand (playlist));
2957 commit_reversible_command ();
2961 Editor::set_region_sync_position ()
2963 set_sync_point (get_preferred_edit_position (), get_regions_from_selection_and_edit_point ());
2967 Editor::set_sync_point (framepos_t where, const RegionSelection& rs)
2969 bool in_command = false;
2971 for (RegionSelection::const_iterator r = rs.begin(); r != rs.end(); ++r) {
2973 if (!(*r)->region()->covers (where)) {
2977 boost::shared_ptr<Region> region ((*r)->region());
2980 begin_reversible_command (_("set sync point"));
2984 region->clear_changes ();
2985 region->set_sync_position (where);
2986 _session->add_command(new StatefulDiffCommand (region));
2990 commit_reversible_command ();
2994 /** Remove the sync positions of the selection */
2996 Editor::remove_region_sync ()
2998 RegionSelection rs = get_regions_from_selection_and_entered ();
3004 begin_reversible_command (_("remove region sync"));
3006 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3008 (*i)->region()->clear_changes ();
3009 (*i)->region()->clear_sync_position ();
3010 _session->add_command(new StatefulDiffCommand ((*i)->region()));
3013 commit_reversible_command ();
3017 Editor::naturalize_region ()
3019 RegionSelection rs = get_regions_from_selection_and_entered ();
3025 if (rs.size() > 1) {
3026 begin_reversible_command (_("move regions to original position"));
3028 begin_reversible_command (_("move region to original position"));
3031 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3032 (*i)->region()->clear_changes ();
3033 (*i)->region()->move_to_natural_position ();
3034 _session->add_command (new StatefulDiffCommand ((*i)->region()));
3037 commit_reversible_command ();
3041 Editor::align_regions (RegionPoint what)
3043 RegionSelection const rs = get_regions_from_selection_and_edit_point ();
3049 begin_reversible_command (_("align selection"));
3051 framepos_t const position = get_preferred_edit_position ();
3053 for (RegionSelection::const_iterator i = rs.begin(); i != rs.end(); ++i) {
3054 align_region_internal ((*i)->region(), what, position);
3057 commit_reversible_command ();
3060 struct RegionSortByTime {
3061 bool operator() (const RegionView* a, const RegionView* b) {
3062 return a->region()->position() < b->region()->position();
3067 Editor::align_regions_relative (RegionPoint point)
3069 RegionSelection const rs = get_regions_from_selection_and_edit_point ();
3075 framepos_t const position = get_preferred_edit_position ();
3077 framepos_t distance = 0;
3081 list<RegionView*> sorted;
3082 rs.by_position (sorted);
3084 boost::shared_ptr<Region> r ((*sorted.begin())->region());
3089 if (position > r->position()) {
3090 distance = position - r->position();
3092 distance = r->position() - position;
3098 if (position > r->last_frame()) {
3099 distance = position - r->last_frame();
3100 pos = r->position() + distance;
3102 distance = r->last_frame() - position;
3103 pos = r->position() - distance;
3109 pos = r->adjust_to_sync (position);
3110 if (pos > r->position()) {
3111 distance = pos - r->position();
3113 distance = r->position() - pos;
3119 if (pos == r->position()) {
3123 begin_reversible_command (_("align selection (relative)"));
3125 /* move first one specially */
3127 r->clear_changes ();
3128 r->set_position (pos);
3129 _session->add_command(new StatefulDiffCommand (r));
3131 /* move rest by the same amount */
3135 for (list<RegionView*>::iterator i = sorted.begin(); i != sorted.end(); ++i) {
3137 boost::shared_ptr<Region> region ((*i)->region());
3139 region->clear_changes ();
3142 region->set_position (region->position() + distance);
3144 region->set_position (region->position() - distance);
3147 _session->add_command(new StatefulDiffCommand (region));
3151 commit_reversible_command ();
3155 Editor::align_region (boost::shared_ptr<Region> region, RegionPoint point, framepos_t position)
3157 begin_reversible_command (_("align region"));
3158 align_region_internal (region, point, position);
3159 commit_reversible_command ();
3163 Editor::align_region_internal (boost::shared_ptr<Region> region, RegionPoint point, framepos_t position)
3165 region->clear_changes ();
3169 region->set_position (region->adjust_to_sync (position));
3173 if (position > region->length()) {
3174 region->set_position (position - region->length());
3179 region->set_position (position);
3183 _session->add_command(new StatefulDiffCommand (region));
3187 Editor::trim_region_front ()
3193 Editor::trim_region_back ()
3195 trim_region (false);
3199 Editor::trim_region (bool front)
3201 framepos_t where = get_preferred_edit_position();
3202 RegionSelection rs = get_regions_from_selection_and_edit_point ();
3204 cerr << "trim regions\n";
3207 cerr << " no regions\n";
3211 cerr << "where = " << where << endl;
3213 begin_reversible_command (front ? _("trim front") : _("trim back"));
3215 for (list<RegionView*>::const_iterator i = rs.by_layer().begin(); i != rs.by_layer().end(); ++i) {
3216 if (!(*i)->region()->locked()) {
3218 (*i)->region()->clear_changes ();
3221 (*i)->region()->trim_front (where);
3223 (*i)->region()->trim_end (where);
3226 _session->add_command (new StatefulDiffCommand ((*i)->region()));
3230 commit_reversible_command ();
3233 /** Trim the end of the selected regions to the position of the edit cursor */
3235 Editor::trim_region_to_loop ()
3237 Location* loc = _session->locations()->auto_loop_location();
3241 trim_region_to_location (*loc, _("trim to loop"));
3245 Editor::trim_region_to_punch ()
3247 Location* loc = _session->locations()->auto_punch_location();
3251 trim_region_to_location (*loc, _("trim to punch"));
3255 Editor::trim_region_to_location (const Location& loc, const char* str)
3257 RegionSelection rs = get_regions_from_selection_and_entered ();
3259 begin_reversible_command (str);
3261 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
3262 RegionView* rv = (*x);
3264 /* require region to span proposed trim */
3265 switch (rv->region()->coverage (loc.start(), loc.end())) {
3266 case Evoral::OverlapInternal:
3272 RouteTimeAxisView* tav = dynamic_cast<RouteTimeAxisView*> (&rv->get_time_axis_view());
3281 if (tav->track() != 0) {
3282 speed = tav->track()->speed();
3285 start = session_frame_to_track_frame (loc.start(), speed);
3286 end = session_frame_to_track_frame (loc.end(), speed);
3288 rv->region()->clear_changes ();
3289 rv->region()->trim_to (start, (end - start));
3290 _session->add_command(new StatefulDiffCommand (rv->region()));
3293 commit_reversible_command ();
3297 Editor::trim_region_to_previous_region_end ()
3299 return trim_to_region(false);
3303 Editor::trim_region_to_next_region_start ()
3305 return trim_to_region(true);
3309 Editor::trim_to_region(bool forward)
3311 RegionSelection rs = get_regions_from_selection_and_entered ();
3313 begin_reversible_command (_("trim to region"));
3315 boost::shared_ptr<Region> next_region;
3317 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
3319 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*x);
3325 AudioTimeAxisView* atav = dynamic_cast<AudioTimeAxisView*> (&arv->get_time_axis_view());
3333 if (atav->track() != 0) {
3334 speed = atav->track()->speed();
3338 boost::shared_ptr<Region> region = arv->region();
3339 boost::shared_ptr<Playlist> playlist (region->playlist());
3341 region->clear_changes ();
3345 next_region = playlist->find_next_region (region->first_frame(), Start, 1);
3351 region->trim_end((framepos_t) ( (next_region->first_frame() - 1) * speed));
3352 arv->region_changed (PropertyChange (ARDOUR::Properties::length));
3356 next_region = playlist->find_next_region (region->first_frame(), Start, 0);
3362 region->trim_front((framepos_t) ((next_region->last_frame() + 1) * speed));
3364 arv->region_changed (ARDOUR::bounds_change);
3367 _session->add_command(new StatefulDiffCommand (region));
3370 commit_reversible_command ();
3374 Editor::unfreeze_route ()
3376 if (clicked_routeview == 0 || !clicked_routeview->is_track()) {
3380 clicked_routeview->track()->unfreeze ();
3384 Editor::_freeze_thread (void* arg)
3386 return static_cast<Editor*>(arg)->freeze_thread ();
3390 Editor::freeze_thread ()
3392 /* create event pool because we may need to talk to the session */
3393 SessionEvent::create_per_thread_pool ("freeze events", 64);
3394 /* create per-thread buffers for process() tree to use */
3395 current_interthread_info->process_thread.init ();
3396 current_interthread_info->process_thread.get_buffers ();
3397 clicked_routeview->audio_track()->freeze_me (*current_interthread_info);
3398 current_interthread_info->done = true;
3399 current_interthread_info->process_thread.drop_buffers();
3404 Editor::freeze_route ()
3410 /* stop transport before we start. this is important */
3412 _session->request_transport_speed (0.0);
3414 /* wait for just a little while, because the above call is asynchronous */
3418 if (clicked_routeview == 0 || !clicked_routeview->is_audio_track()) {
3422 if (!clicked_routeview->track()->bounceable (clicked_routeview->track()->main_outs(), true)) {
3424 _("This track/bus cannot be frozen because the signal adds or loses channels before reaching the outputs.\n"
3425 "This is typically caused by plugins that generate stereo output from mono input or vice versa.")
3427 d.set_title (_("Cannot freeze"));
3432 if (clicked_routeview->track()->has_external_redirects()) {
3433 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"
3434 "Freezing will only process the signal as far as the first send/insert/return."),
3435 clicked_routeview->track()->name()), true, MESSAGE_INFO, BUTTONS_NONE, true);
3437 d.add_button (_("Freeze anyway"), Gtk::RESPONSE_OK);
3438 d.add_button (_("Don't freeze"), Gtk::RESPONSE_CANCEL);
3439 d.set_title (_("Freeze Limits"));
3441 int response = d.run ();
3444 case Gtk::RESPONSE_CANCEL:
3451 InterThreadInfo itt;
3452 current_interthread_info = &itt;
3454 InterthreadProgressWindow ipw (current_interthread_info, _("Freeze"), _("Cancel Freeze"));
3456 pthread_create_and_store (X_("freezer"), &itt.thread, _freeze_thread, this);
3458 set_canvas_cursor (_cursors->wait);
3460 while (!itt.done && !itt.cancel) {
3461 gtk_main_iteration ();
3464 current_interthread_info = 0;
3465 set_canvas_cursor (current_canvas_cursor);
3469 Editor::bounce_range_selection (bool replace, bool enable_processing)
3471 if (selection->time.empty()) {
3475 TrackSelection views = selection->tracks;
3477 for (TrackViewList::iterator i = views.begin(); i != views.end(); ++i) {
3479 if (enable_processing) {
3481 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*i);
3483 if (rtv && rtv->track() && replace && enable_processing && !rtv->track()->bounceable (rtv->track()->main_outs(), false)) {
3485 _("You can't perform this operation because the processing of the signal "
3486 "will cause one or more of the tracks will end up with a region with more channels than this track has inputs.\n\n"
3487 "You can do this without processing, which is a different operation.")
3489 d.set_title (_("Cannot bounce"));
3496 framepos_t start = selection->time[clicked_selection].start;
3497 framepos_t end = selection->time[clicked_selection].end;
3498 framepos_t cnt = end - start + 1;
3500 begin_reversible_command (_("bounce range"));
3502 for (TrackViewList::iterator i = views.begin(); i != views.end(); ++i) {
3504 RouteTimeAxisView* rtv;
3506 if ((rtv = dynamic_cast<RouteTimeAxisView*> (*i)) == 0) {
3510 boost::shared_ptr<Playlist> playlist;
3512 if ((playlist = rtv->playlist()) == 0) {
3516 InterThreadInfo itt;
3518 playlist->clear_changes ();
3519 playlist->clear_owned_changes ();
3521 boost::shared_ptr<Region> r;
3523 if (enable_processing) {
3524 r = rtv->track()->bounce_range (start, start+cnt, itt, rtv->track()->main_outs(), false);
3526 r = rtv->track()->bounce_range (start, start+cnt, itt, boost::shared_ptr<Processor>(), false);
3534 list<AudioRange> ranges;
3535 ranges.push_back (AudioRange (start, start+cnt, 0));
3536 playlist->cut (ranges); // discard result
3537 playlist->add_region (r, start);
3540 vector<Command*> cmds;
3541 playlist->rdiff (cmds);
3542 _session->add_commands (cmds);
3544 _session->add_command (new StatefulDiffCommand (playlist));
3547 commit_reversible_command ();
3550 /** Delete selected regions, automation points or a time range */
3557 /** Cut selected regions, automation points or a time range */
3564 /** Copy selected regions, automation points or a time range */
3572 /** @return true if a Cut, Copy or Clear is possible */
3574 Editor::can_cut_copy () const
3576 switch (current_mouse_mode()) {
3579 if (!selection->regions.empty() || !selection->points.empty()) {
3585 if (!selection->time.empty()) {
3598 /** Cut, copy or clear selected regions, automation points or a time range.
3599 * @param op Operation (Cut, Copy or Clear)
3602 Editor::cut_copy (CutCopyOp op)
3604 /* only cancel selection if cut/copy is successful.*/
3610 opname = _("delete");
3619 opname = _("clear");
3623 /* if we're deleting something, and the mouse is still pressed,
3624 the thing we started a drag for will be gone when we release
3625 the mouse button(s). avoid this. see part 2 at the end of
3629 if (op == Delete || op == Cut || op == Clear) {
3630 if (_drags->active ()) {
3635 cut_buffer->clear ();
3637 if (entered_marker) {
3639 /* cut/delete op while pointing at a marker */
3642 Location* loc = find_location_from_marker (entered_marker, ignored);
3644 if (_session && loc) {
3645 Glib::signal_idle().connect (sigc::bind (sigc::mem_fun(*this, &Editor::really_remove_marker), loc));
3652 if (internal_editing()) {
3654 switch (current_mouse_mode()) {
3667 /* we only want to cut regions if some are selected */
3669 if (doing_object_stuff()) {
3670 rs = get_regions_from_selection ();
3671 if (!rs.empty() || !selection->points.empty()) {
3673 begin_reversible_command (opname + _(" objects"));
3676 cut_copy_regions (op, rs);
3678 if (op == Cut || op == Delete) {
3679 selection->clear_regions ();
3683 if (!selection->points.empty()) {
3684 cut_copy_points (op);
3686 if (op == Cut || op == Delete) {
3687 selection->clear_points ();
3690 commit_reversible_command ();
3693 if (!selection->time.empty() && (_join_object_range_state == JOIN_OBJECT_RANGE_NONE)) {
3694 /* don't cause suprises */
3699 if (doing_range_stuff()) {
3700 if (selection->time.empty()) {
3701 framepos_t start, end;
3702 if (!get_edit_op_range (start, end)) {
3705 selection->set (start, end);
3708 begin_reversible_command (opname + _(" range"));
3709 cut_copy_ranges (op);
3710 commit_reversible_command ();
3712 if (op == Cut || op == Delete) {
3713 selection->clear_time ();
3719 if (op == Delete || op == Cut || op == Clear) {
3724 /** Cut, copy or clear selected automation points.
3725 * @param op Operation (Cut, Copy or Clear)
3728 Editor::cut_copy_points (CutCopyOp op)
3730 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
3732 AutomationTimeAxisView* atv = dynamic_cast<AutomationTimeAxisView*>((*i).track);
3733 _last_cut_copy_source_track = atv;
3736 atv->cut_copy_clear_objects (selection->points, op);
3741 /** Cut, copy or clear selected automation points.
3742 * @param op Operation (Cut, Copy or Clear)
3745 Editor::cut_copy_midi (CutCopyOp op)
3747 for (MidiRegionSelection::iterator i = selection->midi_regions.begin(); i != selection->midi_regions.end(); ++i) {
3748 MidiRegionView* mrv = *i;
3749 mrv->cut_copy_clear (op);
3755 struct lt_playlist {
3756 bool operator () (const PlaylistState& a, const PlaylistState& b) {
3757 return a.playlist < b.playlist;
3761 struct PlaylistMapping {
3763 boost::shared_ptr<Playlist> pl;
3765 PlaylistMapping (TimeAxisView* tvp) : tv (tvp) {}
3768 /** Remove `clicked_regionview' */
3770 Editor::remove_clicked_region ()
3772 if (clicked_routeview == 0 || clicked_regionview == 0) {
3776 boost::shared_ptr<Playlist> playlist = clicked_routeview->playlist();
3778 begin_reversible_command (_("remove region"));
3779 playlist->clear_changes ();
3780 playlist->clear_owned_changes ();
3781 playlist->remove_region (clicked_regionview->region());
3783 /* We might have removed regions, which alters other regions' layering_index,
3784 so we need to do a recursive diff here.
3786 vector<Command*> cmds;
3787 playlist->rdiff (cmds);
3788 _session->add_commands (cmds);
3790 _session->add_command(new StatefulDiffCommand (playlist));
3791 commit_reversible_command ();
3795 /** Remove the selected regions */
3797 Editor::remove_selected_regions ()
3799 RegionSelection rs = get_regions_from_selection_and_entered ();
3801 if (!_session || rs.empty()) {
3805 begin_reversible_command (_("remove region"));
3807 list<boost::shared_ptr<Region> > regions_to_remove;
3809 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3810 // we can't just remove the region(s) in this loop because
3811 // this removes them from the RegionSelection, and they thus
3812 // disappear from underneath the iterator, and the ++i above
3813 // SEGVs in a puzzling fashion.
3815 // so, first iterate over the regions to be removed from rs and
3816 // add them to the regions_to_remove list, and then
3817 // iterate over the list to actually remove them.
3819 regions_to_remove.push_back ((*i)->region());
3822 vector<boost::shared_ptr<Playlist> > playlists;
3824 for (list<boost::shared_ptr<Region> >::iterator rl = regions_to_remove.begin(); rl != regions_to_remove.end(); ++rl) {
3826 boost::shared_ptr<Playlist> playlist = (*rl)->playlist();
3829 // is this check necessary?
3833 /* get_regions_from_selection_and_entered() guarantees that
3834 the playlists involved are unique, so there is no need
3838 playlists.push_back (playlist);
3840 playlist->clear_changes ();
3841 playlist->clear_owned_changes ();
3842 playlist->freeze ();
3843 playlist->remove_region (*rl);
3846 vector<boost::shared_ptr<Playlist> >::iterator pl;
3848 for (pl = playlists.begin(); pl != playlists.end(); ++pl) {
3851 /* We might have removed regions, which alters other regions' layering_index,
3852 so we need to do a recursive diff here.
3854 vector<Command*> cmds;
3855 (*pl)->rdiff (cmds);
3856 _session->add_commands (cmds);
3858 _session->add_command(new StatefulDiffCommand (*pl));
3861 commit_reversible_command ();
3864 /** Cut, copy or clear selected regions.
3865 * @param op Operation (Cut, Copy or Clear)
3868 Editor::cut_copy_regions (CutCopyOp op, RegionSelection& rs)
3870 /* we can't use a std::map here because the ordering is important, and we can't trivially sort
3871 a map when we want ordered access to both elements. i think.
3874 vector<PlaylistMapping> pmap;
3876 framepos_t first_position = max_framepos;
3878 typedef set<boost::shared_ptr<Playlist> > FreezeList;
3879 FreezeList freezelist;
3881 /* get ordering correct before we cut/copy */
3883 rs.sort_by_position_and_track ();
3885 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
3887 first_position = min ((framepos_t) (*x)->region()->position(), first_position);
3889 if (op == Cut || op == Clear || op == Delete) {
3890 boost::shared_ptr<Playlist> pl = (*x)->region()->playlist();
3893 FreezeList::iterator fl;
3895 // only take state if this is a new playlist.
3896 for (fl = freezelist.begin(); fl != freezelist.end(); ++fl) {
3902 if (fl == freezelist.end()) {
3903 pl->clear_changes();
3904 pl->clear_owned_changes ();
3906 freezelist.insert (pl);
3911 TimeAxisView* tv = &(*x)->get_time_axis_view();
3912 vector<PlaylistMapping>::iterator z;
3914 for (z = pmap.begin(); z != pmap.end(); ++z) {
3915 if ((*z).tv == tv) {
3920 if (z == pmap.end()) {
3921 pmap.push_back (PlaylistMapping (tv));
3925 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ) {
3927 boost::shared_ptr<Playlist> pl = (*x)->region()->playlist();
3930 /* region not yet associated with a playlist (e.g. unfinished
3937 TimeAxisView& tv = (*x)->get_time_axis_view();
3938 boost::shared_ptr<Playlist> npl;
3939 RegionSelection::iterator tmp;
3946 vector<PlaylistMapping>::iterator z;
3948 for (z = pmap.begin(); z != pmap.end(); ++z) {
3949 if ((*z).tv == &tv) {
3954 assert (z != pmap.end());
3957 npl = PlaylistFactory::create (pl->data_type(), *_session, "cutlist", true);
3965 boost::shared_ptr<Region> r = (*x)->region();
3966 boost::shared_ptr<Region> _xx;
3972 pl->remove_region (r);
3976 _xx = RegionFactory::create (r);
3977 npl->add_region (_xx, r->position() - first_position);
3978 pl->remove_region (r);
3982 /* copy region before adding, so we're not putting same object into two different playlists */
3983 npl->add_region (RegionFactory::create (r), r->position() - first_position);
3987 pl->remove_region (r);
3996 list<boost::shared_ptr<Playlist> > foo;
3998 /* the pmap is in the same order as the tracks in which selected regions occured */
4000 for (vector<PlaylistMapping>::iterator i = pmap.begin(); i != pmap.end(); ++i) {
4003 foo.push_back ((*i).pl);
4008 cut_buffer->set (foo);
4012 _last_cut_copy_source_track = 0;
4014 _last_cut_copy_source_track = pmap.front().tv;
4018 for (FreezeList::iterator pl = freezelist.begin(); pl != freezelist.end(); ++pl) {
4021 /* We might have removed regions, which alters other regions' layering_index,
4022 so we need to do a recursive diff here.
4024 vector<Command*> cmds;
4025 (*pl)->rdiff (cmds);
4026 _session->add_commands (cmds);
4028 _session->add_command (new StatefulDiffCommand (*pl));
4033 Editor::cut_copy_ranges (CutCopyOp op)
4035 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4037 /* Sort the track selection now, so that it if is used, the playlists
4038 selected by the calls below to cut_copy_clear are in the order that
4039 their tracks appear in the editor. This makes things like paste
4040 of ranges work properly.
4043 sort_track_selection (ts);
4046 if (!entered_track) {
4049 ts.push_back (entered_track);
4052 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4053 (*i)->cut_copy_clear (*selection, op);
4058 Editor::paste (float times, bool from_context)
4060 DEBUG_TRACE (DEBUG::CutNPaste, "paste to preferred edit pos\n");
4062 paste_internal (get_preferred_edit_position (false, from_context), times);
4066 Editor::mouse_paste ()
4071 if (!mouse_frame (where, ignored)) {
4076 paste_internal (where, 1);
4080 Editor::paste_internal (framepos_t position, float times)
4082 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("apparent paste position is %1\n", position));
4084 if (internal_editing()) {
4085 if (cut_buffer->midi_notes.empty()) {
4089 if (cut_buffer->empty()) {
4094 if (position == max_framepos) {
4095 position = get_preferred_edit_position();
4096 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("preferred edit position is %1\n", position));
4100 TrackViewList::iterator i;
4103 /* get everything in the correct order */
4105 if (!selection->tracks.empty()) {
4106 /* there are some selected tracks, so paste to them */
4107 ts = selection->tracks.filter_to_unique_playlists ();
4108 sort_track_selection (ts);
4109 } else if (_last_cut_copy_source_track) {
4110 /* otherwise paste to the track that the cut/copy came from;
4111 see discussion in mantis #3333.
4113 ts.push_back (_last_cut_copy_source_track);
4116 if (internal_editing ()) {
4118 /* undo/redo is handled by individual tracks/regions */
4120 for (nth = 0, i = ts.begin(); i != ts.end(); ++i, ++nth) {
4123 RegionSelection::iterator r;
4124 MidiNoteSelection::iterator cb;
4126 get_regions_at (rs, position, ts);
4128 for (cb = cut_buffer->midi_notes.begin(), r = rs.begin();
4129 cb != cut_buffer->midi_notes.end() && r != rs.end(); ++r) {
4130 MidiRegionView* mrv = dynamic_cast<MidiRegionView*> (*r);
4132 mrv->paste (position, times, **cb);
4140 /* we do redo (do you do voodoo?) */
4142 begin_reversible_command (Operations::paste);
4144 for (nth = 0, i = ts.begin(); i != ts.end(); ++i, ++nth) {
4145 (*i)->paste (position, times, *cut_buffer, nth);
4148 commit_reversible_command ();
4153 Editor::duplicate_some_regions (RegionSelection& regions, float times)
4155 boost::shared_ptr<Playlist> playlist;
4156 RegionSelection sel = regions; // clear (below) may clear the argument list if its the current region selection
4157 RegionSelection foo;
4159 framepos_t const start_frame = regions.start ();
4160 framepos_t const end_frame = regions.end_frame ();
4162 begin_reversible_command (Operations::duplicate_region);
4164 selection->clear_regions ();
4166 for (RegionSelection::iterator i = sel.begin(); i != sel.end(); ++i) {
4168 boost::shared_ptr<Region> r ((*i)->region());
4170 TimeAxisView& tv = (*i)->get_time_axis_view();
4171 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (&tv);
4172 latest_regionviews.clear ();
4173 sigc::connection c = rtv->view()->RegionViewAdded.connect (sigc::mem_fun(*this, &Editor::collect_new_region_view));
4175 playlist = (*i)->region()->playlist();
4176 playlist->clear_changes ();
4177 playlist->duplicate (r, end_frame + (r->first_frame() - start_frame), times);
4178 _session->add_command(new StatefulDiffCommand (playlist));
4182 foo.insert (foo.end(), latest_regionviews.begin(), latest_regionviews.end());
4185 commit_reversible_command ();
4188 selection->set (foo);
4193 Editor::duplicate_selection (float times)
4195 if (selection->time.empty() || selection->tracks.empty()) {
4199 boost::shared_ptr<Playlist> playlist;
4200 vector<boost::shared_ptr<Region> > new_regions;
4201 vector<boost::shared_ptr<Region> >::iterator ri;
4203 create_region_from_selection (new_regions);
4205 if (new_regions.empty()) {
4209 begin_reversible_command (_("duplicate selection"));
4211 ri = new_regions.begin();
4213 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4215 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4216 if ((playlist = (*i)->playlist()) == 0) {
4219 playlist->clear_changes ();
4220 playlist->duplicate (*ri, selection->time[clicked_selection].end, times);
4221 _session->add_command (new StatefulDiffCommand (playlist));
4224 if (ri == new_regions.end()) {
4229 commit_reversible_command ();
4233 Editor::reset_point_selection ()
4235 /* reset all selected points to the relevant default value */
4237 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
4239 AutomationTimeAxisView* atv = dynamic_cast<AutomationTimeAxisView*>((*i).track);
4242 atv->reset_objects (selection->points);
4248 Editor::center_playhead ()
4250 float page = _canvas_width * frames_per_unit;
4251 center_screen_internal (playhead_cursor->current_frame, page);
4255 Editor::center_edit_point ()
4257 float page = _canvas_width * frames_per_unit;
4258 center_screen_internal (get_preferred_edit_position(), page);
4261 /** Caller must begin and commit a reversible command */
4263 Editor::clear_playlist (boost::shared_ptr<Playlist> playlist)
4265 playlist->clear_changes ();
4267 _session->add_command (new StatefulDiffCommand (playlist));
4271 Editor::nudge_track (bool use_edit, bool forwards)
4273 boost::shared_ptr<Playlist> playlist;
4274 framepos_t distance;
4275 framepos_t next_distance;
4279 start = get_preferred_edit_position();
4284 if ((distance = get_nudge_distance (start, next_distance)) == 0) {
4288 if (selection->tracks.empty()) {
4292 begin_reversible_command (_("nudge track"));
4294 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4296 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4298 if ((playlist = (*i)->playlist()) == 0) {
4302 playlist->clear_changes ();
4303 playlist->clear_owned_changes ();
4305 playlist->nudge_after (start, distance, forwards);
4307 vector<Command*> cmds;
4309 playlist->rdiff (cmds);
4310 _session->add_commands (cmds);
4312 _session->add_command (new StatefulDiffCommand (playlist));
4315 commit_reversible_command ();
4319 Editor::remove_last_capture ()
4321 vector<string> choices;
4328 if (Config->get_verify_remove_last_capture()) {
4329 prompt = _("Do you really want to destroy the last capture?"
4330 "\n(This is destructive and cannot be undone)");
4332 choices.push_back (_("No, do nothing."));
4333 choices.push_back (_("Yes, destroy it."));
4335 Gtkmm2ext::Choice prompter (_("Destroy last capture"), prompt, choices);
4337 if (prompter.run () == 1) {
4338 _session->remove_last_capture ();
4339 _regions->redisplay ();
4343 _session->remove_last_capture();
4344 _regions->redisplay ();
4349 Editor::normalize_region ()
4355 RegionSelection rs = get_regions_from_selection_and_entered ();
4361 NormalizeDialog dialog (rs.size() > 1);
4363 if (dialog.run () == RESPONSE_CANCEL) {
4367 set_canvas_cursor (_cursors->wait);
4370 /* XXX: should really only count audio regions here */
4371 int const regions = rs.size ();
4373 /* Make a list of the selected audio regions' maximum amplitudes, and also
4374 obtain the maximum amplitude of them all.
4376 list<double> max_amps;
4378 for (RegionSelection::const_iterator i = rs.begin(); i != rs.end(); ++i) {
4379 AudioRegionView const * arv = dynamic_cast<AudioRegionView const *> (*i);
4381 dialog.descend (1.0 / regions);
4382 double const a = arv->audio_region()->maximum_amplitude (&dialog);
4385 /* the user cancelled the operation */
4386 set_canvas_cursor (current_canvas_cursor);
4390 max_amps.push_back (a);
4391 max_amp = max (max_amp, a);
4396 begin_reversible_command (_("normalize"));
4398 list<double>::const_iterator a = max_amps.begin ();
4400 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
4401 AudioRegionView* const arv = dynamic_cast<AudioRegionView*> (*r);
4406 arv->region()->clear_changes ();
4408 double const amp = dialog.normalize_individually() ? *a : max_amp;
4410 arv->audio_region()->normalize (amp, dialog.target ());
4411 _session->add_command (new StatefulDiffCommand (arv->region()));
4416 commit_reversible_command ();
4417 set_canvas_cursor (current_canvas_cursor);
4422 Editor::reset_region_scale_amplitude ()
4428 RegionSelection rs = get_regions_from_selection_and_entered ();
4434 begin_reversible_command ("reset gain");
4436 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
4437 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
4440 arv->region()->clear_changes ();
4441 arv->audio_region()->set_scale_amplitude (1.0f);
4442 _session->add_command (new StatefulDiffCommand (arv->region()));
4445 commit_reversible_command ();
4449 Editor::adjust_region_gain (bool up)
4451 RegionSelection rs = get_regions_from_selection_and_entered ();
4453 if (!_session || rs.empty()) {
4457 begin_reversible_command ("adjust region gain");
4459 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
4460 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
4465 arv->region()->clear_changes ();
4467 double dB = accurate_coefficient_to_dB (arv->audio_region()->scale_amplitude ());
4475 arv->audio_region()->set_scale_amplitude (dB_to_coefficient (dB));
4476 _session->add_command (new StatefulDiffCommand (arv->region()));
4479 commit_reversible_command ();
4484 Editor::reverse_region ()
4490 Reverse rev (*_session);
4491 apply_filter (rev, _("reverse regions"));
4495 Editor::strip_region_silence ()
4501 RegionSelection rs = get_regions_from_selection_and_entered ();
4507 std::list<RegionView*> audio_only;
4509 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
4510 AudioRegionView* const arv = dynamic_cast<AudioRegionView*> (*i);
4512 audio_only.push_back (arv);
4516 StripSilenceDialog d (_session, audio_only);
4517 int const r = d.run ();
4521 if (r == Gtk::RESPONSE_OK) {
4522 ARDOUR::AudioIntervalMap silences;
4523 d.silences (silences);
4524 StripSilence s (*_session, silences, d.fade_length());
4525 apply_filter (s, _("strip silence"), &d);
4530 Editor::apply_midi_note_edit_op_to_region (MidiOperator& op, MidiRegionView& mrv)
4532 Evoral::Sequence<Evoral::MusicalTime>::Notes selected;
4533 mrv.selection_as_notelist (selected, true);
4535 vector<Evoral::Sequence<Evoral::MusicalTime>::Notes> v;
4536 v.push_back (selected);
4538 framepos_t pos_frames = mrv.midi_region()->position();
4539 double pos_beats = _session->tempo_map().framewalk_to_beats(0, pos_frames);
4541 return op (mrv.midi_region()->model(), pos_beats, v);
4545 Editor::apply_midi_note_edit_op (MidiOperator& op)
4549 RegionSelection rs = get_regions_from_selection_and_entered ();
4555 begin_reversible_command (op.name ());
4557 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
4558 RegionSelection::iterator tmp = r;
4561 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*r);
4564 cmd = apply_midi_note_edit_op_to_region (op, *mrv);
4567 _session->add_command (cmd);
4574 commit_reversible_command ();
4578 Editor::fork_region ()
4580 RegionSelection rs = get_regions_from_selection_and_entered ();
4586 begin_reversible_command (_("Fork Region(s)"));
4588 set_canvas_cursor (_cursors->wait);
4591 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
4592 RegionSelection::iterator tmp = r;
4595 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*>(*r);
4598 boost::shared_ptr<Playlist> playlist = mrv->region()->playlist();
4599 boost::shared_ptr<MidiRegion> newregion = mrv->midi_region()->clone ();
4601 playlist->clear_changes ();
4602 playlist->replace_region (mrv->region(), newregion, mrv->region()->position());
4603 _session->add_command(new StatefulDiffCommand (playlist));
4609 commit_reversible_command ();
4611 set_canvas_cursor (current_canvas_cursor);
4615 Editor::quantize_region ()
4617 int selected_midi_region_cnt = 0;
4623 RegionSelection rs = get_regions_from_selection_and_entered ();
4629 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
4630 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*r);
4632 selected_midi_region_cnt++;
4636 if (selected_midi_region_cnt == 0) {
4640 QuantizeDialog* qd = new QuantizeDialog (*this);
4643 const int r = qd->run ();
4646 if (r == Gtk::RESPONSE_OK) {
4647 Quantize quant (*_session, Plain,
4648 qd->snap_start(), qd->snap_end(),
4649 qd->start_grid_size(), qd->end_grid_size(),
4650 qd->strength(), qd->swing(), qd->threshold());
4652 apply_midi_note_edit_op (quant);
4657 Editor::insert_patch_change (bool from_context)
4659 RegionSelection rs = get_regions_from_selection_and_entered ();
4665 const framepos_t p = get_preferred_edit_position (false, from_context);
4667 Evoral::PatchChange<Evoral::MusicalTime> empty (0, 0, 0, 0);
4668 PatchChangeDialog d (0, _session, empty, Gtk::Stock::ADD);
4670 if (d.run() == RESPONSE_CANCEL) {
4674 for (RegionSelection::iterator i = rs.begin (); i != rs.end(); ++i) {
4675 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*i);
4677 if (p >= mrv->region()->first_frame() && p <= mrv->region()->last_frame()) {
4678 mrv->add_patch_change (p - mrv->region()->position(), d.patch ());
4685 Editor::apply_filter (Filter& filter, string command, ProgressReporter* progress)
4687 RegionSelection rs = get_regions_from_selection_and_entered ();
4693 begin_reversible_command (command);
4695 set_canvas_cursor (_cursors->wait);
4699 int const N = rs.size ();
4701 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
4702 RegionSelection::iterator tmp = r;
4705 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
4707 boost::shared_ptr<Playlist> playlist = arv->region()->playlist();
4710 progress->descend (1.0 / N);
4713 if (arv->audio_region()->apply (filter, progress) == 0) {
4715 playlist->clear_changes ();
4716 playlist->clear_owned_changes ();
4718 if (filter.results.empty ()) {
4720 /* no regions returned; remove the old one */
4721 playlist->remove_region (arv->region ());
4725 std::vector<boost::shared_ptr<Region> >::iterator res = filter.results.begin ();
4727 /* first region replaces the old one */
4728 playlist->replace_region (arv->region(), *res, (*res)->position());
4732 while (res != filter.results.end()) {
4733 playlist->add_region (*res, (*res)->position());
4739 /* We might have removed regions, which alters other regions' layering_index,
4740 so we need to do a recursive diff here.
4742 vector<Command*> cmds;
4743 playlist->rdiff (cmds);
4744 _session->add_commands (cmds);
4746 _session->add_command(new StatefulDiffCommand (playlist));
4752 progress->ascend ();
4760 commit_reversible_command ();
4763 set_canvas_cursor (current_canvas_cursor);
4767 Editor::external_edit_region ()
4773 Editor::reset_region_gain_envelopes ()
4775 RegionSelection rs = get_regions_from_selection_and_entered ();
4777 if (!_session || rs.empty()) {
4781 _session->begin_reversible_command (_("reset region gain"));
4783 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
4784 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
4786 boost::shared_ptr<AutomationList> alist (arv->audio_region()->envelope());
4787 XMLNode& before (alist->get_state());
4789 arv->audio_region()->set_default_envelope ();
4790 _session->add_command (new MementoCommand<AutomationList>(*arv->audio_region()->envelope().get(), &before, &alist->get_state()));
4794 _session->commit_reversible_command ();
4798 Editor::set_region_gain_visibility (RegionView* rv, bool yn)
4800 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (rv);
4802 arv->set_envelope_visible (yn);
4807 Editor::set_gain_envelope_visibility (bool yn)
4813 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4814 AudioTimeAxisView* v = dynamic_cast<AudioTimeAxisView*>(*i);
4816 v->audio_view()->foreach_regionview (sigc::bind (sigc::mem_fun (this, &Editor::set_region_gain_visibility), yn));
4822 Editor::toggle_gain_envelope_active ()
4824 if (_ignore_region_action) {
4828 RegionSelection rs = get_regions_from_selection_and_entered ();
4830 if (!_session || rs.empty()) {
4834 _session->begin_reversible_command (_("region gain envelope active"));
4836 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
4837 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
4839 arv->region()->clear_changes ();
4840 arv->audio_region()->set_envelope_active (!arv->audio_region()->envelope_active());
4841 _session->add_command (new StatefulDiffCommand (arv->region()));
4845 _session->commit_reversible_command ();
4849 Editor::toggle_region_lock ()
4851 if (_ignore_region_action) {
4855 RegionSelection rs = get_regions_from_selection_and_entered ();
4857 if (!_session || rs.empty()) {
4861 _session->begin_reversible_command (_("toggle region lock"));
4863 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
4864 (*i)->region()->clear_changes ();
4865 (*i)->region()->set_locked (!(*i)->region()->locked());
4866 _session->add_command (new StatefulDiffCommand ((*i)->region()));
4869 _session->commit_reversible_command ();
4873 Editor::toggle_region_lock_style ()
4875 if (_ignore_region_action) {
4879 RegionSelection rs = get_regions_from_selection_and_entered ();
4881 if (!_session || rs.empty()) {
4885 _session->begin_reversible_command (_("region lock style"));
4887 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
4888 (*i)->region()->clear_changes ();
4889 PositionLockStyle const ns = (*i)->region()->position_lock_style() == AudioTime ? MusicTime : AudioTime;
4890 (*i)->region()->set_position_lock_style (ns);
4891 _session->add_command (new StatefulDiffCommand ((*i)->region()));
4894 _session->commit_reversible_command ();
4898 Editor::toggle_opaque_region ()
4900 if (_ignore_region_action) {
4904 RegionSelection rs = get_regions_from_selection_and_entered ();
4906 if (!_session || rs.empty()) {
4910 _session->begin_reversible_command (_("change region opacity"));
4912 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
4913 (*i)->region()->clear_changes ();
4914 (*i)->region()->set_opaque (!(*i)->region()->opaque());
4915 _session->add_command (new StatefulDiffCommand ((*i)->region()));
4918 _session->commit_reversible_command ();
4922 Editor::toggle_record_enable ()
4924 bool new_state = false;
4926 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4927 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
4930 if (!rtav->is_track())
4934 new_state = !rtav->track()->record_enabled();
4938 rtav->track()->set_record_enabled (new_state, this);
4943 Editor::toggle_solo ()
4945 bool new_state = false;
4947 boost::shared_ptr<RouteList> rl (new RouteList);
4949 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4950 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
4957 new_state = !rtav->route()->soloed ();
4961 rl->push_back (rtav->route());
4964 _session->set_solo (rl, new_state, Session::rt_cleanup, true);
4968 Editor::toggle_mute ()
4970 bool new_state = false;
4972 boost::shared_ptr<RouteList> rl (new RouteList);
4974 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4975 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
4982 new_state = !rtav->route()->muted();
4986 rl->push_back (rtav->route());
4989 _session->set_mute (rl, new_state, Session::rt_cleanup, true);
4993 Editor::toggle_solo_isolate ()
4998 Editor::set_fade_length (bool in)
5000 RegionSelection rs = get_regions_from_selection_and_entered ();
5006 /* we need a region to measure the offset from the start */
5008 RegionView* rv = rs.front ();
5010 framepos_t pos = get_preferred_edit_position();
5014 if (pos > rv->region()->last_frame() || pos < rv->region()->first_frame()) {
5015 /* edit point is outside the relevant region */
5020 if (pos <= rv->region()->position()) {
5024 len = pos - rv->region()->position();
5025 cmd = _("set fade in length");
5027 if (pos >= rv->region()->last_frame()) {
5031 len = rv->region()->last_frame() - pos;
5032 cmd = _("set fade out length");
5035 begin_reversible_command (cmd);
5037 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5038 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5044 boost::shared_ptr<AutomationList> alist;
5046 alist = tmp->audio_region()->fade_in();
5048 alist = tmp->audio_region()->fade_out();
5051 XMLNode &before = alist->get_state();
5054 tmp->audio_region()->set_fade_in_length (len);
5055 tmp->audio_region()->set_fade_in_active (true);
5057 tmp->audio_region()->set_fade_out_length (len);
5058 tmp->audio_region()->set_fade_out_active (true);
5061 XMLNode &after = alist->get_state();
5062 _session->add_command(new MementoCommand<AutomationList>(*alist, &before, &after));
5065 commit_reversible_command ();
5069 Editor::set_fade_in_shape (FadeShape shape)
5071 RegionSelection rs = get_regions_from_selection_and_entered ();
5077 begin_reversible_command (_("set fade in shape"));
5079 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5080 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5086 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_in();
5087 XMLNode &before = alist->get_state();
5089 tmp->audio_region()->set_fade_in_shape (shape);
5091 XMLNode &after = alist->get_state();
5092 _session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
5095 commit_reversible_command ();
5100 Editor::set_fade_out_shape (FadeShape shape)
5102 RegionSelection rs = get_regions_from_selection_and_entered ();
5108 begin_reversible_command (_("set fade out shape"));
5110 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5111 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5117 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_out();
5118 XMLNode &before = alist->get_state();
5120 tmp->audio_region()->set_fade_out_shape (shape);
5122 XMLNode &after = alist->get_state();
5123 _session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
5126 commit_reversible_command ();
5130 Editor::set_fade_in_active (bool yn)
5132 RegionSelection rs = get_regions_from_selection_and_entered ();
5138 begin_reversible_command (_("set fade in active"));
5140 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5141 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5148 boost::shared_ptr<AudioRegion> ar (tmp->audio_region());
5150 ar->clear_changes ();
5151 ar->set_fade_in_active (yn);
5152 _session->add_command (new StatefulDiffCommand (ar));
5155 commit_reversible_command ();
5159 Editor::set_fade_out_active (bool yn)
5161 RegionSelection rs = get_regions_from_selection_and_entered ();
5167 begin_reversible_command (_("set fade out active"));
5169 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5170 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5176 boost::shared_ptr<AudioRegion> ar (tmp->audio_region());
5178 ar->clear_changes ();
5179 ar->set_fade_out_active (yn);
5180 _session->add_command(new StatefulDiffCommand (ar));
5183 commit_reversible_command ();
5187 Editor::toggle_region_fades (int dir)
5189 boost::shared_ptr<AudioRegion> ar;
5192 RegionSelection rs = get_regions_from_selection_and_entered ();
5198 RegionSelection::iterator i;
5199 for (i = rs.begin(); i != rs.end(); ++i) {
5200 if ((ar = boost::dynamic_pointer_cast<AudioRegion>((*i)->region())) != 0) {
5202 yn = ar->fade_out_active ();
5204 yn = ar->fade_in_active ();
5210 if (i == rs.end()) {
5214 /* XXX should this undo-able? */
5216 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5217 if ((ar = boost::dynamic_pointer_cast<AudioRegion>((*i)->region())) == 0) {
5220 if (dir == 1 || dir == 0) {
5221 ar->set_fade_in_active (!yn);
5224 if (dir == -1 || dir == 0) {
5225 ar->set_fade_out_active (!yn);
5231 /** Update region fade visibility after its configuration has been changed */
5233 Editor::update_region_fade_visibility ()
5235 bool _fade_visibility = _session->config.get_show_region_fades ();
5237 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5238 AudioTimeAxisView* v = dynamic_cast<AudioTimeAxisView*>(*i);
5240 if (_fade_visibility) {
5241 v->audio_view()->show_all_fades ();
5243 v->audio_view()->hide_all_fades ();
5250 Editor::set_edit_point ()
5255 if (!mouse_frame (where, ignored)) {
5261 if (selection->markers.empty()) {
5263 mouse_add_new_marker (where);
5268 Location* loc = find_location_from_marker (selection->markers.front(), ignored);
5271 loc->move_to (where);
5277 Editor::set_playhead_cursor ()
5279 if (entered_marker) {
5280 _session->request_locate (entered_marker->position(), _session->transport_rolling());
5285 if (!mouse_frame (where, ignored)) {
5292 _session->request_locate (where, _session->transport_rolling());
5298 Editor::split_region ()
5300 if (((mouse_mode == MouseRange) ||
5301 (mouse_mode != MouseObject && _join_object_range_state == JOIN_OBJECT_RANGE_RANGE)) &&
5302 !selection->time.empty()) {
5303 separate_regions_between (selection->time);
5307 RegionSelection rs = get_regions_from_selection_and_edit_point ();
5309 framepos_t where = get_preferred_edit_position ();
5315 split_regions_at (where, rs);
5319 Editor::ensure_entered_track_selected (bool op_really_wants_one_track_if_none_are_selected)
5321 if (entered_track && mouse_mode == MouseObject) {
5322 if (!selection->tracks.empty()) {
5323 if (!selection->selected (entered_track)) {
5324 selection->add (entered_track);
5327 /* there is no selection, but this operation requires/prefers selected objects */
5329 if (op_really_wants_one_track_if_none_are_selected) {
5330 selection->set (entered_track);
5336 struct EditorOrderRouteSorter {
5337 bool operator() (boost::shared_ptr<Route> a, boost::shared_ptr<Route> b) {
5338 /* use of ">" forces the correct sort order */
5339 return a->order_key ("editor") < b->order_key ("editor");
5344 Editor::select_next_route()
5346 if (selection->tracks.empty()) {
5347 selection->set (track_views.front());
5351 TimeAxisView* current = selection->tracks.front();
5355 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5356 if (*i == current) {
5358 if (i != track_views.end()) {
5361 current = (*(track_views.begin()));
5362 //selection->set (*(track_views.begin()));
5367 rui = dynamic_cast<RouteUI *>(current);
5368 } while ( current->hidden() || (rui != NULL && !rui->route()->active()));
5370 selection->set(current);
5372 ensure_track_visible(current);
5376 Editor::select_prev_route()
5378 if (selection->tracks.empty()) {
5379 selection->set (track_views.front());
5383 TimeAxisView* current = selection->tracks.front();
5387 for (TrackViewList::reverse_iterator i = track_views.rbegin(); i != track_views.rend(); ++i) {
5388 if (*i == current) {
5390 if (i != track_views.rend()) {
5393 current = *(track_views.rbegin());
5398 rui = dynamic_cast<RouteUI *>(current);
5399 } while ( current->hidden() || (rui != NULL && !rui->route()->active()));
5401 selection->set (current);
5403 ensure_track_visible(current);
5407 Editor::ensure_track_visible(TimeAxisView *track)
5409 if (track->hidden())
5412 double const current_view_min_y = vertical_adjustment.get_value();
5413 double const current_view_max_y = vertical_adjustment.get_value() + vertical_adjustment.get_page_size() - canvas_timebars_vsize;
5415 double const track_min_y = track->y_position ();
5416 double const track_max_y = track->y_position () + track->effective_height ();
5418 if (track_min_y >= current_view_min_y &&
5419 track_max_y <= current_view_max_y) {
5425 if (track_min_y < current_view_min_y) {
5426 // Track is above the current view
5427 new_value = track_min_y;
5429 // Track is below the current view
5430 new_value = track->y_position () + track->effective_height() + canvas_timebars_vsize - vertical_adjustment.get_page_size();
5433 vertical_adjustment.set_value(new_value);
5437 Editor::set_loop_from_selection (bool play)
5439 if (_session == 0 || selection->time.empty()) {
5443 framepos_t start = selection->time[clicked_selection].start;
5444 framepos_t end = selection->time[clicked_selection].end;
5446 set_loop_range (start, end, _("set loop range from selection"));
5449 _session->request_play_loop (true);
5450 _session->request_locate (start, true);
5455 Editor::set_loop_from_edit_range (bool play)
5457 if (_session == 0) {
5464 if (!get_edit_op_range (start, end)) {
5468 set_loop_range (start, end, _("set loop range from edit range"));
5471 _session->request_play_loop (true);
5472 _session->request_locate (start, true);
5477 Editor::set_loop_from_region (bool play)
5479 framepos_t start = max_framepos;
5482 RegionSelection rs = get_regions_from_selection_and_entered ();
5488 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5489 if ((*i)->region()->position() < start) {
5490 start = (*i)->region()->position();
5492 if ((*i)->region()->last_frame() + 1 > end) {
5493 end = (*i)->region()->last_frame() + 1;
5497 set_loop_range (start, end, _("set loop range from region"));
5500 _session->request_play_loop (true);
5501 _session->request_locate (start, true);
5506 Editor::set_punch_from_selection ()
5508 if (_session == 0 || selection->time.empty()) {
5512 framepos_t start = selection->time[clicked_selection].start;
5513 framepos_t end = selection->time[clicked_selection].end;
5515 set_punch_range (start, end, _("set punch range from selection"));
5519 Editor::set_punch_from_edit_range ()
5521 if (_session == 0) {
5528 if (!get_edit_op_range (start, end)) {
5532 set_punch_range (start, end, _("set punch range from edit range"));
5536 Editor::set_punch_from_region ()
5538 framepos_t start = max_framepos;
5541 RegionSelection rs = get_regions_from_selection_and_entered ();
5547 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5548 if ((*i)->region()->position() < start) {
5549 start = (*i)->region()->position();
5551 if ((*i)->region()->last_frame() + 1 > end) {
5552 end = (*i)->region()->last_frame() + 1;
5556 set_punch_range (start, end, _("set punch range from region"));
5560 Editor::pitch_shift_region ()
5562 RegionSelection rs = get_regions_from_selection_and_entered ();
5564 RegionSelection audio_rs;
5565 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5566 if (dynamic_cast<AudioRegionView*> (*i)) {
5567 audio_rs.push_back (*i);
5571 if (audio_rs.empty()) {
5575 pitch_shift (audio_rs, 1.2);
5579 Editor::transpose_region ()
5581 RegionSelection rs = get_regions_from_selection_and_entered ();
5583 list<MidiRegionView*> midi_region_views;
5584 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5585 MidiRegionView* mrv = dynamic_cast<MidiRegionView*> (*i);
5587 midi_region_views.push_back (mrv);
5592 int const r = d.run ();
5593 if (r != RESPONSE_ACCEPT) {
5597 for (list<MidiRegionView*>::iterator i = midi_region_views.begin(); i != midi_region_views.end(); ++i) {
5598 (*i)->midi_region()->transpose (d.semitones ());
5603 Editor::set_tempo_from_region ()
5605 RegionSelection rs = get_regions_from_selection_and_entered ();
5607 if (!_session || rs.empty()) {
5611 RegionView* rv = rs.front();
5613 define_one_bar (rv->region()->position(), rv->region()->last_frame() + 1);
5617 Editor::use_range_as_bar ()
5619 framepos_t start, end;
5620 if (get_edit_op_range (start, end)) {
5621 define_one_bar (start, end);
5626 Editor::define_one_bar (framepos_t start, framepos_t end)
5628 framepos_t length = end - start;
5630 const Meter& m (_session->tempo_map().meter_at (start));
5632 /* length = 1 bar */
5634 /* now we want frames per beat.
5635 we have frames per bar, and beats per bar, so ...
5638 /* XXXX METER MATH */
5640 double frames_per_beat = length / m.divisions_per_bar();
5642 /* beats per minute = */
5644 double beats_per_minute = (_session->frame_rate() * 60.0) / frames_per_beat;
5646 /* now decide whether to:
5648 (a) set global tempo
5649 (b) add a new tempo marker
5653 const TempoSection& t (_session->tempo_map().tempo_section_at (start));
5655 bool do_global = false;
5657 if ((_session->tempo_map().n_tempos() == 1) && (_session->tempo_map().n_meters() == 1)) {
5659 /* only 1 tempo & 1 meter: ask if the user wants to set the tempo
5660 at the start, or create a new marker
5663 vector<string> options;
5664 options.push_back (_("Cancel"));
5665 options.push_back (_("Add new marker"));
5666 options.push_back (_("Set global tempo"));
5669 _("Define one bar"),
5670 _("Do you want to set the global tempo or add a new tempo marker?"),
5674 c.set_default_response (2);
5690 /* more than 1 tempo and/or meter section already, go ahead do the "usual":
5691 if the marker is at the region starter, change it, otherwise add
5696 begin_reversible_command (_("set tempo from region"));
5697 XMLNode& before (_session->tempo_map().get_state());
5700 _session->tempo_map().change_initial_tempo (beats_per_minute, t.note_type());
5701 } else if (t.frame() == start) {
5702 _session->tempo_map().change_existing_tempo_at (start, beats_per_minute, t.note_type());
5704 _session->tempo_map().add_tempo (Tempo (beats_per_minute, t.note_type()), start);
5707 XMLNode& after (_session->tempo_map().get_state());
5709 _session->add_command (new MementoCommand<TempoMap>(_session->tempo_map(), &before, &after));
5710 commit_reversible_command ();
5714 Editor::split_region_at_transients ()
5716 AnalysisFeatureList positions;
5718 RegionSelection rs = get_regions_from_selection_and_entered ();
5720 if (!_session || rs.empty()) {
5724 _session->begin_reversible_command (_("split regions"));
5726 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ) {
5728 RegionSelection::iterator tmp;
5733 boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion> ((*i)->region());
5735 if (ar && (ar->get_transients (positions) == 0)) {
5736 split_region_at_points ((*i)->region(), positions, true);
5743 _session->commit_reversible_command ();
5748 Editor::split_region_at_points (boost::shared_ptr<Region> r, AnalysisFeatureList& positions, bool can_ferret, bool select_new)
5750 bool use_rhythmic_rodent = false;
5752 boost::shared_ptr<Playlist> pl = r->playlist();
5754 list<boost::shared_ptr<Region> > new_regions;
5760 if (positions.empty()) {
5765 if (positions.size() > 20 && can_ferret) {
5766 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);
5767 MessageDialog msg (msgstr,
5770 Gtk::BUTTONS_OK_CANCEL);
5773 msg.add_button (_("Call for the Ferret!"), RESPONSE_APPLY);
5774 msg.set_secondary_text (_("Press OK to continue with this split operation\nor ask the Ferret dialog to tune the analysis"));
5776 msg.set_secondary_text (_("Press OK to continue with this split operation"));
5779 msg.set_title (_("Excessive split?"));
5782 int response = msg.run();
5788 case RESPONSE_APPLY:
5789 use_rhythmic_rodent = true;
5796 if (use_rhythmic_rodent) {
5797 show_rhythm_ferret ();
5801 AnalysisFeatureList::const_iterator x;
5803 pl->clear_changes ();
5804 pl->clear_owned_changes ();
5806 x = positions.begin();
5808 if (x == positions.end()) {
5813 pl->remove_region (r);
5817 while (x != positions.end()) {
5819 /* deal with positons that are out of scope of present region bounds */
5820 if (*x <= 0 || *x > r->length()) {
5825 /* file start = original start + how far we from the initial position ?
5828 framepos_t file_start = r->start() + pos;
5830 /* length = next position - current position
5833 framepos_t len = (*x) - pos;
5835 /* XXX we do we really want to allow even single-sample regions?
5836 shouldn't we have some kind of lower limit on region size?
5845 if (RegionFactory::region_name (new_name, r->name())) {
5849 /* do NOT announce new regions 1 by one, just wait till they are all done */
5853 plist.add (ARDOUR::Properties::start, file_start);
5854 plist.add (ARDOUR::Properties::length, len);
5855 plist.add (ARDOUR::Properties::name, new_name);
5856 plist.add (ARDOUR::Properties::layer, 0);
5858 boost::shared_ptr<Region> nr = RegionFactory::create (r->sources(), plist, false);
5860 pl->add_region (nr, r->position() + pos);
5863 new_regions.push_front(nr);
5872 RegionFactory::region_name (new_name, r->name());
5874 /* Add the final region */
5877 plist.add (ARDOUR::Properties::start, r->start() + pos);
5878 plist.add (ARDOUR::Properties::length, r->last_frame() - (r->position() + pos) + 1);
5879 plist.add (ARDOUR::Properties::name, new_name);
5880 plist.add (ARDOUR::Properties::layer, 0);
5882 boost::shared_ptr<Region> nr = RegionFactory::create (r->sources(), plist, false);
5883 pl->add_region (nr, r->position() + pos);
5886 new_regions.push_front(nr);
5891 /* We might have removed regions, which alters other regions' layering_index,
5892 so we need to do a recursive diff here.
5894 vector<Command*> cmds;
5896 _session->add_commands (cmds);
5898 _session->add_command (new StatefulDiffCommand (pl));
5902 for (list<boost::shared_ptr<Region> >::iterator i = new_regions.begin(); i != new_regions.end(); ++i){
5903 set_selected_regionview_from_region_list ((*i), Selection::Add);
5909 Editor::place_transient()
5915 RegionSelection rs = get_regions_from_selection_and_edit_point ();
5921 framepos_t where = get_preferred_edit_position();
5923 _session->begin_reversible_command (_("place transient"));
5925 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
5926 framepos_t position = (*r)->region()->position();
5927 (*r)->region()->add_transient(where - position);
5930 _session->commit_reversible_command ();
5934 Editor::remove_transient(ArdourCanvas::Item* item)
5940 ArdourCanvas::Line* _line = reinterpret_cast<ArdourCanvas::Line*> (item);
5943 AudioRegionView* _arv = reinterpret_cast<AudioRegionView*> (item->get_data ("regionview"));
5944 _arv->remove_transient (*(float*) _line->get_data ("position"));
5948 Editor::snap_regions_to_grid ()
5950 list <boost::shared_ptr<Playlist > > used_playlists;
5952 RegionSelection rs = get_regions_from_selection_and_entered ();
5954 if (!_session || rs.empty()) {
5958 _session->begin_reversible_command (_("snap regions to grid"));
5960 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
5962 boost::shared_ptr<Playlist> pl = (*r)->region()->playlist();
5964 if (!pl->frozen()) {
5965 /* we haven't seen this playlist before */
5967 /* remember used playlists so we can thaw them later */
5968 used_playlists.push_back(pl);
5972 framepos_t start_frame = (*r)->region()->first_frame ();
5973 snap_to (start_frame);
5974 (*r)->region()->set_position (start_frame);
5977 while (used_playlists.size() > 0) {
5978 list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
5980 used_playlists.pop_front();
5983 _session->commit_reversible_command ();
5987 Editor::close_region_gaps ()
5989 list <boost::shared_ptr<Playlist > > used_playlists;
5991 RegionSelection rs = get_regions_from_selection_and_entered ();
5993 if (!_session || rs.empty()) {
5997 Dialog dialog (_("Close Region Gaps"));
6000 table.set_spacings (12);
6001 table.set_border_width (12);
6002 Label* l = manage (new Label (_("Crossfade length")));
6003 l->set_alignment (0, 0.5);
6004 table.attach (*l, 0, 1, 0, 1);
6006 SpinButton spin_crossfade (1, 0);
6007 spin_crossfade.set_range (0, 15);
6008 spin_crossfade.set_increments (1, 1);
6009 spin_crossfade.set_value (5);
6010 table.attach (spin_crossfade, 1, 2, 0, 1);
6012 table.attach (*manage (new Label (_("ms"))), 2, 3, 0, 1);
6014 l = manage (new Label (_("Pull-back length")));
6015 l->set_alignment (0, 0.5);
6016 table.attach (*l, 0, 1, 1, 2);
6018 SpinButton spin_pullback (1, 0);
6019 spin_pullback.set_range (0, 100);
6020 spin_pullback.set_increments (1, 1);
6021 spin_pullback.set_value(30);
6022 table.attach (spin_pullback, 1, 2, 1, 2);
6024 table.attach (*manage (new Label (_("ms"))), 2, 3, 1, 2);
6026 dialog.get_vbox()->pack_start (table);
6027 dialog.add_button (Stock::CANCEL, RESPONSE_CANCEL);
6028 dialog.add_button (_("Ok"), RESPONSE_ACCEPT);
6031 if (dialog.run () == RESPONSE_CANCEL) {
6035 framepos_t crossfade_len = spin_crossfade.get_value();
6036 framepos_t pull_back_frames = spin_pullback.get_value();
6038 crossfade_len = lrintf (crossfade_len * _session->frame_rate()/1000);
6039 pull_back_frames = lrintf (pull_back_frames * _session->frame_rate()/1000);
6041 /* Iterate over the region list and make adjacent regions overlap by crossfade_len_ms */
6043 _session->begin_reversible_command (_("close region gaps"));
6046 boost::shared_ptr<Region> last_region;
6048 rs.sort_by_position_and_track();
6050 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6052 boost::shared_ptr<Playlist> pl = (*r)->region()->playlist();
6054 if (!pl->frozen()) {
6055 /* we haven't seen this playlist before */
6057 /* remember used playlists so we can thaw them later */
6058 used_playlists.push_back(pl);
6062 framepos_t position = (*r)->region()->position();
6064 if (idx == 0 || position < last_region->position()){
6065 last_region = (*r)->region();
6070 (*r)->region()->trim_front( (position - pull_back_frames));
6071 last_region->trim_end( (position - pull_back_frames + crossfade_len));
6073 last_region = (*r)->region();
6078 while (used_playlists.size() > 0) {
6079 list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
6081 used_playlists.pop_front();
6084 _session->commit_reversible_command ();
6088 Editor::tab_to_transient (bool forward)
6090 AnalysisFeatureList positions;
6092 RegionSelection rs = get_regions_from_selection_and_entered ();
6098 framepos_t pos = _session->audible_frame ();
6100 if (!selection->tracks.empty()) {
6102 /* don't waste time searching for transients in duplicate playlists.
6105 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
6107 for (TrackViewList::iterator t = ts.begin(); t != ts.end(); ++t) {
6109 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*t);
6112 boost::shared_ptr<Track> tr = rtv->track();
6114 boost::shared_ptr<Playlist> pl = tr->playlist ();
6116 framepos_t result = pl->find_next_transient (pos, forward ? 1 : -1);
6119 positions.push_back (result);
6132 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6133 (*r)->region()->get_transients (positions);
6137 TransientDetector::cleanup_transients (positions, _session->frame_rate(), 3.0);
6140 AnalysisFeatureList::iterator x;
6142 for (x = positions.begin(); x != positions.end(); ++x) {
6148 if (x != positions.end ()) {
6149 _session->request_locate (*x);
6153 AnalysisFeatureList::reverse_iterator x;
6155 for (x = positions.rbegin(); x != positions.rend(); ++x) {
6161 if (x != positions.rend ()) {
6162 _session->request_locate (*x);
6168 Editor::playhead_forward_to_grid ()
6170 if (!_session) return;
6171 framepos_t pos = playhead_cursor->current_frame;
6172 if (pos < max_framepos - 1) {
6174 snap_to_internal (pos, 1, false);
6175 _session->request_locate (pos);
6181 Editor::playhead_backward_to_grid ()
6183 if (!_session) return;
6184 framepos_t pos = playhead_cursor->current_frame;
6187 snap_to_internal (pos, -1, false);
6188 _session->request_locate (pos);
6193 Editor::set_track_height (Height h)
6195 TrackSelection& ts (selection->tracks);
6197 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
6198 (*x)->set_height_enum (h);
6203 Editor::toggle_tracks_active ()
6205 TrackSelection& ts (selection->tracks);
6207 bool target = false;
6213 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
6214 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*x);
6218 target = !rtv->_route->active();
6221 rtv->_route->set_active (target, this);
6227 Editor::remove_tracks ()
6229 TrackSelection& ts (selection->tracks);
6235 vector<string> choices;
6239 const char* trackstr;
6241 vector<boost::shared_ptr<Route> > routes;
6242 bool special_bus = false;
6244 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
6245 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*x);
6247 if (rtv->is_track()) {
6253 routes.push_back (rtv->_route);
6255 if (rtv->route()->is_master() || rtv->route()->is_monitor()) {
6260 if (special_bus && !Config->get_allow_special_bus_removal()) {
6261 MessageDialog msg (_("That would be bad news ...."),
6265 msg.set_secondary_text (string_compose (_(
6266 "Removing the master or monitor bus is such a bad idea\n\
6267 that %1 is not going to allow it.\n\
6269 If you really want to do this sort of thing\n\
6270 edit your ardour.rc file to set the\n\
6271 \"allow-special-bus-removal\" option to be \"yes\""), PROGRAM_NAME));
6278 if (ntracks + nbusses == 0) {
6283 trackstr = _("tracks");
6285 trackstr = _("track");
6289 busstr = _("busses");
6296 prompt = string_compose (_("Do you really want to remove %1 %2 and %3 %4?\n"
6297 "(You may also lose the playlists associated with the %2)\n\n"
6298 "This action cannot be undone, and the session file will be overwritten!"),
6299 ntracks, trackstr, nbusses, busstr);
6301 prompt = string_compose (_("Do you really want to remove %1 %2?\n"
6302 "(You may also lose the playlists associated with the %2)\n\n"
6303 "This action cannot be undone, and the session file will be overwritten!"),
6306 } else if (nbusses) {
6307 prompt = string_compose (_("Do you really want to remove %1 %2?\n\n"
6308 "This action cannot be undon, and the session file will be overwritten"),
6312 choices.push_back (_("No, do nothing."));
6313 if (ntracks + nbusses > 1) {
6314 choices.push_back (_("Yes, remove them."));
6316 choices.push_back (_("Yes, remove it."));
6321 title = string_compose (_("Remove %1"), trackstr);
6323 title = string_compose (_("Remove %1"), busstr);
6326 Choice prompter (title, prompt, choices);
6328 if (prompter.run () != 1) {
6332 for (vector<boost::shared_ptr<Route> >::iterator x = routes.begin(); x != routes.end(); ++x) {
6333 _session->remove_route (*x);
6338 Editor::do_insert_time ()
6340 if (selection->tracks.empty()) {
6344 InsertTimeDialog d (*this);
6345 int response = d.run ();
6347 if (response != RESPONSE_OK) {
6351 if (d.distance() == 0) {
6355 InsertTimeOption opt = d.intersected_region_action ();
6358 get_preferred_edit_position(),
6364 d.move_glued_markers(),
6365 d.move_locked_markers(),
6371 Editor::insert_time (
6372 framepos_t pos, framecnt_t frames, InsertTimeOption opt,
6373 bool all_playlists, bool ignore_music_glue, bool markers_too, bool glued_markers_too, bool locked_markers_too, bool tempo_too
6376 bool commit = false;
6378 if (Config->get_edit_mode() == Lock) {
6382 begin_reversible_command (_("insert time"));
6384 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
6386 for (TrackViewList::iterator x = ts.begin(); x != ts.end(); ++x) {
6390 /* don't operate on any playlist more than once, which could
6391 * happen if "all playlists" is enabled, but there is more
6392 * than 1 track using playlists "from" a given track.
6395 set<boost::shared_ptr<Playlist> > pl;
6397 if (all_playlists) {
6398 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*x);
6400 vector<boost::shared_ptr<Playlist> > all = _session->playlists->playlists_for_track (rtav->track ());
6401 for (vector<boost::shared_ptr<Playlist> >::iterator p = all.begin(); p != all.end(); ++p) {
6406 if ((*x)->playlist ()) {
6407 pl.insert ((*x)->playlist ());
6411 for (set<boost::shared_ptr<Playlist> >::iterator i = pl.begin(); i != pl.end(); ++i) {
6413 (*i)->clear_changes ();
6414 (*i)->clear_owned_changes ();
6416 if (opt == SplitIntersected) {
6420 (*i)->shift (pos, frames, (opt == MoveIntersected), ignore_music_glue);
6422 vector<Command*> cmds;
6424 _session->add_commands (cmds);
6426 _session->add_command (new StatefulDiffCommand (*i));
6431 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*x);
6433 rtav->route ()->shift (pos, frames);
6441 XMLNode& before (_session->locations()->get_state());
6442 Locations::LocationList copy (_session->locations()->list());
6444 for (Locations::LocationList::iterator i = copy.begin(); i != copy.end(); ++i) {
6446 Locations::LocationList::const_iterator tmp;
6448 bool const was_locked = (*i)->locked ();
6449 if (locked_markers_too) {
6453 if ((*i)->position_lock_style() == AudioTime || glued_markers_too) {
6455 if ((*i)->start() >= pos) {
6456 (*i)->set_start ((*i)->start() + frames);
6457 if (!(*i)->is_mark()) {
6458 (*i)->set_end ((*i)->end() + frames);
6471 XMLNode& after (_session->locations()->get_state());
6472 _session->add_command (new MementoCommand<Locations>(*_session->locations(), &before, &after));
6477 _session->tempo_map().insert_time (pos, frames);
6481 commit_reversible_command ();
6486 Editor::fit_selected_tracks ()
6488 if (!selection->tracks.empty()) {
6489 fit_tracks (selection->tracks);
6493 /* no selected tracks - use tracks with selected regions */
6495 if (!selection->regions.empty()) {
6496 for (RegionSelection::iterator r = selection->regions.begin(); r != selection->regions.end(); ++r) {
6497 tvl.push_back (&(*r)->get_time_axis_view ());
6503 } else if (internal_editing()) {
6504 /* no selected tracks, or regions, but in internal edit mode, so follow the mouse and use
6507 if (entered_track) {
6508 tvl.push_back (entered_track);
6516 Editor::fit_tracks (TrackViewList & tracks)
6518 if (tracks.empty()) {
6522 uint32_t child_heights = 0;
6523 int visible_tracks = 0;
6525 for (TrackSelection::iterator t = tracks.begin(); t != tracks.end(); ++t) {
6527 if (!(*t)->marked_for_display()) {
6531 child_heights += (*t)->effective_height() - (*t)->current_height();
6535 uint32_t h = (uint32_t) floor ((_canvas_height - child_heights - canvas_timebars_vsize) / visible_tracks);
6536 double first_y_pos = DBL_MAX;
6538 if (h < TimeAxisView::preset_height (HeightSmall)) {
6539 MessageDialog msg (*this, _("There are too many tracks to fit in the current window"));
6540 /* too small to be displayed */
6544 undo_visual_stack.push_back (current_visual_state (true));
6545 no_save_visual = true;
6547 /* build a list of all tracks, including children */
6550 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
6552 TimeAxisView::Children c = (*i)->get_child_list ();
6553 for (TimeAxisView::Children::iterator j = c.begin(); j != c.end(); ++j) {
6554 all.push_back (j->get());
6558 /* operate on all tracks, hide unselected ones that are in the middle of selected ones */
6560 bool prev_was_selected = false;
6561 bool is_selected = tracks.contains (all.front());
6562 bool next_is_selected;
6564 for (TrackViewList::iterator t = all.begin(); t != all.end(); ++t) {
6566 TrackViewList::iterator next;
6571 if (next != all.end()) {
6572 next_is_selected = tracks.contains (*next);
6574 next_is_selected = false;
6577 if ((*t)->marked_for_display ()) {
6579 (*t)->set_height (h);
6580 first_y_pos = std::min ((*t)->y_position (), first_y_pos);
6582 if (prev_was_selected && next_is_selected) {
6583 hide_track_in_display (*t);
6588 prev_was_selected = is_selected;
6589 is_selected = next_is_selected;
6593 set the controls_layout height now, because waiting for its size
6594 request signal handler will cause the vertical adjustment setting to fail
6597 controls_layout.property_height () = full_canvas_height - canvas_timebars_vsize;
6598 vertical_adjustment.set_value (first_y_pos);
6600 redo_visual_stack.push_back (current_visual_state (true));
6604 Editor::save_visual_state (uint32_t n)
6606 while (visual_states.size() <= n) {
6607 visual_states.push_back (0);
6610 if (visual_states[n] != 0) {
6611 delete visual_states[n];
6614 visual_states[n] = current_visual_state (true);
6619 Editor::goto_visual_state (uint32_t n)
6621 if (visual_states.size() <= n) {
6625 if (visual_states[n] == 0) {
6629 use_visual_state (*visual_states[n]);
6633 Editor::start_visual_state_op (uint32_t n)
6635 save_visual_state (n);
6637 PopUp* pup = new PopUp (WIN_POS_MOUSE, 1000, true);
6639 snprintf (buf, sizeof (buf), _("Saved view %u"), n+1);
6640 pup->set_text (buf);
6645 Editor::cancel_visual_state_op (uint32_t n)
6647 goto_visual_state (n);
6651 Editor::toggle_region_mute ()
6653 if (_ignore_region_action) {
6657 RegionSelection rs = get_regions_from_selection_and_entered ();
6663 if (rs.size() > 1) {
6664 begin_reversible_command (_("mute regions"));
6666 begin_reversible_command (_("mute region"));
6669 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
6671 (*i)->region()->playlist()->clear_changes ();
6672 (*i)->region()->set_muted (!(*i)->region()->muted ());
6673 _session->add_command (new StatefulDiffCommand ((*i)->region()->playlist()));
6677 commit_reversible_command ();
6681 Editor::combine_regions ()
6683 /* foreach track with selected regions, take all selected regions
6684 and join them into a new region containing the subregions (as a
6688 typedef set<RouteTimeAxisView*> RTVS;
6691 if (selection->regions.empty()) {
6695 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
6696 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(&(*i)->get_time_axis_view());
6699 tracks.insert (rtv);
6703 begin_reversible_command (_("combine regions"));
6705 vector<RegionView*> new_selection;
6707 for (RTVS::iterator i = tracks.begin(); i != tracks.end(); ++i) {
6710 if ((rv = (*i)->combine_regions ()) != 0) {
6711 new_selection.push_back (rv);
6715 selection->clear_regions ();
6716 for (vector<RegionView*>::iterator i = new_selection.begin(); i != new_selection.end(); ++i) {
6717 selection->add (*i);
6720 commit_reversible_command ();
6724 Editor::uncombine_regions ()
6726 typedef set<RouteTimeAxisView*> RTVS;
6729 if (selection->regions.empty()) {
6733 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
6734 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(&(*i)->get_time_axis_view());
6737 tracks.insert (rtv);
6741 begin_reversible_command (_("uncombine regions"));
6743 for (RTVS::iterator i = tracks.begin(); i != tracks.end(); ++i) {
6744 (*i)->uncombine_regions ();
6747 commit_reversible_command ();