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 ();
3397 clicked_routeview->audio_track()->freeze_me (*current_interthread_info);
3398 current_interthread_info->done = true;
3403 Editor::freeze_route ()
3409 /* stop transport before we start. this is important */
3411 _session->request_transport_speed (0.0);
3413 /* wait for just a little while, because the above call is asynchronous */
3417 if (clicked_routeview == 0 || !clicked_routeview->is_audio_track()) {
3421 if (!clicked_routeview->track()->bounceable (clicked_routeview->track()->main_outs(), true)) {
3423 _("This track/bus cannot be frozen because the signal adds or loses channels before reaching the outputs.\n"
3424 "This is typically caused by plugins that generate stereo output from mono input or vice versa.")
3426 d.set_title (_("Cannot freeze"));
3431 if (clicked_routeview->track()->has_external_redirects()) {
3432 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"
3433 "Freezing will only process the signal as far as the first send/insert/return."),
3434 clicked_routeview->track()->name()), true, MESSAGE_INFO, BUTTONS_NONE, true);
3436 d.add_button (_("Freeze anyway"), Gtk::RESPONSE_OK);
3437 d.add_button (_("Don't freeze"), Gtk::RESPONSE_CANCEL);
3438 d.set_title (_("Freeze Limits"));
3440 int response = d.run ();
3443 case Gtk::RESPONSE_CANCEL:
3450 InterThreadInfo itt;
3451 current_interthread_info = &itt;
3453 InterthreadProgressWindow ipw (current_interthread_info, _("Freeze"), _("Cancel Freeze"));
3455 pthread_create_and_store (X_("freezer"), &itt.thread, _freeze_thread, this);
3457 set_canvas_cursor (_cursors->wait);
3459 while (!itt.done && !itt.cancel) {
3460 gtk_main_iteration ();
3463 current_interthread_info = 0;
3464 set_canvas_cursor (current_canvas_cursor);
3468 Editor::bounce_range_selection (bool replace, bool enable_processing)
3470 if (selection->time.empty()) {
3474 TrackSelection views = selection->tracks;
3476 for (TrackViewList::iterator i = views.begin(); i != views.end(); ++i) {
3478 if (enable_processing) {
3480 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*i);
3482 if (rtv && rtv->track() && replace && enable_processing && !rtv->track()->bounceable (rtv->track()->main_outs(), false)) {
3484 _("You can't perform this operation because the processing of the signal "
3485 "will cause one or more of the tracks will end up with a region with more channels than this track has inputs.\n\n"
3486 "You can do this without processing, which is a different operation.")
3488 d.set_title (_("Cannot bounce"));
3495 framepos_t start = selection->time[clicked_selection].start;
3496 framepos_t end = selection->time[clicked_selection].end;
3497 framepos_t cnt = end - start + 1;
3499 begin_reversible_command (_("bounce range"));
3501 for (TrackViewList::iterator i = views.begin(); i != views.end(); ++i) {
3503 RouteTimeAxisView* rtv;
3505 if ((rtv = dynamic_cast<RouteTimeAxisView*> (*i)) == 0) {
3509 boost::shared_ptr<Playlist> playlist;
3511 if ((playlist = rtv->playlist()) == 0) {
3515 InterThreadInfo itt;
3517 playlist->clear_changes ();
3518 playlist->clear_owned_changes ();
3520 boost::shared_ptr<Region> r;
3522 if (enable_processing) {
3523 r = rtv->track()->bounce_range (start, start+cnt, itt, rtv->track()->main_outs(), false);
3525 r = rtv->track()->bounce_range (start, start+cnt, itt, boost::shared_ptr<Processor>(), false);
3533 list<AudioRange> ranges;
3534 ranges.push_back (AudioRange (start, start+cnt, 0));
3535 playlist->cut (ranges); // discard result
3536 playlist->add_region (r, start);
3539 vector<Command*> cmds;
3540 playlist->rdiff (cmds);
3541 _session->add_commands (cmds);
3543 _session->add_command (new StatefulDiffCommand (playlist));
3546 commit_reversible_command ();
3549 /** Delete selected regions, automation points or a time range */
3556 /** Cut selected regions, automation points or a time range */
3563 /** Copy selected regions, automation points or a time range */
3571 /** @return true if a Cut, Copy or Clear is possible */
3573 Editor::can_cut_copy () const
3575 switch (current_mouse_mode()) {
3578 if (!selection->regions.empty() || !selection->points.empty()) {
3584 if (!selection->time.empty()) {
3597 /** Cut, copy or clear selected regions, automation points or a time range.
3598 * @param op Operation (Cut, Copy or Clear)
3601 Editor::cut_copy (CutCopyOp op)
3603 /* only cancel selection if cut/copy is successful.*/
3609 opname = _("delete");
3618 opname = _("clear");
3622 /* if we're deleting something, and the mouse is still pressed,
3623 the thing we started a drag for will be gone when we release
3624 the mouse button(s). avoid this. see part 2 at the end of
3628 if (op == Delete || op == Cut || op == Clear) {
3629 if (_drags->active ()) {
3634 cut_buffer->clear ();
3636 if (entered_marker) {
3638 /* cut/delete op while pointing at a marker */
3641 Location* loc = find_location_from_marker (entered_marker, ignored);
3643 if (_session && loc) {
3644 Glib::signal_idle().connect (sigc::bind (sigc::mem_fun(*this, &Editor::really_remove_marker), loc));
3651 if (internal_editing()) {
3653 switch (current_mouse_mode()) {
3666 /* we only want to cut regions if some are selected */
3668 if (doing_object_stuff()) {
3669 rs = get_regions_from_selection ();
3670 if (!rs.empty() || !selection->points.empty()) {
3672 begin_reversible_command (opname + _(" objects"));
3675 cut_copy_regions (op, rs);
3677 if (op == Cut || op == Delete) {
3678 selection->clear_regions ();
3682 if (!selection->points.empty()) {
3683 cut_copy_points (op);
3685 if (op == Cut || op == Delete) {
3686 selection->clear_points ();
3689 commit_reversible_command ();
3692 if (!selection->time.empty() && (_join_object_range_state == JOIN_OBJECT_RANGE_NONE)) {
3693 /* don't cause suprises */
3698 if (doing_range_stuff()) {
3699 if (selection->time.empty()) {
3700 framepos_t start, end;
3701 if (!get_edit_op_range (start, end)) {
3704 selection->set (start, end);
3707 begin_reversible_command (opname + _(" range"));
3708 cut_copy_ranges (op);
3709 commit_reversible_command ();
3711 if (op == Cut || op == Delete) {
3712 selection->clear_time ();
3718 if (op == Delete || op == Cut || op == Clear) {
3723 /** Cut, copy or clear selected automation points.
3724 * @param op Operation (Cut, Copy or Clear)
3727 Editor::cut_copy_points (CutCopyOp op)
3729 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
3731 AutomationTimeAxisView* atv = dynamic_cast<AutomationTimeAxisView*>((*i).track);
3732 _last_cut_copy_source_track = atv;
3735 atv->cut_copy_clear_objects (selection->points, op);
3740 /** Cut, copy or clear selected automation points.
3741 * @param op Operation (Cut, Copy or Clear)
3744 Editor::cut_copy_midi (CutCopyOp op)
3746 for (MidiRegionSelection::iterator i = selection->midi_regions.begin(); i != selection->midi_regions.end(); ++i) {
3747 MidiRegionView* mrv = *i;
3748 mrv->cut_copy_clear (op);
3754 struct lt_playlist {
3755 bool operator () (const PlaylistState& a, const PlaylistState& b) {
3756 return a.playlist < b.playlist;
3760 struct PlaylistMapping {
3762 boost::shared_ptr<Playlist> pl;
3764 PlaylistMapping (TimeAxisView* tvp) : tv (tvp) {}
3767 /** Remove `clicked_regionview' */
3769 Editor::remove_clicked_region ()
3771 if (clicked_routeview == 0 || clicked_regionview == 0) {
3775 boost::shared_ptr<Playlist> playlist = clicked_routeview->playlist();
3777 begin_reversible_command (_("remove region"));
3778 playlist->clear_changes ();
3779 playlist->clear_owned_changes ();
3780 playlist->remove_region (clicked_regionview->region());
3782 /* We might have removed regions, which alters other regions' layering_index,
3783 so we need to do a recursive diff here.
3785 vector<Command*> cmds;
3786 playlist->rdiff (cmds);
3787 _session->add_commands (cmds);
3789 _session->add_command(new StatefulDiffCommand (playlist));
3790 commit_reversible_command ();
3794 /** Remove the selected regions */
3796 Editor::remove_selected_regions ()
3798 RegionSelection rs = get_regions_from_selection_and_entered ();
3800 if (!_session || rs.empty()) {
3804 begin_reversible_command (_("remove region"));
3806 list<boost::shared_ptr<Region> > regions_to_remove;
3808 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3809 // we can't just remove the region(s) in this loop because
3810 // this removes them from the RegionSelection, and they thus
3811 // disappear from underneath the iterator, and the ++i above
3812 // SEGVs in a puzzling fashion.
3814 // so, first iterate over the regions to be removed from rs and
3815 // add them to the regions_to_remove list, and then
3816 // iterate over the list to actually remove them.
3818 regions_to_remove.push_back ((*i)->region());
3821 vector<boost::shared_ptr<Playlist> > playlists;
3823 for (list<boost::shared_ptr<Region> >::iterator rl = regions_to_remove.begin(); rl != regions_to_remove.end(); ++rl) {
3825 boost::shared_ptr<Playlist> playlist = (*rl)->playlist();
3828 // is this check necessary?
3832 /* get_regions_from_selection_and_entered() guarantees that
3833 the playlists involved are unique, so there is no need
3837 playlists.push_back (playlist);
3839 playlist->clear_changes ();
3840 playlist->clear_owned_changes ();
3841 playlist->freeze ();
3842 playlist->remove_region (*rl);
3845 vector<boost::shared_ptr<Playlist> >::iterator pl;
3847 for (pl = playlists.begin(); pl != playlists.end(); ++pl) {
3850 /* We might have removed regions, which alters other regions' layering_index,
3851 so we need to do a recursive diff here.
3853 vector<Command*> cmds;
3854 (*pl)->rdiff (cmds);
3855 _session->add_commands (cmds);
3857 _session->add_command(new StatefulDiffCommand (*pl));
3860 commit_reversible_command ();
3863 /** Cut, copy or clear selected regions.
3864 * @param op Operation (Cut, Copy or Clear)
3867 Editor::cut_copy_regions (CutCopyOp op, RegionSelection& rs)
3869 /* we can't use a std::map here because the ordering is important, and we can't trivially sort
3870 a map when we want ordered access to both elements. i think.
3873 vector<PlaylistMapping> pmap;
3875 framepos_t first_position = max_framepos;
3877 typedef set<boost::shared_ptr<Playlist> > FreezeList;
3878 FreezeList freezelist;
3880 /* get ordering correct before we cut/copy */
3882 rs.sort_by_position_and_track ();
3884 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
3886 first_position = min ((framepos_t) (*x)->region()->position(), first_position);
3888 if (op == Cut || op == Clear || op == Delete) {
3889 boost::shared_ptr<Playlist> pl = (*x)->region()->playlist();
3892 FreezeList::iterator fl;
3894 // only take state if this is a new playlist.
3895 for (fl = freezelist.begin(); fl != freezelist.end(); ++fl) {
3901 if (fl == freezelist.end()) {
3902 pl->clear_changes();
3903 pl->clear_owned_changes ();
3905 freezelist.insert (pl);
3910 TimeAxisView* tv = &(*x)->get_time_axis_view();
3911 vector<PlaylistMapping>::iterator z;
3913 for (z = pmap.begin(); z != pmap.end(); ++z) {
3914 if ((*z).tv == tv) {
3919 if (z == pmap.end()) {
3920 pmap.push_back (PlaylistMapping (tv));
3924 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ) {
3926 boost::shared_ptr<Playlist> pl = (*x)->region()->playlist();
3929 /* region not yet associated with a playlist (e.g. unfinished
3936 TimeAxisView& tv = (*x)->get_time_axis_view();
3937 boost::shared_ptr<Playlist> npl;
3938 RegionSelection::iterator tmp;
3945 vector<PlaylistMapping>::iterator z;
3947 for (z = pmap.begin(); z != pmap.end(); ++z) {
3948 if ((*z).tv == &tv) {
3953 assert (z != pmap.end());
3956 npl = PlaylistFactory::create (pl->data_type(), *_session, "cutlist", true);
3964 boost::shared_ptr<Region> r = (*x)->region();
3965 boost::shared_ptr<Region> _xx;
3971 pl->remove_region (r);
3975 _xx = RegionFactory::create (r);
3976 npl->add_region (_xx, r->position() - first_position);
3977 pl->remove_region (r);
3981 /* copy region before adding, so we're not putting same object into two different playlists */
3982 npl->add_region (RegionFactory::create (r), r->position() - first_position);
3986 pl->remove_region (r);
3995 list<boost::shared_ptr<Playlist> > foo;
3997 /* the pmap is in the same order as the tracks in which selected regions occured */
3999 for (vector<PlaylistMapping>::iterator i = pmap.begin(); i != pmap.end(); ++i) {
4002 foo.push_back ((*i).pl);
4007 cut_buffer->set (foo);
4011 _last_cut_copy_source_track = 0;
4013 _last_cut_copy_source_track = pmap.front().tv;
4017 for (FreezeList::iterator pl = freezelist.begin(); pl != freezelist.end(); ++pl) {
4020 /* We might have removed regions, which alters other regions' layering_index,
4021 so we need to do a recursive diff here.
4023 vector<Command*> cmds;
4024 (*pl)->rdiff (cmds);
4025 _session->add_commands (cmds);
4027 _session->add_command (new StatefulDiffCommand (*pl));
4032 Editor::cut_copy_ranges (CutCopyOp op)
4034 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4036 /* Sort the track selection now, so that it if is used, the playlists
4037 selected by the calls below to cut_copy_clear are in the order that
4038 their tracks appear in the editor. This makes things like paste
4039 of ranges work properly.
4042 sort_track_selection (ts);
4045 if (!entered_track) {
4048 ts.push_back (entered_track);
4051 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4052 (*i)->cut_copy_clear (*selection, op);
4057 Editor::paste (float times, bool from_context)
4059 DEBUG_TRACE (DEBUG::CutNPaste, "paste to preferred edit pos\n");
4061 paste_internal (get_preferred_edit_position (false, from_context), times);
4065 Editor::mouse_paste ()
4070 if (!mouse_frame (where, ignored)) {
4075 paste_internal (where, 1);
4079 Editor::paste_internal (framepos_t position, float times)
4081 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("apparent paste position is %1\n", position));
4083 if (internal_editing()) {
4084 if (cut_buffer->midi_notes.empty()) {
4088 if (cut_buffer->empty()) {
4093 if (position == max_framepos) {
4094 position = get_preferred_edit_position();
4095 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("preferred edit position is %1\n", position));
4099 TrackViewList::iterator i;
4102 /* get everything in the correct order */
4104 if (!selection->tracks.empty()) {
4105 /* there are some selected tracks, so paste to them */
4106 ts = selection->tracks.filter_to_unique_playlists ();
4107 sort_track_selection (ts);
4108 } else if (_last_cut_copy_source_track) {
4109 /* otherwise paste to the track that the cut/copy came from;
4110 see discussion in mantis #3333.
4112 ts.push_back (_last_cut_copy_source_track);
4115 if (internal_editing ()) {
4117 /* undo/redo is handled by individual tracks/regions */
4119 for (nth = 0, i = ts.begin(); i != ts.end(); ++i, ++nth) {
4122 RegionSelection::iterator r;
4123 MidiNoteSelection::iterator cb;
4125 get_regions_at (rs, position, ts);
4127 for (cb = cut_buffer->midi_notes.begin(), r = rs.begin();
4128 cb != cut_buffer->midi_notes.end() && r != rs.end(); ++r) {
4129 MidiRegionView* mrv = dynamic_cast<MidiRegionView*> (*r);
4131 mrv->paste (position, times, **cb);
4139 /* we do redo (do you do voodoo?) */
4141 begin_reversible_command (Operations::paste);
4143 for (nth = 0, i = ts.begin(); i != ts.end(); ++i, ++nth) {
4144 (*i)->paste (position, times, *cut_buffer, nth);
4147 commit_reversible_command ();
4152 Editor::duplicate_some_regions (RegionSelection& regions, float times)
4154 boost::shared_ptr<Playlist> playlist;
4155 RegionSelection sel = regions; // clear (below) may clear the argument list if its the current region selection
4156 RegionSelection foo;
4158 framepos_t const start_frame = regions.start ();
4159 framepos_t const end_frame = regions.end_frame ();
4161 begin_reversible_command (Operations::duplicate_region);
4163 selection->clear_regions ();
4165 for (RegionSelection::iterator i = sel.begin(); i != sel.end(); ++i) {
4167 boost::shared_ptr<Region> r ((*i)->region());
4169 TimeAxisView& tv = (*i)->get_time_axis_view();
4170 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (&tv);
4171 latest_regionviews.clear ();
4172 sigc::connection c = rtv->view()->RegionViewAdded.connect (sigc::mem_fun(*this, &Editor::collect_new_region_view));
4174 playlist = (*i)->region()->playlist();
4175 playlist->clear_changes ();
4176 playlist->duplicate (r, end_frame + (r->first_frame() - start_frame), times);
4177 _session->add_command(new StatefulDiffCommand (playlist));
4181 foo.insert (foo.end(), latest_regionviews.begin(), latest_regionviews.end());
4184 commit_reversible_command ();
4187 selection->set (foo);
4192 Editor::duplicate_selection (float times)
4194 if (selection->time.empty() || selection->tracks.empty()) {
4198 boost::shared_ptr<Playlist> playlist;
4199 vector<boost::shared_ptr<Region> > new_regions;
4200 vector<boost::shared_ptr<Region> >::iterator ri;
4202 create_region_from_selection (new_regions);
4204 if (new_regions.empty()) {
4208 begin_reversible_command (_("duplicate selection"));
4210 ri = new_regions.begin();
4212 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4214 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4215 if ((playlist = (*i)->playlist()) == 0) {
4218 playlist->clear_changes ();
4219 playlist->duplicate (*ri, selection->time[clicked_selection].end, times);
4220 _session->add_command (new StatefulDiffCommand (playlist));
4223 if (ri == new_regions.end()) {
4228 commit_reversible_command ();
4232 Editor::reset_point_selection ()
4234 /* reset all selected points to the relevant default value */
4236 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
4238 AutomationTimeAxisView* atv = dynamic_cast<AutomationTimeAxisView*>((*i).track);
4241 atv->reset_objects (selection->points);
4247 Editor::center_playhead ()
4249 float page = _canvas_width * frames_per_unit;
4250 center_screen_internal (playhead_cursor->current_frame, page);
4254 Editor::center_edit_point ()
4256 float page = _canvas_width * frames_per_unit;
4257 center_screen_internal (get_preferred_edit_position(), page);
4260 /** Caller must begin and commit a reversible command */
4262 Editor::clear_playlist (boost::shared_ptr<Playlist> playlist)
4264 playlist->clear_changes ();
4266 _session->add_command (new StatefulDiffCommand (playlist));
4270 Editor::nudge_track (bool use_edit, bool forwards)
4272 boost::shared_ptr<Playlist> playlist;
4273 framepos_t distance;
4274 framepos_t next_distance;
4278 start = get_preferred_edit_position();
4283 if ((distance = get_nudge_distance (start, next_distance)) == 0) {
4287 if (selection->tracks.empty()) {
4291 begin_reversible_command (_("nudge track"));
4293 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4295 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4297 if ((playlist = (*i)->playlist()) == 0) {
4301 playlist->clear_changes ();
4302 playlist->clear_owned_changes ();
4304 playlist->nudge_after (start, distance, forwards);
4306 vector<Command*> cmds;
4308 playlist->rdiff (cmds);
4309 _session->add_commands (cmds);
4311 _session->add_command (new StatefulDiffCommand (playlist));
4314 commit_reversible_command ();
4318 Editor::remove_last_capture ()
4320 vector<string> choices;
4327 if (Config->get_verify_remove_last_capture()) {
4328 prompt = _("Do you really want to destroy the last capture?"
4329 "\n(This is destructive and cannot be undone)");
4331 choices.push_back (_("No, do nothing."));
4332 choices.push_back (_("Yes, destroy it."));
4334 Gtkmm2ext::Choice prompter (_("Destroy last capture"), prompt, choices);
4336 if (prompter.run () == 1) {
4337 _session->remove_last_capture ();
4338 _regions->redisplay ();
4342 _session->remove_last_capture();
4343 _regions->redisplay ();
4348 Editor::normalize_region ()
4354 RegionSelection rs = get_regions_from_selection_and_entered ();
4360 NormalizeDialog dialog (rs.size() > 1);
4362 if (dialog.run () == RESPONSE_CANCEL) {
4366 set_canvas_cursor (_cursors->wait);
4369 /* XXX: should really only count audio regions here */
4370 int const regions = rs.size ();
4372 /* Make a list of the selected audio regions' maximum amplitudes, and also
4373 obtain the maximum amplitude of them all.
4375 list<double> max_amps;
4377 for (RegionSelection::const_iterator i = rs.begin(); i != rs.end(); ++i) {
4378 AudioRegionView const * arv = dynamic_cast<AudioRegionView const *> (*i);
4380 dialog.descend (1.0 / regions);
4381 double const a = arv->audio_region()->maximum_amplitude (&dialog);
4384 /* the user cancelled the operation */
4385 set_canvas_cursor (current_canvas_cursor);
4389 max_amps.push_back (a);
4390 max_amp = max (max_amp, a);
4395 begin_reversible_command (_("normalize"));
4397 list<double>::const_iterator a = max_amps.begin ();
4399 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
4400 AudioRegionView* const arv = dynamic_cast<AudioRegionView*> (*r);
4405 arv->region()->clear_changes ();
4407 double const amp = dialog.normalize_individually() ? *a : max_amp;
4409 arv->audio_region()->normalize (amp, dialog.target ());
4410 _session->add_command (new StatefulDiffCommand (arv->region()));
4415 commit_reversible_command ();
4416 set_canvas_cursor (current_canvas_cursor);
4421 Editor::reset_region_scale_amplitude ()
4427 RegionSelection rs = get_regions_from_selection_and_entered ();
4433 begin_reversible_command ("reset gain");
4435 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
4436 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
4439 arv->region()->clear_changes ();
4440 arv->audio_region()->set_scale_amplitude (1.0f);
4441 _session->add_command (new StatefulDiffCommand (arv->region()));
4444 commit_reversible_command ();
4448 Editor::adjust_region_gain (bool up)
4450 RegionSelection rs = get_regions_from_selection_and_entered ();
4452 if (!_session || rs.empty()) {
4456 begin_reversible_command ("adjust region gain");
4458 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
4459 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
4464 arv->region()->clear_changes ();
4466 double dB = accurate_coefficient_to_dB (arv->audio_region()->scale_amplitude ());
4474 arv->audio_region()->set_scale_amplitude (dB_to_coefficient (dB));
4475 _session->add_command (new StatefulDiffCommand (arv->region()));
4478 commit_reversible_command ();
4483 Editor::reverse_region ()
4489 Reverse rev (*_session);
4490 apply_filter (rev, _("reverse regions"));
4494 Editor::strip_region_silence ()
4500 RegionSelection rs = get_regions_from_selection_and_entered ();
4506 std::list<RegionView*> audio_only;
4508 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
4509 AudioRegionView* const arv = dynamic_cast<AudioRegionView*> (*i);
4511 audio_only.push_back (arv);
4515 StripSilenceDialog d (_session, audio_only);
4516 int const r = d.run ();
4520 if (r == Gtk::RESPONSE_OK) {
4521 ARDOUR::AudioIntervalMap silences;
4522 d.silences (silences);
4523 StripSilence s (*_session, silences, d.fade_length());
4524 apply_filter (s, _("strip silence"), &d);
4529 Editor::apply_midi_note_edit_op_to_region (MidiOperator& op, MidiRegionView& mrv)
4531 Evoral::Sequence<Evoral::MusicalTime>::Notes selected;
4532 mrv.selection_as_notelist (selected, true);
4534 vector<Evoral::Sequence<Evoral::MusicalTime>::Notes> v;
4535 v.push_back (selected);
4537 framepos_t pos_frames = mrv.midi_region()->position();
4538 double pos_beats = _session->tempo_map().framewalk_to_beats(0, pos_frames);
4540 return op (mrv.midi_region()->model(), pos_beats, v);
4544 Editor::apply_midi_note_edit_op (MidiOperator& op)
4548 RegionSelection rs = get_regions_from_selection_and_entered ();
4554 begin_reversible_command (op.name ());
4556 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
4557 RegionSelection::iterator tmp = r;
4560 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*r);
4563 cmd = apply_midi_note_edit_op_to_region (op, *mrv);
4566 _session->add_command (cmd);
4573 commit_reversible_command ();
4577 Editor::fork_region ()
4579 RegionSelection rs = get_regions_from_selection_and_entered ();
4585 begin_reversible_command (_("Fork Region(s)"));
4587 set_canvas_cursor (_cursors->wait);
4590 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
4591 RegionSelection::iterator tmp = r;
4594 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*>(*r);
4597 boost::shared_ptr<Playlist> playlist = mrv->region()->playlist();
4598 boost::shared_ptr<MidiRegion> newregion = mrv->midi_region()->clone ();
4600 playlist->clear_changes ();
4601 playlist->replace_region (mrv->region(), newregion, mrv->region()->position());
4602 _session->add_command(new StatefulDiffCommand (playlist));
4608 commit_reversible_command ();
4610 set_canvas_cursor (current_canvas_cursor);
4614 Editor::quantize_region ()
4616 int selected_midi_region_cnt = 0;
4622 RegionSelection rs = get_regions_from_selection_and_entered ();
4628 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
4629 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*r);
4631 selected_midi_region_cnt++;
4635 if (selected_midi_region_cnt == 0) {
4639 QuantizeDialog* qd = new QuantizeDialog (*this);
4642 const int r = qd->run ();
4645 if (r == Gtk::RESPONSE_OK) {
4646 Quantize quant (*_session, Plain,
4647 qd->snap_start(), qd->snap_end(),
4648 qd->start_grid_size(), qd->end_grid_size(),
4649 qd->strength(), qd->swing(), qd->threshold());
4651 apply_midi_note_edit_op (quant);
4656 Editor::insert_patch_change (bool from_context)
4658 RegionSelection rs = get_regions_from_selection_and_entered ();
4664 const framepos_t p = get_preferred_edit_position (false, from_context);
4666 Evoral::PatchChange<Evoral::MusicalTime> empty (0, 0, 0, 0);
4667 PatchChangeDialog d (0, _session, empty, Gtk::Stock::ADD);
4669 if (d.run() == RESPONSE_CANCEL) {
4673 for (RegionSelection::iterator i = rs.begin (); i != rs.end(); ++i) {
4674 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*i);
4676 if (p >= mrv->region()->first_frame() && p <= mrv->region()->last_frame()) {
4677 mrv->add_patch_change (p - mrv->region()->position(), d.patch ());
4684 Editor::apply_filter (Filter& filter, string command, ProgressReporter* progress)
4686 RegionSelection rs = get_regions_from_selection_and_entered ();
4692 begin_reversible_command (command);
4694 set_canvas_cursor (_cursors->wait);
4698 int const N = rs.size ();
4700 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
4701 RegionSelection::iterator tmp = r;
4704 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
4706 boost::shared_ptr<Playlist> playlist = arv->region()->playlist();
4709 progress->descend (1.0 / N);
4712 if (arv->audio_region()->apply (filter, progress) == 0) {
4714 playlist->clear_changes ();
4715 playlist->clear_owned_changes ();
4717 if (filter.results.empty ()) {
4719 /* no regions returned; remove the old one */
4720 playlist->remove_region (arv->region ());
4724 std::vector<boost::shared_ptr<Region> >::iterator res = filter.results.begin ();
4726 /* first region replaces the old one */
4727 playlist->replace_region (arv->region(), *res, (*res)->position());
4731 while (res != filter.results.end()) {
4732 playlist->add_region (*res, (*res)->position());
4738 /* We might have removed regions, which alters other regions' layering_index,
4739 so we need to do a recursive diff here.
4741 vector<Command*> cmds;
4742 playlist->rdiff (cmds);
4743 _session->add_commands (cmds);
4745 _session->add_command(new StatefulDiffCommand (playlist));
4751 progress->ascend ();
4759 commit_reversible_command ();
4762 set_canvas_cursor (current_canvas_cursor);
4766 Editor::external_edit_region ()
4772 Editor::reset_region_gain_envelopes ()
4774 RegionSelection rs = get_regions_from_selection_and_entered ();
4776 if (!_session || rs.empty()) {
4780 _session->begin_reversible_command (_("reset region gain"));
4782 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
4783 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
4785 boost::shared_ptr<AutomationList> alist (arv->audio_region()->envelope());
4786 XMLNode& before (alist->get_state());
4788 arv->audio_region()->set_default_envelope ();
4789 _session->add_command (new MementoCommand<AutomationList>(*arv->audio_region()->envelope().get(), &before, &alist->get_state()));
4793 _session->commit_reversible_command ();
4797 Editor::set_region_gain_visibility (RegionView* rv, bool yn)
4799 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (rv);
4801 arv->set_envelope_visible (yn);
4806 Editor::set_gain_envelope_visibility (bool yn)
4812 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4813 AudioTimeAxisView* v = dynamic_cast<AudioTimeAxisView*>(*i);
4815 v->audio_view()->foreach_regionview (sigc::bind (sigc::mem_fun (this, &Editor::set_region_gain_visibility), yn));
4821 Editor::toggle_gain_envelope_active ()
4823 if (_ignore_region_action) {
4827 RegionSelection rs = get_regions_from_selection_and_entered ();
4829 if (!_session || rs.empty()) {
4833 _session->begin_reversible_command (_("region gain envelope active"));
4835 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
4836 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
4838 arv->region()->clear_changes ();
4839 arv->audio_region()->set_envelope_active (!arv->audio_region()->envelope_active());
4840 _session->add_command (new StatefulDiffCommand (arv->region()));
4844 _session->commit_reversible_command ();
4848 Editor::toggle_region_lock ()
4850 if (_ignore_region_action) {
4854 RegionSelection rs = get_regions_from_selection_and_entered ();
4856 if (!_session || rs.empty()) {
4860 _session->begin_reversible_command (_("toggle region lock"));
4862 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
4863 (*i)->region()->clear_changes ();
4864 (*i)->region()->set_locked (!(*i)->region()->locked());
4865 _session->add_command (new StatefulDiffCommand ((*i)->region()));
4868 _session->commit_reversible_command ();
4872 Editor::toggle_region_lock_style ()
4874 if (_ignore_region_action) {
4878 RegionSelection rs = get_regions_from_selection_and_entered ();
4880 if (!_session || rs.empty()) {
4884 _session->begin_reversible_command (_("region lock style"));
4886 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
4887 (*i)->region()->clear_changes ();
4888 PositionLockStyle const ns = (*i)->region()->position_lock_style() == AudioTime ? MusicTime : AudioTime;
4889 (*i)->region()->set_position_lock_style (ns);
4890 _session->add_command (new StatefulDiffCommand ((*i)->region()));
4893 _session->commit_reversible_command ();
4897 Editor::toggle_opaque_region ()
4899 if (_ignore_region_action) {
4903 RegionSelection rs = get_regions_from_selection_and_entered ();
4905 if (!_session || rs.empty()) {
4909 _session->begin_reversible_command (_("change region opacity"));
4911 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
4912 (*i)->region()->clear_changes ();
4913 (*i)->region()->set_opaque (!(*i)->region()->opaque());
4914 _session->add_command (new StatefulDiffCommand ((*i)->region()));
4917 _session->commit_reversible_command ();
4921 Editor::toggle_record_enable ()
4923 bool new_state = false;
4925 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4926 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
4929 if (!rtav->is_track())
4933 new_state = !rtav->track()->record_enabled();
4937 rtav->track()->set_record_enabled (new_state, this);
4942 Editor::toggle_solo ()
4944 bool new_state = false;
4946 boost::shared_ptr<RouteList> rl (new RouteList);
4948 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4949 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
4956 new_state = !rtav->route()->soloed ();
4960 rl->push_back (rtav->route());
4963 _session->set_solo (rl, new_state, Session::rt_cleanup, true);
4967 Editor::toggle_mute ()
4969 bool new_state = false;
4971 boost::shared_ptr<RouteList> rl (new RouteList);
4973 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4974 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
4981 new_state = !rtav->route()->muted();
4985 rl->push_back (rtav->route());
4988 _session->set_mute (rl, new_state, Session::rt_cleanup, true);
4992 Editor::toggle_solo_isolate ()
4997 Editor::set_fade_length (bool in)
4999 RegionSelection rs = get_regions_from_selection_and_entered ();
5005 /* we need a region to measure the offset from the start */
5007 RegionView* rv = rs.front ();
5009 framepos_t pos = get_preferred_edit_position();
5013 if (pos > rv->region()->last_frame() || pos < rv->region()->first_frame()) {
5014 /* edit point is outside the relevant region */
5019 if (pos <= rv->region()->position()) {
5023 len = pos - rv->region()->position();
5024 cmd = _("set fade in length");
5026 if (pos >= rv->region()->last_frame()) {
5030 len = rv->region()->last_frame() - pos;
5031 cmd = _("set fade out length");
5034 begin_reversible_command (cmd);
5036 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5037 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5043 boost::shared_ptr<AutomationList> alist;
5045 alist = tmp->audio_region()->fade_in();
5047 alist = tmp->audio_region()->fade_out();
5050 XMLNode &before = alist->get_state();
5053 tmp->audio_region()->set_fade_in_length (len);
5054 tmp->audio_region()->set_fade_in_active (true);
5056 tmp->audio_region()->set_fade_out_length (len);
5057 tmp->audio_region()->set_fade_out_active (true);
5060 XMLNode &after = alist->get_state();
5061 _session->add_command(new MementoCommand<AutomationList>(*alist, &before, &after));
5064 commit_reversible_command ();
5068 Editor::set_fade_in_shape (FadeShape shape)
5070 RegionSelection rs = get_regions_from_selection_and_entered ();
5076 begin_reversible_command (_("set fade in shape"));
5078 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5079 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5085 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_in();
5086 XMLNode &before = alist->get_state();
5088 tmp->audio_region()->set_fade_in_shape (shape);
5090 XMLNode &after = alist->get_state();
5091 _session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
5094 commit_reversible_command ();
5099 Editor::set_fade_out_shape (FadeShape shape)
5101 RegionSelection rs = get_regions_from_selection_and_entered ();
5107 begin_reversible_command (_("set fade out shape"));
5109 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5110 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5116 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_out();
5117 XMLNode &before = alist->get_state();
5119 tmp->audio_region()->set_fade_out_shape (shape);
5121 XMLNode &after = alist->get_state();
5122 _session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
5125 commit_reversible_command ();
5129 Editor::set_fade_in_active (bool yn)
5131 RegionSelection rs = get_regions_from_selection_and_entered ();
5137 begin_reversible_command (_("set fade in active"));
5139 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5140 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5147 boost::shared_ptr<AudioRegion> ar (tmp->audio_region());
5149 ar->clear_changes ();
5150 ar->set_fade_in_active (yn);
5151 _session->add_command (new StatefulDiffCommand (ar));
5154 commit_reversible_command ();
5158 Editor::set_fade_out_active (bool yn)
5160 RegionSelection rs = get_regions_from_selection_and_entered ();
5166 begin_reversible_command (_("set fade out active"));
5168 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5169 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5175 boost::shared_ptr<AudioRegion> ar (tmp->audio_region());
5177 ar->clear_changes ();
5178 ar->set_fade_out_active (yn);
5179 _session->add_command(new StatefulDiffCommand (ar));
5182 commit_reversible_command ();
5186 Editor::toggle_region_fades (int dir)
5188 boost::shared_ptr<AudioRegion> ar;
5191 RegionSelection rs = get_regions_from_selection_and_entered ();
5197 RegionSelection::iterator i;
5198 for (i = rs.begin(); i != rs.end(); ++i) {
5199 if ((ar = boost::dynamic_pointer_cast<AudioRegion>((*i)->region())) != 0) {
5201 yn = ar->fade_out_active ();
5203 yn = ar->fade_in_active ();
5209 if (i == rs.end()) {
5213 /* XXX should this undo-able? */
5215 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5216 if ((ar = boost::dynamic_pointer_cast<AudioRegion>((*i)->region())) == 0) {
5219 if (dir == 1 || dir == 0) {
5220 ar->set_fade_in_active (!yn);
5223 if (dir == -1 || dir == 0) {
5224 ar->set_fade_out_active (!yn);
5230 /** Update region fade visibility after its configuration has been changed */
5232 Editor::update_region_fade_visibility ()
5234 bool _fade_visibility = _session->config.get_show_region_fades ();
5236 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5237 AudioTimeAxisView* v = dynamic_cast<AudioTimeAxisView*>(*i);
5239 if (_fade_visibility) {
5240 v->audio_view()->show_all_fades ();
5242 v->audio_view()->hide_all_fades ();
5249 Editor::set_edit_point ()
5254 if (!mouse_frame (where, ignored)) {
5260 if (selection->markers.empty()) {
5262 mouse_add_new_marker (where);
5267 Location* loc = find_location_from_marker (selection->markers.front(), ignored);
5270 loc->move_to (where);
5276 Editor::set_playhead_cursor ()
5278 if (entered_marker) {
5279 _session->request_locate (entered_marker->position(), _session->transport_rolling());
5284 if (!mouse_frame (where, ignored)) {
5291 _session->request_locate (where, _session->transport_rolling());
5297 Editor::split_region ()
5299 if (((mouse_mode == MouseRange) ||
5300 (mouse_mode != MouseObject && _join_object_range_state == JOIN_OBJECT_RANGE_RANGE)) &&
5301 !selection->time.empty()) {
5302 separate_regions_between (selection->time);
5306 RegionSelection rs = get_regions_from_selection_and_edit_point ();
5308 framepos_t where = get_preferred_edit_position ();
5314 split_regions_at (where, rs);
5318 Editor::ensure_entered_track_selected (bool op_really_wants_one_track_if_none_are_selected)
5320 if (entered_track && mouse_mode == MouseObject) {
5321 if (!selection->tracks.empty()) {
5322 if (!selection->selected (entered_track)) {
5323 selection->add (entered_track);
5326 /* there is no selection, but this operation requires/prefers selected objects */
5328 if (op_really_wants_one_track_if_none_are_selected) {
5329 selection->set (entered_track);
5335 struct EditorOrderRouteSorter {
5336 bool operator() (boost::shared_ptr<Route> a, boost::shared_ptr<Route> b) {
5337 /* use of ">" forces the correct sort order */
5338 return a->order_key ("editor") < b->order_key ("editor");
5343 Editor::select_next_route()
5345 if (selection->tracks.empty()) {
5346 selection->set (track_views.front());
5350 TimeAxisView* current = selection->tracks.front();
5354 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5355 if (*i == current) {
5357 if (i != track_views.end()) {
5360 current = (*(track_views.begin()));
5361 //selection->set (*(track_views.begin()));
5366 rui = dynamic_cast<RouteUI *>(current);
5367 } while ( current->hidden() || (rui != NULL && !rui->route()->active()));
5369 selection->set(current);
5371 ensure_track_visible(current);
5375 Editor::select_prev_route()
5377 if (selection->tracks.empty()) {
5378 selection->set (track_views.front());
5382 TimeAxisView* current = selection->tracks.front();
5386 for (TrackViewList::reverse_iterator i = track_views.rbegin(); i != track_views.rend(); ++i) {
5387 if (*i == current) {
5389 if (i != track_views.rend()) {
5392 current = *(track_views.rbegin());
5397 rui = dynamic_cast<RouteUI *>(current);
5398 } while ( current->hidden() || (rui != NULL && !rui->route()->active()));
5400 selection->set (current);
5402 ensure_track_visible(current);
5406 Editor::ensure_track_visible(TimeAxisView *track)
5408 if (track->hidden())
5411 double const current_view_min_y = vertical_adjustment.get_value();
5412 double const current_view_max_y = vertical_adjustment.get_value() + vertical_adjustment.get_page_size() - canvas_timebars_vsize;
5414 double const track_min_y = track->y_position ();
5415 double const track_max_y = track->y_position () + track->effective_height ();
5417 if (track_min_y >= current_view_min_y &&
5418 track_max_y <= current_view_max_y) {
5424 if (track_min_y < current_view_min_y) {
5425 // Track is above the current view
5426 new_value = track_min_y;
5428 // Track is below the current view
5429 new_value = track->y_position () + track->effective_height() + canvas_timebars_vsize - vertical_adjustment.get_page_size();
5432 vertical_adjustment.set_value(new_value);
5436 Editor::set_loop_from_selection (bool play)
5438 if (_session == 0 || selection->time.empty()) {
5442 framepos_t start = selection->time[clicked_selection].start;
5443 framepos_t end = selection->time[clicked_selection].end;
5445 set_loop_range (start, end, _("set loop range from selection"));
5448 _session->request_play_loop (true);
5449 _session->request_locate (start, true);
5454 Editor::set_loop_from_edit_range (bool play)
5456 if (_session == 0) {
5463 if (!get_edit_op_range (start, end)) {
5467 set_loop_range (start, end, _("set loop range from edit range"));
5470 _session->request_play_loop (true);
5471 _session->request_locate (start, true);
5476 Editor::set_loop_from_region (bool play)
5478 framepos_t start = max_framepos;
5481 RegionSelection rs = get_regions_from_selection_and_entered ();
5487 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5488 if ((*i)->region()->position() < start) {
5489 start = (*i)->region()->position();
5491 if ((*i)->region()->last_frame() + 1 > end) {
5492 end = (*i)->region()->last_frame() + 1;
5496 set_loop_range (start, end, _("set loop range from region"));
5499 _session->request_play_loop (true);
5500 _session->request_locate (start, true);
5505 Editor::set_punch_from_selection ()
5507 if (_session == 0 || selection->time.empty()) {
5511 framepos_t start = selection->time[clicked_selection].start;
5512 framepos_t end = selection->time[clicked_selection].end;
5514 set_punch_range (start, end, _("set punch range from selection"));
5518 Editor::set_punch_from_edit_range ()
5520 if (_session == 0) {
5527 if (!get_edit_op_range (start, end)) {
5531 set_punch_range (start, end, _("set punch range from edit range"));
5535 Editor::set_punch_from_region ()
5537 framepos_t start = max_framepos;
5540 RegionSelection rs = get_regions_from_selection_and_entered ();
5546 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5547 if ((*i)->region()->position() < start) {
5548 start = (*i)->region()->position();
5550 if ((*i)->region()->last_frame() + 1 > end) {
5551 end = (*i)->region()->last_frame() + 1;
5555 set_punch_range (start, end, _("set punch range from region"));
5559 Editor::pitch_shift_region ()
5561 RegionSelection rs = get_regions_from_selection_and_entered ();
5563 RegionSelection audio_rs;
5564 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5565 if (dynamic_cast<AudioRegionView*> (*i)) {
5566 audio_rs.push_back (*i);
5570 if (audio_rs.empty()) {
5574 pitch_shift (audio_rs, 1.2);
5578 Editor::transpose_region ()
5580 RegionSelection rs = get_regions_from_selection_and_entered ();
5582 list<MidiRegionView*> midi_region_views;
5583 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5584 MidiRegionView* mrv = dynamic_cast<MidiRegionView*> (*i);
5586 midi_region_views.push_back (mrv);
5591 int const r = d.run ();
5592 if (r != RESPONSE_ACCEPT) {
5596 for (list<MidiRegionView*>::iterator i = midi_region_views.begin(); i != midi_region_views.end(); ++i) {
5597 (*i)->midi_region()->transpose (d.semitones ());
5602 Editor::set_tempo_from_region ()
5604 RegionSelection rs = get_regions_from_selection_and_entered ();
5606 if (!_session || rs.empty()) {
5610 RegionView* rv = rs.front();
5612 define_one_bar (rv->region()->position(), rv->region()->last_frame() + 1);
5616 Editor::use_range_as_bar ()
5618 framepos_t start, end;
5619 if (get_edit_op_range (start, end)) {
5620 define_one_bar (start, end);
5625 Editor::define_one_bar (framepos_t start, framepos_t end)
5627 framepos_t length = end - start;
5629 const Meter& m (_session->tempo_map().meter_at (start));
5631 /* length = 1 bar */
5633 /* now we want frames per beat.
5634 we have frames per bar, and beats per bar, so ...
5637 /* XXXX METER MATH */
5639 double frames_per_beat = length / m.divisions_per_bar();
5641 /* beats per minute = */
5643 double beats_per_minute = (_session->frame_rate() * 60.0) / frames_per_beat;
5645 /* now decide whether to:
5647 (a) set global tempo
5648 (b) add a new tempo marker
5652 const TempoSection& t (_session->tempo_map().tempo_section_at (start));
5654 bool do_global = false;
5656 if ((_session->tempo_map().n_tempos() == 1) && (_session->tempo_map().n_meters() == 1)) {
5658 /* only 1 tempo & 1 meter: ask if the user wants to set the tempo
5659 at the start, or create a new marker
5662 vector<string> options;
5663 options.push_back (_("Cancel"));
5664 options.push_back (_("Add new marker"));
5665 options.push_back (_("Set global tempo"));
5668 _("Define one bar"),
5669 _("Do you want to set the global tempo or add a new tempo marker?"),
5673 c.set_default_response (2);
5689 /* more than 1 tempo and/or meter section already, go ahead do the "usual":
5690 if the marker is at the region starter, change it, otherwise add
5695 begin_reversible_command (_("set tempo from region"));
5696 XMLNode& before (_session->tempo_map().get_state());
5699 _session->tempo_map().change_initial_tempo (beats_per_minute, t.note_type());
5700 } else if (t.frame() == start) {
5701 _session->tempo_map().change_existing_tempo_at (start, beats_per_minute, t.note_type());
5703 _session->tempo_map().add_tempo (Tempo (beats_per_minute, t.note_type()), start);
5706 XMLNode& after (_session->tempo_map().get_state());
5708 _session->add_command (new MementoCommand<TempoMap>(_session->tempo_map(), &before, &after));
5709 commit_reversible_command ();
5713 Editor::split_region_at_transients ()
5715 AnalysisFeatureList positions;
5717 RegionSelection rs = get_regions_from_selection_and_entered ();
5719 if (!_session || rs.empty()) {
5723 _session->begin_reversible_command (_("split regions"));
5725 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ) {
5727 RegionSelection::iterator tmp;
5732 boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion> ((*i)->region());
5734 if (ar && (ar->get_transients (positions) == 0)) {
5735 split_region_at_points ((*i)->region(), positions, true);
5742 _session->commit_reversible_command ();
5747 Editor::split_region_at_points (boost::shared_ptr<Region> r, AnalysisFeatureList& positions, bool can_ferret, bool select_new)
5749 bool use_rhythmic_rodent = false;
5751 boost::shared_ptr<Playlist> pl = r->playlist();
5753 list<boost::shared_ptr<Region> > new_regions;
5759 if (positions.empty()) {
5764 if (positions.size() > 20 && can_ferret) {
5765 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);
5766 MessageDialog msg (msgstr,
5769 Gtk::BUTTONS_OK_CANCEL);
5772 msg.add_button (_("Call for the Ferret!"), RESPONSE_APPLY);
5773 msg.set_secondary_text (_("Press OK to continue with this split operation\nor ask the Ferret dialog to tune the analysis"));
5775 msg.set_secondary_text (_("Press OK to continue with this split operation"));
5778 msg.set_title (_("Excessive split?"));
5781 int response = msg.run();
5787 case RESPONSE_APPLY:
5788 use_rhythmic_rodent = true;
5795 if (use_rhythmic_rodent) {
5796 show_rhythm_ferret ();
5800 AnalysisFeatureList::const_iterator x;
5802 pl->clear_changes ();
5803 pl->clear_owned_changes ();
5805 x = positions.begin();
5807 if (x == positions.end()) {
5812 pl->remove_region (r);
5816 while (x != positions.end()) {
5818 /* deal with positons that are out of scope of present region bounds */
5819 if (*x <= 0 || *x > r->length()) {
5824 /* file start = original start + how far we from the initial position ?
5827 framepos_t file_start = r->start() + pos;
5829 /* length = next position - current position
5832 framepos_t len = (*x) - pos;
5834 /* XXX we do we really want to allow even single-sample regions?
5835 shouldn't we have some kind of lower limit on region size?
5844 if (RegionFactory::region_name (new_name, r->name())) {
5848 /* do NOT announce new regions 1 by one, just wait till they are all done */
5852 plist.add (ARDOUR::Properties::start, file_start);
5853 plist.add (ARDOUR::Properties::length, len);
5854 plist.add (ARDOUR::Properties::name, new_name);
5855 plist.add (ARDOUR::Properties::layer, 0);
5857 boost::shared_ptr<Region> nr = RegionFactory::create (r->sources(), plist, false);
5859 pl->add_region (nr, r->position() + pos);
5862 new_regions.push_front(nr);
5871 RegionFactory::region_name (new_name, r->name());
5873 /* Add the final region */
5876 plist.add (ARDOUR::Properties::start, r->start() + pos);
5877 plist.add (ARDOUR::Properties::length, r->last_frame() - (r->position() + pos) + 1);
5878 plist.add (ARDOUR::Properties::name, new_name);
5879 plist.add (ARDOUR::Properties::layer, 0);
5881 boost::shared_ptr<Region> nr = RegionFactory::create (r->sources(), plist, false);
5882 pl->add_region (nr, r->position() + pos);
5885 new_regions.push_front(nr);
5890 /* We might have removed regions, which alters other regions' layering_index,
5891 so we need to do a recursive diff here.
5893 vector<Command*> cmds;
5895 _session->add_commands (cmds);
5897 _session->add_command (new StatefulDiffCommand (pl));
5901 for (list<boost::shared_ptr<Region> >::iterator i = new_regions.begin(); i != new_regions.end(); ++i){
5902 set_selected_regionview_from_region_list ((*i), Selection::Add);
5908 Editor::place_transient()
5914 RegionSelection rs = get_regions_from_selection_and_edit_point ();
5920 framepos_t where = get_preferred_edit_position();
5922 _session->begin_reversible_command (_("place transient"));
5924 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
5925 framepos_t position = (*r)->region()->position();
5926 (*r)->region()->add_transient(where - position);
5929 _session->commit_reversible_command ();
5933 Editor::remove_transient(ArdourCanvas::Item* item)
5939 ArdourCanvas::Line* _line = reinterpret_cast<ArdourCanvas::Line*> (item);
5942 AudioRegionView* _arv = reinterpret_cast<AudioRegionView*> (item->get_data ("regionview"));
5943 _arv->remove_transient (*(float*) _line->get_data ("position"));
5947 Editor::snap_regions_to_grid ()
5949 list <boost::shared_ptr<Playlist > > used_playlists;
5951 RegionSelection rs = get_regions_from_selection_and_entered ();
5953 if (!_session || rs.empty()) {
5957 _session->begin_reversible_command (_("snap regions to grid"));
5959 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
5961 boost::shared_ptr<Playlist> pl = (*r)->region()->playlist();
5963 if (!pl->frozen()) {
5964 /* we haven't seen this playlist before */
5966 /* remember used playlists so we can thaw them later */
5967 used_playlists.push_back(pl);
5971 framepos_t start_frame = (*r)->region()->first_frame ();
5972 snap_to (start_frame);
5973 (*r)->region()->set_position (start_frame);
5976 while (used_playlists.size() > 0) {
5977 list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
5979 used_playlists.pop_front();
5982 _session->commit_reversible_command ();
5986 Editor::close_region_gaps ()
5988 list <boost::shared_ptr<Playlist > > used_playlists;
5990 RegionSelection rs = get_regions_from_selection_and_entered ();
5992 if (!_session || rs.empty()) {
5996 Dialog dialog (_("Close Region Gaps"));
5999 table.set_spacings (12);
6000 table.set_border_width (12);
6001 Label* l = manage (new Label (_("Crossfade length")));
6002 l->set_alignment (0, 0.5);
6003 table.attach (*l, 0, 1, 0, 1);
6005 SpinButton spin_crossfade (1, 0);
6006 spin_crossfade.set_range (0, 15);
6007 spin_crossfade.set_increments (1, 1);
6008 spin_crossfade.set_value (5);
6009 table.attach (spin_crossfade, 1, 2, 0, 1);
6011 table.attach (*manage (new Label (_("ms"))), 2, 3, 0, 1);
6013 l = manage (new Label (_("Pull-back length")));
6014 l->set_alignment (0, 0.5);
6015 table.attach (*l, 0, 1, 1, 2);
6017 SpinButton spin_pullback (1, 0);
6018 spin_pullback.set_range (0, 100);
6019 spin_pullback.set_increments (1, 1);
6020 spin_pullback.set_value(30);
6021 table.attach (spin_pullback, 1, 2, 1, 2);
6023 table.attach (*manage (new Label (_("ms"))), 2, 3, 1, 2);
6025 dialog.get_vbox()->pack_start (table);
6026 dialog.add_button (Stock::CANCEL, RESPONSE_CANCEL);
6027 dialog.add_button (_("Ok"), RESPONSE_ACCEPT);
6030 if (dialog.run () == RESPONSE_CANCEL) {
6034 framepos_t crossfade_len = spin_crossfade.get_value();
6035 framepos_t pull_back_frames = spin_pullback.get_value();
6037 crossfade_len = lrintf (crossfade_len * _session->frame_rate()/1000);
6038 pull_back_frames = lrintf (pull_back_frames * _session->frame_rate()/1000);
6040 /* Iterate over the region list and make adjacent regions overlap by crossfade_len_ms */
6042 _session->begin_reversible_command (_("close region gaps"));
6045 boost::shared_ptr<Region> last_region;
6047 rs.sort_by_position_and_track();
6049 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6051 boost::shared_ptr<Playlist> pl = (*r)->region()->playlist();
6053 if (!pl->frozen()) {
6054 /* we haven't seen this playlist before */
6056 /* remember used playlists so we can thaw them later */
6057 used_playlists.push_back(pl);
6061 framepos_t position = (*r)->region()->position();
6063 if (idx == 0 || position < last_region->position()){
6064 last_region = (*r)->region();
6069 (*r)->region()->trim_front( (position - pull_back_frames));
6070 last_region->trim_end( (position - pull_back_frames + crossfade_len));
6072 last_region = (*r)->region();
6077 while (used_playlists.size() > 0) {
6078 list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
6080 used_playlists.pop_front();
6083 _session->commit_reversible_command ();
6087 Editor::tab_to_transient (bool forward)
6089 AnalysisFeatureList positions;
6091 RegionSelection rs = get_regions_from_selection_and_entered ();
6097 framepos_t pos = _session->audible_frame ();
6099 if (!selection->tracks.empty()) {
6101 /* don't waste time searching for transients in duplicate playlists.
6104 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
6106 for (TrackViewList::iterator t = ts.begin(); t != ts.end(); ++t) {
6108 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*t);
6111 boost::shared_ptr<Track> tr = rtv->track();
6113 boost::shared_ptr<Playlist> pl = tr->playlist ();
6115 framepos_t result = pl->find_next_transient (pos, forward ? 1 : -1);
6118 positions.push_back (result);
6131 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6132 (*r)->region()->get_transients (positions);
6136 TransientDetector::cleanup_transients (positions, _session->frame_rate(), 3.0);
6139 AnalysisFeatureList::iterator x;
6141 for (x = positions.begin(); x != positions.end(); ++x) {
6147 if (x != positions.end ()) {
6148 _session->request_locate (*x);
6152 AnalysisFeatureList::reverse_iterator x;
6154 for (x = positions.rbegin(); x != positions.rend(); ++x) {
6160 if (x != positions.rend ()) {
6161 _session->request_locate (*x);
6167 Editor::playhead_forward_to_grid ()
6169 if (!_session) return;
6170 framepos_t pos = playhead_cursor->current_frame;
6171 if (pos < max_framepos - 1) {
6173 snap_to_internal (pos, 1, false);
6174 _session->request_locate (pos);
6180 Editor::playhead_backward_to_grid ()
6182 if (!_session) return;
6183 framepos_t pos = playhead_cursor->current_frame;
6186 snap_to_internal (pos, -1, false);
6187 _session->request_locate (pos);
6192 Editor::set_track_height (Height h)
6194 TrackSelection& ts (selection->tracks);
6196 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
6197 (*x)->set_height_enum (h);
6202 Editor::toggle_tracks_active ()
6204 TrackSelection& ts (selection->tracks);
6206 bool target = false;
6212 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
6213 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*x);
6217 target = !rtv->_route->active();
6220 rtv->_route->set_active (target, this);
6226 Editor::remove_tracks ()
6228 TrackSelection& ts (selection->tracks);
6234 vector<string> choices;
6238 const char* trackstr;
6240 vector<boost::shared_ptr<Route> > routes;
6241 bool special_bus = false;
6243 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
6244 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*x);
6246 if (rtv->is_track()) {
6252 routes.push_back (rtv->_route);
6254 if (rtv->route()->is_master() || rtv->route()->is_monitor()) {
6259 if (special_bus && !Config->get_allow_special_bus_removal()) {
6260 MessageDialog msg (_("That would be bad news ...."),
6264 msg.set_secondary_text (string_compose (_(
6265 "Removing the master or monitor bus is such a bad idea\n\
6266 that %1 is not going to allow it.\n\
6268 If you really want to do this sort of thing\n\
6269 edit your ardour.rc file to set the\n\
6270 \"allow-special-bus-removal\" option to be \"yes\""), PROGRAM_NAME));
6277 if (ntracks + nbusses == 0) {
6282 trackstr = _("tracks");
6284 trackstr = _("track");
6288 busstr = _("busses");
6295 prompt = string_compose (_("Do you really want to remove %1 %2 and %3 %4?\n"
6296 "(You may also lose the playlists associated with the %2)\n\n"
6297 "This action cannot be undone, and the session file will be overwritten!"),
6298 ntracks, trackstr, nbusses, busstr);
6300 prompt = string_compose (_("Do you really want to remove %1 %2?\n"
6301 "(You may also lose the playlists associated with the %2)\n\n"
6302 "This action cannot be undone, and the session file will be overwritten!"),
6305 } else if (nbusses) {
6306 prompt = string_compose (_("Do you really want to remove %1 %2?\n\n"
6307 "This action cannot be undon, and the session file will be overwritten"),
6311 choices.push_back (_("No, do nothing."));
6312 if (ntracks + nbusses > 1) {
6313 choices.push_back (_("Yes, remove them."));
6315 choices.push_back (_("Yes, remove it."));
6320 title = string_compose (_("Remove %1"), trackstr);
6322 title = string_compose (_("Remove %1"), busstr);
6325 Choice prompter (title, prompt, choices);
6327 if (prompter.run () != 1) {
6331 for (vector<boost::shared_ptr<Route> >::iterator x = routes.begin(); x != routes.end(); ++x) {
6332 _session->remove_route (*x);
6337 Editor::do_insert_time ()
6339 if (selection->tracks.empty()) {
6343 InsertTimeDialog d (*this);
6344 int response = d.run ();
6346 if (response != RESPONSE_OK) {
6350 if (d.distance() == 0) {
6354 InsertTimeOption opt = d.intersected_region_action ();
6357 get_preferred_edit_position(),
6363 d.move_glued_markers(),
6364 d.move_locked_markers(),
6370 Editor::insert_time (
6371 framepos_t pos, framecnt_t frames, InsertTimeOption opt,
6372 bool all_playlists, bool ignore_music_glue, bool markers_too, bool glued_markers_too, bool locked_markers_too, bool tempo_too
6375 bool commit = false;
6377 if (Config->get_edit_mode() == Lock) {
6381 begin_reversible_command (_("insert time"));
6383 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
6385 for (TrackViewList::iterator x = ts.begin(); x != ts.end(); ++x) {
6389 /* don't operate on any playlist more than once, which could
6390 * happen if "all playlists" is enabled, but there is more
6391 * than 1 track using playlists "from" a given track.
6394 set<boost::shared_ptr<Playlist> > pl;
6396 if (all_playlists) {
6397 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*x);
6399 vector<boost::shared_ptr<Playlist> > all = _session->playlists->playlists_for_track (rtav->track ());
6400 for (vector<boost::shared_ptr<Playlist> >::iterator p = all.begin(); p != all.end(); ++p) {
6405 if ((*x)->playlist ()) {
6406 pl.insert ((*x)->playlist ());
6410 for (set<boost::shared_ptr<Playlist> >::iterator i = pl.begin(); i != pl.end(); ++i) {
6412 (*i)->clear_changes ();
6413 (*i)->clear_owned_changes ();
6415 if (opt == SplitIntersected) {
6419 (*i)->shift (pos, frames, (opt == MoveIntersected), ignore_music_glue);
6421 vector<Command*> cmds;
6423 _session->add_commands (cmds);
6425 _session->add_command (new StatefulDiffCommand (*i));
6430 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*x);
6432 rtav->route ()->shift (pos, frames);
6440 XMLNode& before (_session->locations()->get_state());
6441 Locations::LocationList copy (_session->locations()->list());
6443 for (Locations::LocationList::iterator i = copy.begin(); i != copy.end(); ++i) {
6445 Locations::LocationList::const_iterator tmp;
6447 bool const was_locked = (*i)->locked ();
6448 if (locked_markers_too) {
6452 if ((*i)->position_lock_style() == AudioTime || glued_markers_too) {
6454 if ((*i)->start() >= pos) {
6455 (*i)->set_start ((*i)->start() + frames);
6456 if (!(*i)->is_mark()) {
6457 (*i)->set_end ((*i)->end() + frames);
6470 XMLNode& after (_session->locations()->get_state());
6471 _session->add_command (new MementoCommand<Locations>(*_session->locations(), &before, &after));
6476 _session->tempo_map().insert_time (pos, frames);
6480 commit_reversible_command ();
6485 Editor::fit_selected_tracks ()
6487 if (!selection->tracks.empty()) {
6488 fit_tracks (selection->tracks);
6492 /* no selected tracks - use tracks with selected regions */
6494 if (!selection->regions.empty()) {
6495 for (RegionSelection::iterator r = selection->regions.begin(); r != selection->regions.end(); ++r) {
6496 tvl.push_back (&(*r)->get_time_axis_view ());
6502 } else if (internal_editing()) {
6503 /* no selected tracks, or regions, but in internal edit mode, so follow the mouse and use
6506 if (entered_track) {
6507 tvl.push_back (entered_track);
6515 Editor::fit_tracks (TrackViewList & tracks)
6517 if (tracks.empty()) {
6521 uint32_t child_heights = 0;
6522 int visible_tracks = 0;
6524 for (TrackSelection::iterator t = tracks.begin(); t != tracks.end(); ++t) {
6526 if (!(*t)->marked_for_display()) {
6530 child_heights += (*t)->effective_height() - (*t)->current_height();
6534 uint32_t h = (uint32_t) floor ((_canvas_height - child_heights - canvas_timebars_vsize) / visible_tracks);
6535 double first_y_pos = DBL_MAX;
6537 if (h < TimeAxisView::preset_height (HeightSmall)) {
6538 MessageDialog msg (*this, _("There are too many tracks to fit in the current window"));
6539 /* too small to be displayed */
6543 undo_visual_stack.push_back (current_visual_state (true));
6544 no_save_visual = true;
6546 /* build a list of all tracks, including children */
6549 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
6551 TimeAxisView::Children c = (*i)->get_child_list ();
6552 for (TimeAxisView::Children::iterator j = c.begin(); j != c.end(); ++j) {
6553 all.push_back (j->get());
6557 /* operate on all tracks, hide unselected ones that are in the middle of selected ones */
6559 bool prev_was_selected = false;
6560 bool is_selected = tracks.contains (all.front());
6561 bool next_is_selected;
6563 for (TrackViewList::iterator t = all.begin(); t != all.end(); ++t) {
6565 TrackViewList::iterator next;
6570 if (next != all.end()) {
6571 next_is_selected = tracks.contains (*next);
6573 next_is_selected = false;
6576 if ((*t)->marked_for_display ()) {
6578 (*t)->set_height (h);
6579 first_y_pos = std::min ((*t)->y_position (), first_y_pos);
6581 if (prev_was_selected && next_is_selected) {
6582 hide_track_in_display (*t);
6587 prev_was_selected = is_selected;
6588 is_selected = next_is_selected;
6592 set the controls_layout height now, because waiting for its size
6593 request signal handler will cause the vertical adjustment setting to fail
6596 controls_layout.property_height () = full_canvas_height - canvas_timebars_vsize;
6597 vertical_adjustment.set_value (first_y_pos);
6599 redo_visual_stack.push_back (current_visual_state (true));
6603 Editor::save_visual_state (uint32_t n)
6605 while (visual_states.size() <= n) {
6606 visual_states.push_back (0);
6609 if (visual_states[n] != 0) {
6610 delete visual_states[n];
6613 visual_states[n] = current_visual_state (true);
6618 Editor::goto_visual_state (uint32_t n)
6620 if (visual_states.size() <= n) {
6624 if (visual_states[n] == 0) {
6628 use_visual_state (*visual_states[n]);
6632 Editor::start_visual_state_op (uint32_t n)
6634 save_visual_state (n);
6636 PopUp* pup = new PopUp (WIN_POS_MOUSE, 1000, true);
6638 snprintf (buf, sizeof (buf), _("Saved view %u"), n+1);
6639 pup->set_text (buf);
6644 Editor::cancel_visual_state_op (uint32_t n)
6646 goto_visual_state (n);
6650 Editor::toggle_region_mute ()
6652 if (_ignore_region_action) {
6656 RegionSelection rs = get_regions_from_selection_and_entered ();
6662 if (rs.size() > 1) {
6663 begin_reversible_command (_("mute regions"));
6665 begin_reversible_command (_("mute region"));
6668 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
6670 (*i)->region()->playlist()->clear_changes ();
6671 (*i)->region()->set_muted (!(*i)->region()->muted ());
6672 _session->add_command (new StatefulDiffCommand ((*i)->region()->playlist()));
6676 commit_reversible_command ();
6680 Editor::combine_regions ()
6682 /* foreach track with selected regions, take all selected regions
6683 and join them into a new region containing the subregions (as a
6687 typedef set<RouteTimeAxisView*> RTVS;
6690 if (selection->regions.empty()) {
6694 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
6695 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(&(*i)->get_time_axis_view());
6698 tracks.insert (rtv);
6702 begin_reversible_command (_("combine regions"));
6704 vector<RegionView*> new_selection;
6706 for (RTVS::iterator i = tracks.begin(); i != tracks.end(); ++i) {
6709 if ((rv = (*i)->combine_regions ()) != 0) {
6710 new_selection.push_back (rv);
6714 selection->clear_regions ();
6715 for (vector<RegionView*>::iterator i = new_selection.begin(); i != new_selection.end(); ++i) {
6716 selection->add (*i);
6719 commit_reversible_command ();
6723 Editor::uncombine_regions ()
6725 typedef set<RouteTimeAxisView*> RTVS;
6728 if (selection->regions.empty()) {
6732 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
6733 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(&(*i)->get_time_axis_view());
6736 tracks.insert (rtv);
6740 begin_reversible_command (_("uncombine regions"));
6742 for (RTVS::iterator i = tracks.begin(); i != tracks.end(); ++i) {
6743 (*i)->uncombine_regions ();
6746 commit_reversible_command ();