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 "control_point.h"
67 #include "streamview.h"
68 #include "audio_streamview.h"
69 #include "audio_region_view.h"
70 #include "midi_region_view.h"
71 #include "rgb_macros.h"
72 #include "selection_templates.h"
73 #include "selection.h"
75 #include "gtk-custom-hruler.h"
76 #include "gui_thread.h"
79 #include "editor_drag.h"
80 #include "strip_silence_dialog.h"
81 #include "editor_routes.h"
82 #include "editor_regions.h"
83 #include "quantize_dialog.h"
84 #include "interthread_progress_window.h"
85 #include "insert_time_dialog.h"
86 #include "normalize_dialog.h"
87 #include "editor_cursors.h"
88 #include "mouse_cursors.h"
89 #include "patch_change_dialog.h"
90 #include "transpose_dialog.h"
95 using namespace ARDOUR;
98 using namespace Gtkmm2ext;
99 using namespace Editing;
100 using Gtkmm2ext::Keyboard;
102 /***********************************************************************
104 ***********************************************************************/
107 Editor::undo (uint32_t n)
109 if (_drags->active ()) {
119 Editor::redo (uint32_t n)
121 if (_drags->active ()) {
131 Editor::split_regions_at (framepos_t where, RegionSelection& regions)
135 list <boost::shared_ptr<Playlist > > used_playlists;
137 if (regions.empty()) {
141 begin_reversible_command (_("split"));
143 // if splitting a single region, and snap-to is using
144 // region boundaries, don't pay attention to them
146 if (regions.size() == 1) {
147 switch (_snap_type) {
148 case SnapToRegionStart:
149 case SnapToRegionSync:
150 case SnapToRegionEnd:
159 EditorFreeze(); /* Emit Signal */
162 for (RegionSelection::iterator a = regions.begin(); a != regions.end(); ) {
164 RegionSelection::iterator tmp;
166 /* XXX this test needs to be more complicated, to make sure we really
167 have something to split.
170 if (!(*a)->region()->covers (where)) {
178 boost::shared_ptr<Playlist> pl = (*a)->region()->playlist();
186 /* we haven't seen this playlist before */
188 /* remember used playlists so we can thaw them later */
189 used_playlists.push_back(pl);
194 pl->clear_changes ();
195 pl->split_region ((*a)->region(), where);
196 _session->add_command (new StatefulDiffCommand (pl));
202 while (used_playlists.size() > 0) {
203 list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
205 used_playlists.pop_front();
208 commit_reversible_command ();
211 EditorThaw(); /* Emit Signal */
215 /** Move one extreme of the current range selection. If more than one range is selected,
216 * the start of the earliest range or the end of the latest range is moved.
218 * @param move_end true to move the end of the current range selection, false to move
220 * @param next true to move the extreme to the next region boundary, false to move to
224 Editor::move_range_selection_start_or_end_to_region_boundary (bool move_end, bool next)
226 if (selection->time.start() == selection->time.end_frame()) {
230 framepos_t start = selection->time.start ();
231 framepos_t end = selection->time.end_frame ();
233 /* the position of the thing we may move */
234 framepos_t pos = move_end ? end : start;
235 int dir = next ? 1 : -1;
237 /* so we don't find the current region again */
238 if (dir > 0 || pos > 0) {
242 framepos_t const target = get_region_boundary (pos, dir, true, false);
257 begin_reversible_command (_("alter selection"));
258 selection->set_preserving_all_ranges (start, end);
259 commit_reversible_command ();
263 Editor::nudge_forward_release (GdkEventButton* ev)
265 if (ev->state & Keyboard::PrimaryModifier) {
266 nudge_forward (false, true);
268 nudge_forward (false, false);
274 Editor::nudge_backward_release (GdkEventButton* ev)
276 if (ev->state & Keyboard::PrimaryModifier) {
277 nudge_backward (false, true);
279 nudge_backward (false, false);
286 Editor::nudge_forward (bool next, bool force_playhead)
289 framepos_t next_distance;
295 RegionSelection rs = get_regions_from_selection_and_entered ();
297 if (!force_playhead && !rs.empty()) {
299 begin_reversible_command (_("nudge regions forward"));
301 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
302 boost::shared_ptr<Region> r ((*i)->region());
304 distance = get_nudge_distance (r->position(), next_distance);
307 distance = next_distance;
311 r->set_position (r->position() + distance);
312 _session->add_command (new StatefulDiffCommand (r));
315 commit_reversible_command ();
318 } else if (!force_playhead && !selection->markers.empty()) {
322 begin_reversible_command (_("nudge location forward"));
324 for (MarkerSelection::iterator i = selection->markers.begin(); i != selection->markers.end(); ++i) {
326 Location* loc = find_location_from_marker ((*i), is_start);
330 XMLNode& before (loc->get_state());
333 distance = get_nudge_distance (loc->start(), next_distance);
335 distance = next_distance;
337 if (max_framepos - distance > loc->start() + loc->length()) {
338 loc->set_start (loc->start() + distance);
340 loc->set_start (max_framepos - loc->length());
343 distance = get_nudge_distance (loc->end(), next_distance);
345 distance = next_distance;
347 if (max_framepos - distance > loc->end()) {
348 loc->set_end (loc->end() + distance);
350 loc->set_end (max_framepos);
353 XMLNode& after (loc->get_state());
354 _session->add_command (new MementoCommand<Location>(*loc, &before, &after));
358 commit_reversible_command ();
361 distance = get_nudge_distance (playhead_cursor->current_frame, next_distance);
362 _session->request_locate (playhead_cursor->current_frame + distance);
367 Editor::nudge_backward (bool next, bool force_playhead)
370 framepos_t next_distance;
376 RegionSelection rs = get_regions_from_selection_and_entered ();
378 if (!force_playhead && !rs.empty()) {
380 begin_reversible_command (_("nudge regions backward"));
382 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
383 boost::shared_ptr<Region> r ((*i)->region());
385 distance = get_nudge_distance (r->position(), next_distance);
388 distance = next_distance;
393 if (r->position() > distance) {
394 r->set_position (r->position() - distance);
398 _session->add_command (new StatefulDiffCommand (r));
401 commit_reversible_command ();
403 } else if (!force_playhead && !selection->markers.empty()) {
407 begin_reversible_command (_("nudge location forward"));
409 for (MarkerSelection::iterator i = selection->markers.begin(); i != selection->markers.end(); ++i) {
411 Location* loc = find_location_from_marker ((*i), is_start);
415 XMLNode& before (loc->get_state());
418 distance = get_nudge_distance (loc->start(), next_distance);
420 distance = next_distance;
422 if (distance < loc->start()) {
423 loc->set_start (loc->start() - distance);
428 distance = get_nudge_distance (loc->end(), next_distance);
431 distance = next_distance;
434 if (distance < loc->end() - loc->length()) {
435 loc->set_end (loc->end() - distance);
437 loc->set_end (loc->length());
441 XMLNode& after (loc->get_state());
442 _session->add_command (new MementoCommand<Location>(*loc, &before, &after));
446 commit_reversible_command ();
450 distance = get_nudge_distance (playhead_cursor->current_frame, next_distance);
452 if (playhead_cursor->current_frame > distance) {
453 _session->request_locate (playhead_cursor->current_frame - distance);
455 _session->goto_start();
461 Editor::nudge_forward_capture_offset ()
463 RegionSelection rs = get_regions_from_selection_and_entered ();
465 if (!_session || rs.empty()) {
469 begin_reversible_command (_("nudge forward"));
471 framepos_t const distance = _session->worst_output_latency();
473 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
474 boost::shared_ptr<Region> r ((*i)->region());
477 r->set_position (r->position() + distance);
478 _session->add_command(new StatefulDiffCommand (r));
481 commit_reversible_command ();
485 Editor::nudge_backward_capture_offset ()
487 RegionSelection rs = get_regions_from_selection_and_entered ();
489 if (!_session || rs.empty()) {
493 begin_reversible_command (_("nudge backward"));
495 framepos_t const distance = _session->worst_output_latency();
497 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
498 boost::shared_ptr<Region> r ((*i)->region());
502 if (r->position() > distance) {
503 r->set_position (r->position() - distance);
507 _session->add_command(new StatefulDiffCommand (r));
510 commit_reversible_command ();
516 Editor::move_to_start ()
518 _session->goto_start ();
522 Editor::move_to_end ()
525 _session->request_locate (_session->current_end_frame());
529 Editor::build_region_boundary_cache ()
532 vector<RegionPoint> interesting_points;
533 boost::shared_ptr<Region> r;
534 TrackViewList tracks;
537 region_boundary_cache.clear ();
543 switch (_snap_type) {
544 case SnapToRegionStart:
545 interesting_points.push_back (Start);
547 case SnapToRegionEnd:
548 interesting_points.push_back (End);
550 case SnapToRegionSync:
551 interesting_points.push_back (SyncPoint);
553 case SnapToRegionBoundary:
554 interesting_points.push_back (Start);
555 interesting_points.push_back (End);
558 fatal << string_compose (_("build_region_boundary_cache called with snap_type = %1"), _snap_type) << endmsg;
563 TimeAxisView *ontrack = 0;
566 if (!selection->tracks.empty()) {
567 tlist = selection->tracks.filter_to_unique_playlists ();
569 tlist = track_views.filter_to_unique_playlists ();
572 while (pos < _session->current_end_frame() && !at_end) {
575 framepos_t lpos = max_framepos;
577 for (vector<RegionPoint>::iterator p = interesting_points.begin(); p != interesting_points.end(); ++p) {
579 if ((r = find_next_region (pos, *p, 1, tlist, &ontrack)) == 0) {
580 if (*p == interesting_points.back()) {
583 /* move to next point type */
589 rpos = r->first_frame();
593 rpos = r->last_frame();
597 rpos = r->sync_position ();
605 RouteTimeAxisView *rtav;
607 if (ontrack != 0 && (rtav = dynamic_cast<RouteTimeAxisView*>(ontrack)) != 0 ) {
608 if (rtav->track() != 0) {
609 speed = rtav->track()->speed();
613 rpos = track_frame_to_session_frame (rpos, speed);
619 /* prevent duplicates, but we don't use set<> because we want to be able
623 vector<framepos_t>::iterator ri;
625 for (ri = region_boundary_cache.begin(); ri != region_boundary_cache.end(); ++ri) {
631 if (ri == region_boundary_cache.end()) {
632 region_boundary_cache.push_back (rpos);
639 /* finally sort to be sure that the order is correct */
641 sort (region_boundary_cache.begin(), region_boundary_cache.end());
644 boost::shared_ptr<Region>
645 Editor::find_next_region (framepos_t frame, RegionPoint point, int32_t dir, TrackViewList& tracks, TimeAxisView **ontrack)
647 TrackViewList::iterator i;
648 framepos_t closest = max_framepos;
649 boost::shared_ptr<Region> ret;
653 framepos_t track_frame;
654 RouteTimeAxisView *rtav;
656 for (i = tracks.begin(); i != tracks.end(); ++i) {
659 boost::shared_ptr<Region> r;
662 if ( (rtav = dynamic_cast<RouteTimeAxisView*>(*i)) != 0 ) {
663 if (rtav->track()!=0)
664 track_speed = rtav->track()->speed();
667 track_frame = session_frame_to_track_frame(frame, track_speed);
669 if ((r = (*i)->find_next_region (track_frame, point, dir)) == 0) {
675 rpos = r->first_frame ();
679 rpos = r->last_frame ();
683 rpos = r->sync_position ();
687 // rpos is a "track frame", converting it to "_session frame"
688 rpos = track_frame_to_session_frame(rpos, track_speed);
691 distance = rpos - frame;
693 distance = frame - rpos;
696 if (distance < closest) {
708 Editor::find_next_region_boundary (framepos_t pos, int32_t dir, const TrackViewList& tracks)
710 framecnt_t distance = max_framepos;
711 framepos_t current_nearest = -1;
713 for (TrackViewList::const_iterator i = tracks.begin(); i != tracks.end(); ++i) {
714 framepos_t contender;
717 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*i);
723 if ((contender = rtv->find_next_region_boundary (pos, dir)) < 0) {
727 d = ::llabs (pos - contender);
730 current_nearest = contender;
735 return current_nearest;
739 Editor::get_region_boundary (framepos_t pos, int32_t dir, bool with_selection, bool only_onscreen)
744 if (with_selection && Config->get_region_boundaries_from_selected_tracks()) {
746 if (!selection->tracks.empty()) {
748 target = find_next_region_boundary (pos, dir, selection->tracks);
752 if (only_onscreen || Config->get_region_boundaries_from_onscreen_tracks()) {
753 get_onscreen_tracks (tvl);
754 target = find_next_region_boundary (pos, dir, tvl);
756 target = find_next_region_boundary (pos, dir, track_views);
762 if (only_onscreen || Config->get_region_boundaries_from_onscreen_tracks()) {
763 get_onscreen_tracks (tvl);
764 target = find_next_region_boundary (pos, dir, tvl);
766 target = find_next_region_boundary (pos, dir, track_views);
774 Editor::cursor_to_region_boundary (bool with_selection, int32_t dir)
776 framepos_t pos = playhead_cursor->current_frame;
783 // so we don't find the current region again..
784 if (dir > 0 || pos > 0) {
788 if ((target = get_region_boundary (pos, dir, with_selection, false)) < 0) {
792 _session->request_locate (target);
796 Editor::cursor_to_next_region_boundary (bool with_selection)
798 cursor_to_region_boundary (with_selection, 1);
802 Editor::cursor_to_previous_region_boundary (bool with_selection)
804 cursor_to_region_boundary (with_selection, -1);
808 Editor::cursor_to_region_point (EditorCursor* cursor, RegionPoint point, int32_t dir)
810 boost::shared_ptr<Region> r;
811 framepos_t pos = cursor->current_frame;
817 TimeAxisView *ontrack = 0;
819 // so we don't find the current region again..
823 if (!selection->tracks.empty()) {
825 r = find_next_region (pos, point, dir, selection->tracks, &ontrack);
827 } else if (clicked_axisview) {
830 t.push_back (clicked_axisview);
832 r = find_next_region (pos, point, dir, t, &ontrack);
836 r = find_next_region (pos, point, dir, track_views, &ontrack);
845 pos = r->first_frame ();
849 pos = r->last_frame ();
853 pos = r->sync_position ();
858 RouteTimeAxisView *rtav;
860 if ( ontrack != 0 && (rtav = dynamic_cast<RouteTimeAxisView*>(ontrack)) != 0 ) {
861 if (rtav->track() != 0) {
862 speed = rtav->track()->speed();
866 pos = track_frame_to_session_frame(pos, speed);
868 if (cursor == playhead_cursor) {
869 _session->request_locate (pos);
871 cursor->set_position (pos);
876 Editor::cursor_to_next_region_point (EditorCursor* cursor, RegionPoint point)
878 cursor_to_region_point (cursor, point, 1);
882 Editor::cursor_to_previous_region_point (EditorCursor* cursor, RegionPoint point)
884 cursor_to_region_point (cursor, point, -1);
888 Editor::cursor_to_selection_start (EditorCursor *cursor)
892 switch (mouse_mode) {
894 if (!selection->regions.empty()) {
895 pos = selection->regions.start();
900 if (!selection->time.empty()) {
901 pos = selection->time.start ();
909 if (cursor == playhead_cursor) {
910 _session->request_locate (pos);
912 cursor->set_position (pos);
917 Editor::cursor_to_selection_end (EditorCursor *cursor)
921 switch (mouse_mode) {
923 if (!selection->regions.empty()) {
924 pos = selection->regions.end_frame();
929 if (!selection->time.empty()) {
930 pos = selection->time.end_frame ();
938 if (cursor == playhead_cursor) {
939 _session->request_locate (pos);
941 cursor->set_position (pos);
946 Editor::selected_marker_to_region_boundary (bool with_selection, int32_t dir)
956 if (selection->markers.empty()) {
960 if (!mouse_frame (mouse, ignored)) {
964 add_location_mark (mouse);
967 if ((loc = find_location_from_marker (selection->markers.front(), ignored)) == 0) {
971 framepos_t pos = loc->start();
973 // so we don't find the current region again..
974 if (dir > 0 || pos > 0) {
978 if ((target = get_region_boundary (pos, dir, with_selection, false)) < 0) {
982 loc->move_to (target);
986 Editor::selected_marker_to_next_region_boundary (bool with_selection)
988 selected_marker_to_region_boundary (with_selection, 1);
992 Editor::selected_marker_to_previous_region_boundary (bool with_selection)
994 selected_marker_to_region_boundary (with_selection, -1);
998 Editor::selected_marker_to_region_point (RegionPoint point, int32_t dir)
1000 boost::shared_ptr<Region> r;
1005 if (!_session || selection->markers.empty()) {
1009 if ((loc = find_location_from_marker (selection->markers.front(), ignored)) == 0) {
1013 TimeAxisView *ontrack = 0;
1017 // so we don't find the current region again..
1021 if (!selection->tracks.empty()) {
1023 r = find_next_region (pos, point, dir, selection->tracks, &ontrack);
1027 r = find_next_region (pos, point, dir, track_views, &ontrack);
1036 pos = r->first_frame ();
1040 pos = r->last_frame ();
1044 pos = r->adjust_to_sync (r->first_frame());
1049 RouteTimeAxisView *rtav;
1051 if (ontrack != 0 && (rtav = dynamic_cast<RouteTimeAxisView*>(ontrack)) != 0) {
1052 if (rtav->track() != 0) {
1053 speed = rtav->track()->speed();
1057 pos = track_frame_to_session_frame(pos, speed);
1063 Editor::selected_marker_to_next_region_point (RegionPoint point)
1065 selected_marker_to_region_point (point, 1);
1069 Editor::selected_marker_to_previous_region_point (RegionPoint point)
1071 selected_marker_to_region_point (point, -1);
1075 Editor::selected_marker_to_selection_start ()
1081 if (!_session || selection->markers.empty()) {
1085 if ((loc = find_location_from_marker (selection->markers.front(), ignored)) == 0) {
1089 switch (mouse_mode) {
1091 if (!selection->regions.empty()) {
1092 pos = selection->regions.start();
1097 if (!selection->time.empty()) {
1098 pos = selection->time.start ();
1110 Editor::selected_marker_to_selection_end ()
1116 if (!_session || selection->markers.empty()) {
1120 if ((loc = find_location_from_marker (selection->markers.front(), ignored)) == 0) {
1124 switch (mouse_mode) {
1126 if (!selection->regions.empty()) {
1127 pos = selection->regions.end_frame();
1132 if (!selection->time.empty()) {
1133 pos = selection->time.end_frame ();
1145 Editor::scroll_playhead (bool forward)
1147 framepos_t pos = playhead_cursor->current_frame;
1148 framecnt_t delta = (framecnt_t) floor (current_page_frames() / 0.8);
1151 if (pos == max_framepos) {
1155 if (pos < max_framepos - delta) {
1174 _session->request_locate (pos);
1178 Editor::cursor_align (bool playhead_to_edit)
1184 if (playhead_to_edit) {
1186 if (selection->markers.empty()) {
1190 _session->request_locate (selection->markers.front()->position(), _session->transport_rolling());
1193 /* move selected markers to playhead */
1195 for (MarkerSelection::iterator i = selection->markers.begin(); i != selection->markers.end(); ++i) {
1198 Location* loc = find_location_from_marker (*i, ignored);
1200 if (loc->is_mark()) {
1201 loc->set_start (playhead_cursor->current_frame);
1203 loc->set (playhead_cursor->current_frame,
1204 playhead_cursor->current_frame + loc->length());
1211 Editor::scroll_backward (float pages)
1213 framepos_t const one_page = (framepos_t) rint (_canvas_width * frames_per_unit);
1214 framepos_t const cnt = (framepos_t) floor (pages * one_page);
1217 if (leftmost_frame < cnt) {
1220 frame = leftmost_frame - cnt;
1223 reset_x_origin (frame);
1227 Editor::scroll_forward (float pages)
1229 framepos_t const one_page = (framepos_t) rint (_canvas_width * frames_per_unit);
1230 framepos_t const cnt = (framepos_t) floor (pages * one_page);
1233 if (max_framepos - cnt < leftmost_frame) {
1234 frame = max_framepos - cnt;
1236 frame = leftmost_frame + cnt;
1239 reset_x_origin (frame);
1243 Editor::scroll_tracks_down ()
1245 double vert_value = vertical_adjustment.get_value() + vertical_adjustment.get_page_size();
1246 if (vert_value > vertical_adjustment.get_upper() - _canvas_height) {
1247 vert_value = vertical_adjustment.get_upper() - _canvas_height;
1250 vertical_adjustment.set_value (vert_value);
1254 Editor::scroll_tracks_up ()
1256 vertical_adjustment.set_value (vertical_adjustment.get_value() - vertical_adjustment.get_page_size());
1260 Editor::scroll_tracks_down_line ()
1262 double vert_value = vertical_adjustment.get_value() + 60;
1264 if (vert_value > vertical_adjustment.get_upper() - _canvas_height) {
1265 vert_value = vertical_adjustment.get_upper() - _canvas_height;
1268 vertical_adjustment.set_value (vert_value);
1272 Editor::scroll_tracks_up_line ()
1274 reset_y_origin (vertical_adjustment.get_value() - 60);
1280 Editor::tav_zoom_step (bool coarser)
1282 _routes->suspend_redisplay ();
1286 if (selection->tracks.empty()) {
1289 ts = &selection->tracks;
1292 for (TrackViewList::iterator i = ts->begin(); i != ts->end(); ++i) {
1293 TimeAxisView *tv = (static_cast<TimeAxisView*>(*i));
1294 tv->step_height (coarser);
1297 _routes->resume_redisplay ();
1301 Editor::tav_zoom_smooth (bool coarser, bool force_all)
1303 _routes->suspend_redisplay ();
1307 if (selection->tracks.empty() || force_all) {
1310 ts = &selection->tracks;
1313 for (TrackViewList::iterator i = ts->begin(); i != ts->end(); ++i) {
1314 TimeAxisView *tv = (static_cast<TimeAxisView*>(*i));
1315 uint32_t h = tv->current_height ();
1320 if (h >= TimeAxisView::preset_height (HeightSmall)) {
1325 tv->set_height (h + 5);
1329 _routes->resume_redisplay ();
1333 Editor::temporal_zoom_step (bool coarser)
1335 ENSURE_GUI_THREAD (*this, &Editor::temporal_zoom_step, coarser)
1339 nfpu = frames_per_unit;
1344 nfpu = max(1.0,(nfpu/1.61803399));
1347 temporal_zoom (nfpu);
1351 Editor::temporal_zoom (gdouble fpu)
1353 if (!_session) return;
1355 framepos_t current_page = current_page_frames();
1356 framepos_t current_leftmost = leftmost_frame;
1357 framepos_t current_rightmost;
1358 framepos_t current_center;
1359 framepos_t new_page_size;
1360 framepos_t half_page_size;
1361 framepos_t leftmost_after_zoom = 0;
1363 bool in_track_canvas;
1367 /* XXX this limit is also in ::set_frames_per_unit() */
1369 if (frames_per_unit <= 1.0 && fpu <= frames_per_unit) {
1375 new_page_size = (framepos_t) floor (_canvas_width * nfpu);
1376 half_page_size = new_page_size / 2;
1378 switch (zoom_focus) {
1380 leftmost_after_zoom = current_leftmost;
1383 case ZoomFocusRight:
1384 current_rightmost = leftmost_frame + current_page;
1385 if (current_rightmost < new_page_size) {
1386 leftmost_after_zoom = 0;
1388 leftmost_after_zoom = current_rightmost - new_page_size;
1392 case ZoomFocusCenter:
1393 current_center = current_leftmost + (current_page/2);
1394 if (current_center < half_page_size) {
1395 leftmost_after_zoom = 0;
1397 leftmost_after_zoom = current_center - half_page_size;
1401 case ZoomFocusPlayhead:
1402 /* centre playhead */
1403 l = playhead_cursor->current_frame - (new_page_size * 0.5);
1406 leftmost_after_zoom = 0;
1407 } else if (l > max_framepos) {
1408 leftmost_after_zoom = max_framepos - new_page_size;
1410 leftmost_after_zoom = (framepos_t) l;
1414 case ZoomFocusMouse:
1415 /* try to keep the mouse over the same point in the display */
1417 if (!mouse_frame (where, in_track_canvas)) {
1418 /* use playhead instead */
1419 where = playhead_cursor->current_frame;
1421 if (where < half_page_size) {
1422 leftmost_after_zoom = 0;
1424 leftmost_after_zoom = where - half_page_size;
1429 l = - ((new_page_size * ((where - current_leftmost)/(double)current_page)) - where);
1432 leftmost_after_zoom = 0;
1433 } else if (l > max_framepos) {
1434 leftmost_after_zoom = max_framepos - new_page_size;
1436 leftmost_after_zoom = (framepos_t) l;
1443 /* try to keep the edit point in the same place */
1444 where = get_preferred_edit_position ();
1448 double l = - ((new_page_size * ((where - current_leftmost)/(double)current_page)) - where);
1451 leftmost_after_zoom = 0;
1452 } else if (l > max_framepos) {
1453 leftmost_after_zoom = max_framepos - new_page_size;
1455 leftmost_after_zoom = (framepos_t) l;
1459 /* edit point not defined */
1466 // leftmost_after_zoom = min (leftmost_after_zoom, _session->current_end_frame());
1468 reposition_and_zoom (leftmost_after_zoom, nfpu);
1472 Editor::temporal_zoom_region (bool both_axes)
1474 framepos_t start = max_framepos;
1476 set<TimeAxisView*> tracks;
1478 RegionSelection rs = get_regions_from_selection_and_entered ();
1484 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
1486 if ((*i)->region()->position() < start) {
1487 start = (*i)->region()->position();
1490 if ((*i)->region()->last_frame() + 1 > end) {
1491 end = (*i)->region()->last_frame() + 1;
1494 tracks.insert (&((*i)->get_time_axis_view()));
1497 /* now comes an "interesting" hack ... make sure we leave a little space
1498 at each end of the editor so that the zoom doesn't fit the region
1499 precisely to the screen.
1502 GdkScreen* screen = gdk_screen_get_default ();
1503 gint pixwidth = gdk_screen_get_width (screen);
1504 gint mmwidth = gdk_screen_get_width_mm (screen);
1505 double pix_per_mm = (double) pixwidth/ (double) mmwidth;
1506 double one_centimeter_in_pixels = pix_per_mm * 10.0;
1508 if ((start == 0 && end == 0) || end < start) {
1512 framepos_t range = end - start;
1513 double new_fpu = (double)range / (double)_canvas_width;
1514 framepos_t extra_samples = (framepos_t) floor (one_centimeter_in_pixels * new_fpu);
1516 if (start > extra_samples) {
1517 start -= extra_samples;
1522 if (max_framepos - extra_samples > end) {
1523 end += extra_samples;
1528 /* if we're zooming on both axes we need to save track heights etc.
1531 undo_visual_stack.push_back (current_visual_state (both_axes));
1533 PBD::Unwinder<bool> nsv (no_save_visual, true);
1535 temporal_zoom_by_frame (start, end);
1538 uint32_t per_track_height = (uint32_t) floor ((_canvas_height - canvas_timebars_vsize - 10.0) / tracks.size());
1540 /* set visible track heights appropriately */
1542 for (set<TimeAxisView*>::iterator t = tracks.begin(); t != tracks.end(); ++t) {
1543 (*t)->set_height (per_track_height);
1546 /* hide irrelevant tracks */
1548 _routes->suspend_redisplay ();
1550 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1551 if (find (tracks.begin(), tracks.end(), (*i)) == tracks.end()) {
1552 hide_track_in_display (*i);
1556 _routes->resume_redisplay ();
1558 vertical_adjustment.set_value (0.0);
1561 redo_visual_stack.push_back (current_visual_state (both_axes));
1565 Editor::zoom_to_region (bool both_axes)
1567 temporal_zoom_region (both_axes);
1571 Editor::temporal_zoom_selection ()
1573 if (!selection) return;
1575 if (selection->time.empty()) {
1579 framepos_t start = selection->time[clicked_selection].start;
1580 framepos_t end = selection->time[clicked_selection].end;
1582 temporal_zoom_by_frame (start, end);
1586 Editor::temporal_zoom_session ()
1588 ENSURE_GUI_THREAD (*this, &Editor::temporal_zoom_session)
1591 framecnt_t const l = _session->current_end_frame() - _session->current_start_frame();
1592 double s = _session->current_start_frame() - l * 0.01;
1596 framecnt_t const e = _session->current_end_frame() + l * 0.01;
1597 temporal_zoom_by_frame (framecnt_t (s), e);
1602 Editor::temporal_zoom_by_frame (framepos_t start, framepos_t end)
1604 if (!_session) return;
1606 if ((start == 0 && end == 0) || end < start) {
1610 framepos_t range = end - start;
1612 double new_fpu = (double)range / (double)_canvas_width;
1614 framepos_t new_page = (framepos_t) floor (_canvas_width * new_fpu);
1615 framepos_t middle = (framepos_t) floor( (double)start + ((double)range / 2.0f ));
1616 framepos_t new_leftmost = (framepos_t) floor( (double)middle - ((double)new_page/2.0f));
1618 if (new_leftmost > middle) {
1622 if (new_leftmost < 0) {
1626 reposition_and_zoom (new_leftmost, new_fpu);
1630 Editor::temporal_zoom_to_frame (bool coarser, framepos_t frame)
1635 double range_before = frame - leftmost_frame;
1638 new_fpu = frames_per_unit;
1641 new_fpu *= 1.61803399;
1642 range_before *= 1.61803399;
1644 new_fpu = max(1.0,(new_fpu/1.61803399));
1645 range_before /= 1.61803399;
1648 if (new_fpu == frames_per_unit) {
1652 framepos_t new_leftmost = frame - (framepos_t)range_before;
1654 if (new_leftmost > frame) {
1658 if (new_leftmost < 0) {
1662 reposition_and_zoom (new_leftmost, new_fpu);
1667 Editor::choose_new_marker_name(string &name) {
1669 if (!Config->get_name_new_markers()) {
1670 /* don't prompt user for a new name */
1674 ArdourPrompter dialog (true);
1676 dialog.set_prompt (_("New Name:"));
1678 dialog.set_title (_("New Location Marker"));
1680 dialog.set_name ("MarkNameWindow");
1681 dialog.set_size_request (250, -1);
1682 dialog.set_position (Gtk::WIN_POS_MOUSE);
1684 dialog.add_button (Stock::OK, RESPONSE_ACCEPT);
1685 dialog.set_initial_text (name);
1689 switch (dialog.run ()) {
1690 case RESPONSE_ACCEPT:
1696 dialog.get_result(name);
1703 Editor::add_location_from_selection ()
1707 if (selection->time.empty()) {
1711 if (_session == 0 || clicked_axisview == 0) {
1715 framepos_t start = selection->time[clicked_selection].start;
1716 framepos_t end = selection->time[clicked_selection].end;
1718 _session->locations()->next_available_name(rangename,"selection");
1719 Location *location = new Location (*_session, start, end, rangename, Location::IsRangeMarker);
1721 _session->begin_reversible_command (_("add marker"));
1722 XMLNode &before = _session->locations()->get_state();
1723 _session->locations()->add (location, true);
1724 XMLNode &after = _session->locations()->get_state();
1725 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
1726 _session->commit_reversible_command ();
1730 Editor::add_location_mark (framepos_t where)
1734 select_new_marker = true;
1736 _session->locations()->next_available_name(markername,"mark");
1737 if (!choose_new_marker_name(markername)) {
1740 Location *location = new Location (*_session, where, where, markername, Location::IsMark);
1741 _session->begin_reversible_command (_("add marker"));
1742 XMLNode &before = _session->locations()->get_state();
1743 _session->locations()->add (location, true);
1744 XMLNode &after = _session->locations()->get_state();
1745 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
1746 _session->commit_reversible_command ();
1750 Editor::add_location_from_playhead_cursor ()
1752 add_location_mark (_session->audible_frame());
1755 /** Add a range marker around each selected region */
1757 Editor::add_locations_from_region ()
1759 RegionSelection rs = get_regions_from_selection_and_entered ();
1765 _session->begin_reversible_command (selection->regions.size () > 1 ? _("add markers") : _("add marker"));
1766 XMLNode &before = _session->locations()->get_state();
1768 for (RegionSelection::iterator i = rs.begin (); i != rs.end (); ++i) {
1770 boost::shared_ptr<Region> region = (*i)->region ();
1772 Location *location = new Location (*_session, region->position(), region->last_frame(), region->name(), Location::IsRangeMarker);
1774 _session->locations()->add (location, true);
1777 XMLNode &after = _session->locations()->get_state();
1778 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
1779 _session->commit_reversible_command ();
1782 /** Add a single range marker around all selected regions */
1784 Editor::add_location_from_region ()
1786 RegionSelection rs = get_regions_from_selection_and_entered ();
1792 _session->begin_reversible_command (_("add marker"));
1793 XMLNode &before = _session->locations()->get_state();
1797 if (rs.size() > 1) {
1798 _session->locations()->next_available_name(markername, "regions");
1800 RegionView* rv = *(rs.begin());
1801 boost::shared_ptr<Region> region = rv->region();
1802 markername = region->name();
1805 if (!choose_new_marker_name(markername)) {
1809 // single range spanning all selected
1810 Location *location = new Location (*_session, selection->regions.start(), selection->regions.end_frame(), markername, Location::IsRangeMarker);
1811 _session->locations()->add (location, true);
1813 XMLNode &after = _session->locations()->get_state();
1814 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
1815 _session->commit_reversible_command ();
1821 Editor::jump_forward_to_mark ()
1827 Location *location = _session->locations()->first_location_after (playhead_cursor->current_frame);
1830 _session->request_locate (location->start(), _session->transport_rolling());
1832 _session->request_locate (_session->current_end_frame());
1837 Editor::jump_backward_to_mark ()
1843 Location *location = _session->locations()->first_location_before (playhead_cursor->current_frame);
1846 _session->request_locate (location->start(), _session->transport_rolling());
1848 _session->goto_start ();
1855 framepos_t const pos = _session->audible_frame ();
1858 _session->locations()->next_available_name (markername, "mark");
1860 if (!choose_new_marker_name (markername)) {
1864 _session->locations()->add (new Location (*_session, pos, 0, markername, Location::IsMark), true);
1868 Editor::clear_markers ()
1871 _session->begin_reversible_command (_("clear markers"));
1872 XMLNode &before = _session->locations()->get_state();
1873 _session->locations()->clear_markers ();
1874 XMLNode &after = _session->locations()->get_state();
1875 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
1876 _session->commit_reversible_command ();
1881 Editor::clear_ranges ()
1884 _session->begin_reversible_command (_("clear ranges"));
1885 XMLNode &before = _session->locations()->get_state();
1887 Location * looploc = _session->locations()->auto_loop_location();
1888 Location * punchloc = _session->locations()->auto_punch_location();
1889 Location * sessionloc = _session->locations()->session_range_location();
1891 _session->locations()->clear_ranges ();
1893 if (looploc) _session->locations()->add (looploc);
1894 if (punchloc) _session->locations()->add (punchloc);
1895 if (sessionloc) _session->locations()->add (sessionloc);
1897 XMLNode &after = _session->locations()->get_state();
1898 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
1899 _session->commit_reversible_command ();
1904 Editor::clear_locations ()
1906 _session->begin_reversible_command (_("clear locations"));
1907 XMLNode &before = _session->locations()->get_state();
1908 _session->locations()->clear ();
1909 XMLNode &after = _session->locations()->get_state();
1910 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
1911 _session->commit_reversible_command ();
1912 _session->locations()->clear ();
1916 Editor::unhide_markers ()
1918 for (LocationMarkerMap::iterator i = location_markers.begin(); i != location_markers.end(); ++i) {
1919 Location *l = (*i).first;
1920 if (l->is_hidden() && l->is_mark()) {
1921 l->set_hidden(false, this);
1927 Editor::unhide_ranges ()
1929 for (LocationMarkerMap::iterator i = location_markers.begin(); i != location_markers.end(); ++i) {
1930 Location *l = (*i).first;
1931 if (l->is_hidden() && l->is_range_marker()) {
1932 l->set_hidden(false, this);
1937 /* INSERT/REPLACE */
1940 Editor::insert_region_list_drag (boost::shared_ptr<Region> region, int x, int y)
1945 RouteTimeAxisView *rtv = 0;
1946 boost::shared_ptr<Playlist> playlist;
1948 track_canvas->window_to_world (x, y, wx, wy);
1951 event.type = GDK_BUTTON_RELEASE;
1952 event.button.x = wx;
1953 event.button.y = wy;
1955 where = event_frame (&event, &cx, &cy);
1957 if (where < leftmost_frame || where > leftmost_frame + current_page_frames()) {
1958 /* clearly outside canvas area */
1962 std::pair<TimeAxisView*, int> tv = trackview_by_y_position (cy);
1963 if (tv.first == 0) {
1967 if ((rtv = dynamic_cast<RouteTimeAxisView*> (tv.first)) == 0) {
1971 if ((playlist = rtv->playlist()) == 0) {
1977 begin_reversible_command (_("insert dragged region"));
1978 playlist->clear_changes ();
1979 playlist->add_region (RegionFactory::create (region, true), where, 1.0);
1980 _session->add_command(new StatefulDiffCommand (playlist));
1981 commit_reversible_command ();
1985 Editor::insert_route_list_drag (boost::shared_ptr<Route> route, int x, int y)
1989 RouteTimeAxisView *dest_rtv = 0;
1990 RouteTimeAxisView *source_rtv = 0;
1992 track_canvas->window_to_world (x, y, wx, wy);
1993 wx += horizontal_position ();
1994 wy += vertical_adjustment.get_value();
1997 event.type = GDK_BUTTON_RELEASE;
1998 event.button.x = wx;
1999 event.button.y = wy;
2001 event_frame (&event, &cx, &cy);
2003 std::pair<TimeAxisView*, int> const tv = trackview_by_y_position (cy);
2004 if (tv.first == 0) {
2008 if ((dest_rtv = dynamic_cast<RouteTimeAxisView*> (tv.first)) == 0) {
2012 /* use this drag source to add underlay to a track. But we really don't care
2013 about the Route, only the view of the route, so find it first */
2014 for(TrackViewList::iterator it = track_views.begin(); it != track_views.end(); ++it) {
2015 if((source_rtv = dynamic_cast<RouteTimeAxisView*>(*it)) == 0) {
2019 if(source_rtv->route() == route && source_rtv != dest_rtv) {
2020 dest_rtv->add_underlay(source_rtv->view());
2027 Editor::insert_region_list_selection (float times)
2029 RouteTimeAxisView *tv = 0;
2030 boost::shared_ptr<Playlist> playlist;
2032 if (clicked_routeview != 0) {
2033 tv = clicked_routeview;
2034 } else if (!selection->tracks.empty()) {
2035 if ((tv = dynamic_cast<RouteTimeAxisView*>(selection->tracks.front())) == 0) {
2038 } else if (entered_track != 0) {
2039 if ((tv = dynamic_cast<RouteTimeAxisView*>(entered_track)) == 0) {
2046 if ((playlist = tv->playlist()) == 0) {
2050 boost::shared_ptr<Region> region = _regions->get_single_selection ();
2055 begin_reversible_command (_("insert region"));
2056 playlist->clear_changes ();
2057 playlist->add_region ((RegionFactory::create (region, true)), get_preferred_edit_position(), times);
2058 _session->add_command(new StatefulDiffCommand (playlist));
2059 commit_reversible_command ();
2062 /* BUILT-IN EFFECTS */
2065 Editor::reverse_selection ()
2070 /* GAIN ENVELOPE EDITING */
2073 Editor::edit_envelope ()
2080 Editor::transition_to_rolling (bool fwd)
2086 if (_session->config.get_external_sync()) {
2087 switch (_session->config.get_sync_source()) {
2091 /* transport controlled by the master */
2096 if (_session->is_auditioning()) {
2097 _session->cancel_audition ();
2101 _session->request_transport_speed (fwd ? 1.0f : -1.0f);
2105 Editor::play_from_start ()
2107 _session->request_locate (_session->current_start_frame(), true);
2111 Editor::play_from_edit_point ()
2113 _session->request_locate (get_preferred_edit_position(), true);
2117 Editor::play_from_edit_point_and_return ()
2119 framepos_t start_frame;
2120 framepos_t return_frame;
2122 start_frame = get_preferred_edit_position (true);
2124 if (_session->transport_rolling()) {
2125 _session->request_locate (start_frame, false);
2129 /* don't reset the return frame if its already set */
2131 if ((return_frame = _session->requested_return_frame()) < 0) {
2132 return_frame = _session->audible_frame();
2135 if (start_frame >= 0) {
2136 _session->request_roll_at_and_return (start_frame, return_frame);
2141 Editor::play_selection ()
2143 if (selection->time.empty()) {
2147 _session->request_play_range (&selection->time, true);
2151 Editor::play_location (Location& location)
2153 if (location.start() <= location.end()) {
2157 _session->request_bounded_roll (location.start(), location.end());
2161 Editor::loop_location (Location& location)
2163 if (location.start() <= location.end()) {
2169 if ((tll = transport_loop_location()) != 0) {
2170 tll->set (location.start(), location.end());
2172 // enable looping, reposition and start rolling
2173 _session->request_play_loop (true);
2174 _session->request_locate (tll->start(), true);
2179 Editor::do_layer_operation (LayerOperation op)
2181 if (selection->regions.empty ()) {
2185 bool const multiple = selection->regions.size() > 1;
2189 begin_reversible_command (_("raise regions"));
2191 begin_reversible_command (_("raise region"));
2197 begin_reversible_command (_("raise regions to top"));
2199 begin_reversible_command (_("raise region to top"));
2205 begin_reversible_command (_("lower regions"));
2207 begin_reversible_command (_("lower region"));
2213 begin_reversible_command (_("lower regions to bottom"));
2215 begin_reversible_command (_("lower region"));
2220 set<boost::shared_ptr<Playlist> > playlists = selection->regions.playlists ();
2221 for (set<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
2222 (*i)->clear_owned_changes ();
2225 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
2226 boost::shared_ptr<Region> r = (*i)->region ();
2238 r->lower_to_bottom ();
2242 for (set<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
2243 vector<Command*> cmds;
2245 _session->add_commands (cmds);
2248 commit_reversible_command ();
2252 Editor::raise_region ()
2254 do_layer_operation (Raise);
2258 Editor::raise_region_to_top ()
2260 do_layer_operation (RaiseToTop);
2264 Editor::lower_region ()
2266 do_layer_operation (Lower);
2270 Editor::lower_region_to_bottom ()
2272 do_layer_operation (LowerToBottom);
2275 /** Show the region editor for the selected regions */
2277 Editor::show_region_properties ()
2279 selection->foreach_regionview (&RegionView::show_region_editor);
2282 /** Show the midi list editor for the selected MIDI regions */
2284 Editor::show_midi_list_editor ()
2286 selection->foreach_midi_regionview (&MidiRegionView::show_list_editor);
2290 Editor::rename_region ()
2292 RegionSelection rs = get_regions_from_selection_and_entered ();
2298 ArdourDialog d (*this, _("Rename Region"), true, false);
2300 Label label (_("New name:"));
2303 hbox.set_spacing (6);
2304 hbox.pack_start (label, false, false);
2305 hbox.pack_start (entry, true, true);
2307 d.get_vbox()->set_border_width (12);
2308 d.get_vbox()->pack_start (hbox, false, false);
2310 d.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
2311 d.add_button(Gtk::Stock::OK, Gtk::RESPONSE_OK);
2313 d.set_size_request (300, -1);
2314 d.set_position (Gtk::WIN_POS_MOUSE);
2316 entry.set_text (rs.front()->region()->name());
2317 entry.select_region (0, -1);
2319 entry.signal_activate().connect (sigc::bind (sigc::mem_fun (d, &Dialog::response), RESPONSE_OK));
2325 int const ret = d.run();
2329 if (ret != RESPONSE_OK) {
2333 std::string str = entry.get_text();
2334 strip_whitespace_edges (str);
2336 rs.front()->region()->set_name (str);
2337 _regions->redisplay ();
2342 Editor::audition_playlist_region_via_route (boost::shared_ptr<Region> region, Route& route)
2344 if (_session->is_auditioning()) {
2345 _session->cancel_audition ();
2348 // note: some potential for creativity here, because region doesn't
2349 // have to belong to the playlist that Route is handling
2351 // bool was_soloed = route.soloed();
2353 route.set_solo (true, this);
2355 _session->request_bounded_roll (region->position(), region->position() + region->length());
2357 /* XXX how to unset the solo state ? */
2360 /** Start an audition of the first selected region */
2362 Editor::play_edit_range ()
2364 framepos_t start, end;
2366 if (get_edit_op_range (start, end)) {
2367 _session->request_bounded_roll (start, end);
2372 Editor::play_selected_region ()
2374 framepos_t start = max_framepos;
2377 RegionSelection rs = get_regions_from_selection_and_entered ();
2383 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
2384 if ((*i)->region()->position() < start) {
2385 start = (*i)->region()->position();
2387 if ((*i)->region()->last_frame() + 1 > end) {
2388 end = (*i)->region()->last_frame() + 1;
2392 _session->request_bounded_roll (start, end);
2396 Editor::audition_playlist_region_standalone (boost::shared_ptr<Region> region)
2398 _session->audition_region (region);
2402 Editor::region_from_selection ()
2404 if (clicked_axisview == 0) {
2408 if (selection->time.empty()) {
2412 framepos_t start = selection->time[clicked_selection].start;
2413 framepos_t end = selection->time[clicked_selection].end;
2415 TrackViewList tracks = get_tracks_for_range_action ();
2417 framepos_t selection_cnt = end - start + 1;
2419 for (TrackSelection::iterator i = tracks.begin(); i != tracks.end(); ++i) {
2420 boost::shared_ptr<Region> current;
2421 boost::shared_ptr<Playlist> pl;
2422 framepos_t internal_start;
2425 if ((pl = (*i)->playlist()) == 0) {
2429 if ((current = pl->top_region_at (start)) == 0) {
2433 internal_start = start - current->position();
2434 RegionFactory::region_name (new_name, current->name(), true);
2438 plist.add (ARDOUR::Properties::start, current->start() + internal_start);
2439 plist.add (ARDOUR::Properties::length, selection_cnt);
2440 plist.add (ARDOUR::Properties::name, new_name);
2441 plist.add (ARDOUR::Properties::layer, 0);
2443 boost::shared_ptr<Region> region (RegionFactory::create (current, plist));
2448 Editor::create_region_from_selection (vector<boost::shared_ptr<Region> >& new_regions)
2450 if (selection->time.empty() || selection->tracks.empty()) {
2454 framepos_t start = selection->time[clicked_selection].start;
2455 framepos_t end = selection->time[clicked_selection].end;
2457 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
2458 sort_track_selection (ts);
2460 for (TrackSelection::iterator i = ts.begin(); i != ts.end(); ++i) {
2461 boost::shared_ptr<Region> current;
2462 boost::shared_ptr<Playlist> playlist;
2463 framepos_t internal_start;
2466 if ((playlist = (*i)->playlist()) == 0) {
2470 if ((current = playlist->top_region_at(start)) == 0) {
2474 internal_start = start - current->position();
2475 RegionFactory::region_name (new_name, current->name(), true);
2479 plist.add (ARDOUR::Properties::start, current->start() + internal_start);
2480 plist.add (ARDOUR::Properties::length, end - start + 1);
2481 plist.add (ARDOUR::Properties::name, new_name);
2483 new_regions.push_back (RegionFactory::create (current, plist));
2488 Editor::split_multichannel_region ()
2490 RegionSelection rs = get_regions_from_selection_and_entered ();
2496 vector< boost::shared_ptr<Region> > v;
2498 for (list<RegionView*>::iterator x = rs.begin(); x != rs.end(); ++x) {
2499 (*x)->region()->separate_by_channel (*_session, v);
2504 Editor::new_region_from_selection ()
2506 region_from_selection ();
2507 cancel_selection ();
2511 add_if_covered (RegionView* rv, const AudioRange* ar, RegionSelection* rs)
2513 switch (rv->region()->coverage (ar->start, ar->end - 1)) {
2514 case Evoral::OverlapNone:
2522 * - selected tracks, or if there are none...
2523 * - tracks containing selected regions, or if there are none...
2528 Editor::get_tracks_for_range_action () const
2532 if (selection->tracks.empty()) {
2534 /* use tracks with selected regions */
2536 RegionSelection rs = selection->regions;
2538 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
2539 TimeAxisView* tv = &(*i)->get_time_axis_view();
2541 if (!t.contains (tv)) {
2547 /* no regions and no tracks: use all tracks */
2553 t = selection->tracks;
2556 return t.filter_to_unique_playlists();
2560 Editor::separate_regions_between (const TimeSelection& ts)
2562 bool in_command = false;
2563 boost::shared_ptr<Playlist> playlist;
2564 RegionSelection new_selection;
2566 TrackViewList tmptracks = get_tracks_for_range_action ();
2567 sort_track_selection (tmptracks);
2569 for (TrackSelection::iterator i = tmptracks.begin(); i != tmptracks.end(); ++i) {
2571 RouteTimeAxisView* rtv;
2573 if ((rtv = dynamic_cast<RouteTimeAxisView*> ((*i))) != 0) {
2575 if (rtv->is_track()) {
2577 /* no edits to destructive tracks */
2579 if (rtv->track()->destructive()) {
2583 if ((playlist = rtv->playlist()) != 0) {
2585 playlist->clear_changes ();
2587 /* XXX need to consider musical time selections here at some point */
2589 double speed = rtv->track()->speed();
2592 for (list<AudioRange>::const_iterator t = ts.begin(); t != ts.end(); ++t) {
2594 sigc::connection c = rtv->view()->RegionViewAdded.connect (
2595 sigc::mem_fun(*this, &Editor::collect_new_region_view));
2597 latest_regionviews.clear ();
2599 playlist->partition ((framepos_t)((*t).start * speed),
2600 (framepos_t)((*t).end * speed), false);
2604 if (!latest_regionviews.empty()) {
2606 rtv->view()->foreach_regionview (sigc::bind (
2607 sigc::ptr_fun (add_if_covered),
2608 &(*t), &new_selection));
2611 begin_reversible_command (_("separate"));
2615 /* pick up changes to existing regions */
2617 vector<Command*> cmds;
2618 playlist->rdiff (cmds);
2619 _session->add_commands (cmds);
2621 /* pick up changes to the playlist itself (adds/removes)
2624 _session->add_command(new StatefulDiffCommand (playlist));
2633 selection->set (new_selection);
2634 set_mouse_mode (MouseObject);
2636 commit_reversible_command ();
2640 struct PlaylistState {
2641 boost::shared_ptr<Playlist> playlist;
2645 /** Take tracks from get_tracks_for_range_action and cut any regions
2646 * on those tracks so that the tracks are empty over the time
2650 Editor::separate_region_from_selection ()
2652 /* preferentially use *all* ranges in the time selection if we're in range mode
2653 to allow discontiguous operation, since get_edit_op_range() currently
2654 returns a single range.
2657 if (mouse_mode == MouseRange && !selection->time.empty()) {
2659 separate_regions_between (selection->time);
2666 if (get_edit_op_range (start, end)) {
2668 AudioRange ar (start, end, 1);
2672 separate_regions_between (ts);
2678 Editor::separate_region_from_punch ()
2680 Location* loc = _session->locations()->auto_punch_location();
2682 separate_regions_using_location (*loc);
2687 Editor::separate_region_from_loop ()
2689 Location* loc = _session->locations()->auto_loop_location();
2691 separate_regions_using_location (*loc);
2696 Editor::separate_regions_using_location (Location& loc)
2698 if (loc.is_mark()) {
2702 AudioRange ar (loc.start(), loc.end(), 1);
2707 separate_regions_between (ts);
2710 /** Separate regions under the selected region */
2712 Editor::separate_under_selected_regions ()
2714 vector<PlaylistState> playlists;
2718 rs = get_regions_from_selection_and_entered();
2720 if (!_session || rs.empty()) {
2724 begin_reversible_command (_("separate region under"));
2726 list<boost::shared_ptr<Region> > regions_to_remove;
2728 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
2729 // we can't just remove the region(s) in this loop because
2730 // this removes them from the RegionSelection, and they thus
2731 // disappear from underneath the iterator, and the ++i above
2732 // SEGVs in a puzzling fashion.
2734 // so, first iterate over the regions to be removed from rs and
2735 // add them to the regions_to_remove list, and then
2736 // iterate over the list to actually remove them.
2738 regions_to_remove.push_back ((*i)->region());
2741 for (list<boost::shared_ptr<Region> >::iterator rl = regions_to_remove.begin(); rl != regions_to_remove.end(); ++rl) {
2743 boost::shared_ptr<Playlist> playlist = (*rl)->playlist();
2746 // is this check necessary?
2750 vector<PlaylistState>::iterator i;
2752 //only take state if this is a new playlist.
2753 for (i = playlists.begin(); i != playlists.end(); ++i) {
2754 if ((*i).playlist == playlist) {
2759 if (i == playlists.end()) {
2761 PlaylistState before;
2762 before.playlist = playlist;
2763 before.before = &playlist->get_state();
2765 playlist->freeze ();
2766 playlists.push_back(before);
2769 //Partition on the region bounds
2770 playlist->partition ((*rl)->first_frame() - 1, (*rl)->last_frame() + 1, true);
2772 //Re-add region that was just removed due to the partition operation
2773 playlist->add_region( (*rl), (*rl)->first_frame() );
2776 vector<PlaylistState>::iterator pl;
2778 for (pl = playlists.begin(); pl != playlists.end(); ++pl) {
2779 (*pl).playlist->thaw ();
2780 _session->add_command(new MementoCommand<Playlist>(*(*pl).playlist, (*pl).before, &(*pl).playlist->get_state()));
2783 commit_reversible_command ();
2787 Editor::crop_region_to_selection ()
2789 if (!selection->time.empty()) {
2791 crop_region_to (selection->time.start(), selection->time.end_frame());
2798 if (get_edit_op_range (start, end)) {
2799 crop_region_to (start, end);
2806 Editor::crop_region_to (framepos_t start, framepos_t end)
2808 vector<boost::shared_ptr<Playlist> > playlists;
2809 boost::shared_ptr<Playlist> playlist;
2812 if (selection->tracks.empty()) {
2813 ts = track_views.filter_to_unique_playlists();
2815 ts = selection->tracks.filter_to_unique_playlists ();
2818 sort_track_selection (ts);
2820 for (TrackSelection::iterator i = ts.begin(); i != ts.end(); ++i) {
2822 RouteTimeAxisView* rtv;
2824 if ((rtv = dynamic_cast<RouteTimeAxisView*> ((*i))) != 0) {
2826 boost::shared_ptr<Track> t = rtv->track();
2828 if (t != 0 && ! t->destructive()) {
2830 if ((playlist = rtv->playlist()) != 0) {
2831 playlists.push_back (playlist);
2837 if (playlists.empty()) {
2841 framepos_t the_start;
2845 begin_reversible_command (_("trim to selection"));
2847 for (vector<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
2849 boost::shared_ptr<Region> region;
2853 if ((region = (*i)->top_region_at(the_start)) == 0) {
2857 /* now adjust lengths to that we do the right thing
2858 if the selection extends beyond the region
2861 the_start = max (the_start, (framepos_t) region->position());
2862 if (max_framepos - the_start < region->length()) {
2863 the_end = the_start + region->length() - 1;
2865 the_end = max_framepos;
2867 the_end = min (end, the_end);
2868 cnt = the_end - the_start + 1;
2870 region->clear_changes ();
2871 region->trim_to (the_start, cnt);
2872 _session->add_command (new StatefulDiffCommand (region));
2875 commit_reversible_command ();
2879 Editor::region_fill_track ()
2881 RegionSelection rs = get_regions_from_selection_and_entered ();
2883 if (!_session || rs.empty()) {
2887 framepos_t const end = _session->current_end_frame ();
2889 begin_reversible_command (Operations::region_fill);
2891 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
2893 boost::shared_ptr<Region> region ((*i)->region());
2895 boost::shared_ptr<Playlist> pl = region->playlist();
2897 if (end <= region->last_frame()) {
2901 double times = (double) (end - region->last_frame()) / (double) region->length();
2907 pl->clear_changes ();
2908 pl->add_region (RegionFactory::create (region, true), region->last_frame(), times);
2909 _session->add_command (new StatefulDiffCommand (pl));
2912 commit_reversible_command ();
2916 Editor::region_fill_selection ()
2918 if (clicked_routeview == 0 || !clicked_routeview->is_audio_track()) {
2922 if (selection->time.empty()) {
2926 boost::shared_ptr<Region> region = _regions->get_single_selection ();
2931 framepos_t start = selection->time[clicked_selection].start;
2932 framepos_t end = selection->time[clicked_selection].end;
2934 boost::shared_ptr<Playlist> playlist;
2936 if (selection->tracks.empty()) {
2940 framepos_t selection_length = end - start;
2941 float times = (float)selection_length / region->length();
2943 begin_reversible_command (Operations::fill_selection);
2945 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
2947 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
2949 if ((playlist = (*i)->playlist()) == 0) {
2953 playlist->clear_changes ();
2954 playlist->add_region (RegionFactory::create (region, true), start, times);
2955 _session->add_command (new StatefulDiffCommand (playlist));
2958 commit_reversible_command ();
2962 Editor::set_region_sync_position ()
2964 set_sync_point (get_preferred_edit_position (), get_regions_from_selection_and_edit_point ());
2968 Editor::set_sync_point (framepos_t where, const RegionSelection& rs)
2970 bool in_command = false;
2972 for (RegionSelection::const_iterator r = rs.begin(); r != rs.end(); ++r) {
2974 if (!(*r)->region()->covers (where)) {
2978 boost::shared_ptr<Region> region ((*r)->region());
2981 begin_reversible_command (_("set sync point"));
2985 region->clear_changes ();
2986 region->set_sync_position (where);
2987 _session->add_command(new StatefulDiffCommand (region));
2991 commit_reversible_command ();
2995 /** Remove the sync positions of the selection */
2997 Editor::remove_region_sync ()
2999 RegionSelection rs = get_regions_from_selection_and_entered ();
3005 begin_reversible_command (_("remove region sync"));
3007 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3009 (*i)->region()->clear_changes ();
3010 (*i)->region()->clear_sync_position ();
3011 _session->add_command(new StatefulDiffCommand ((*i)->region()));
3014 commit_reversible_command ();
3018 Editor::naturalize_region ()
3020 RegionSelection rs = get_regions_from_selection_and_entered ();
3026 if (rs.size() > 1) {
3027 begin_reversible_command (_("move regions to original position"));
3029 begin_reversible_command (_("move region to original position"));
3032 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3033 (*i)->region()->clear_changes ();
3034 (*i)->region()->move_to_natural_position ();
3035 _session->add_command (new StatefulDiffCommand ((*i)->region()));
3038 commit_reversible_command ();
3042 Editor::align_regions (RegionPoint what)
3044 RegionSelection const rs = get_regions_from_selection_and_edit_point ();
3050 begin_reversible_command (_("align selection"));
3052 framepos_t const position = get_preferred_edit_position ();
3054 for (RegionSelection::const_iterator i = rs.begin(); i != rs.end(); ++i) {
3055 align_region_internal ((*i)->region(), what, position);
3058 commit_reversible_command ();
3061 struct RegionSortByTime {
3062 bool operator() (const RegionView* a, const RegionView* b) {
3063 return a->region()->position() < b->region()->position();
3068 Editor::align_regions_relative (RegionPoint point)
3070 RegionSelection const rs = get_regions_from_selection_and_edit_point ();
3076 framepos_t const position = get_preferred_edit_position ();
3078 framepos_t distance = 0;
3082 list<RegionView*> sorted;
3083 rs.by_position (sorted);
3085 boost::shared_ptr<Region> r ((*sorted.begin())->region());
3090 if (position > r->position()) {
3091 distance = position - r->position();
3093 distance = r->position() - position;
3099 if (position > r->last_frame()) {
3100 distance = position - r->last_frame();
3101 pos = r->position() + distance;
3103 distance = r->last_frame() - position;
3104 pos = r->position() - distance;
3110 pos = r->adjust_to_sync (position);
3111 if (pos > r->position()) {
3112 distance = pos - r->position();
3114 distance = r->position() - pos;
3120 if (pos == r->position()) {
3124 begin_reversible_command (_("align selection (relative)"));
3126 /* move first one specially */
3128 r->clear_changes ();
3129 r->set_position (pos);
3130 _session->add_command(new StatefulDiffCommand (r));
3132 /* move rest by the same amount */
3136 for (list<RegionView*>::iterator i = sorted.begin(); i != sorted.end(); ++i) {
3138 boost::shared_ptr<Region> region ((*i)->region());
3140 region->clear_changes ();
3143 region->set_position (region->position() + distance);
3145 region->set_position (region->position() - distance);
3148 _session->add_command(new StatefulDiffCommand (region));
3152 commit_reversible_command ();
3156 Editor::align_region (boost::shared_ptr<Region> region, RegionPoint point, framepos_t position)
3158 begin_reversible_command (_("align region"));
3159 align_region_internal (region, point, position);
3160 commit_reversible_command ();
3164 Editor::align_region_internal (boost::shared_ptr<Region> region, RegionPoint point, framepos_t position)
3166 region->clear_changes ();
3170 region->set_position (region->adjust_to_sync (position));
3174 if (position > region->length()) {
3175 region->set_position (position - region->length());
3180 region->set_position (position);
3184 _session->add_command(new StatefulDiffCommand (region));
3188 Editor::trim_region_front ()
3194 Editor::trim_region_back ()
3196 trim_region (false);
3200 Editor::trim_region (bool front)
3202 framepos_t where = get_preferred_edit_position();
3203 RegionSelection rs = get_regions_from_selection_and_edit_point ();
3205 cerr << "trim regions\n";
3208 cerr << " no regions\n";
3212 cerr << "where = " << where << endl;
3214 begin_reversible_command (front ? _("trim front") : _("trim back"));
3216 for (list<RegionView*>::const_iterator i = rs.by_layer().begin(); i != rs.by_layer().end(); ++i) {
3217 if (!(*i)->region()->locked()) {
3219 (*i)->region()->clear_changes ();
3222 (*i)->region()->trim_front (where);
3224 (*i)->region()->trim_end (where);
3227 _session->add_command (new StatefulDiffCommand ((*i)->region()));
3231 commit_reversible_command ();
3234 /** Trim the end of the selected regions to the position of the edit cursor */
3236 Editor::trim_region_to_loop ()
3238 Location* loc = _session->locations()->auto_loop_location();
3242 trim_region_to_location (*loc, _("trim to loop"));
3246 Editor::trim_region_to_punch ()
3248 Location* loc = _session->locations()->auto_punch_location();
3252 trim_region_to_location (*loc, _("trim to punch"));
3256 Editor::trim_region_to_location (const Location& loc, const char* str)
3258 RegionSelection rs = get_regions_from_selection_and_entered ();
3260 begin_reversible_command (str);
3262 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
3263 RegionView* rv = (*x);
3265 /* require region to span proposed trim */
3266 switch (rv->region()->coverage (loc.start(), loc.end())) {
3267 case Evoral::OverlapInternal:
3273 RouteTimeAxisView* tav = dynamic_cast<RouteTimeAxisView*> (&rv->get_time_axis_view());
3282 if (tav->track() != 0) {
3283 speed = tav->track()->speed();
3286 start = session_frame_to_track_frame (loc.start(), speed);
3287 end = session_frame_to_track_frame (loc.end(), speed);
3289 rv->region()->clear_changes ();
3290 rv->region()->trim_to (start, (end - start));
3291 _session->add_command(new StatefulDiffCommand (rv->region()));
3294 commit_reversible_command ();
3298 Editor::trim_region_to_previous_region_end ()
3300 return trim_to_region(false);
3304 Editor::trim_region_to_next_region_start ()
3306 return trim_to_region(true);
3310 Editor::trim_to_region(bool forward)
3312 RegionSelection rs = get_regions_from_selection_and_entered ();
3314 begin_reversible_command (_("trim to region"));
3316 boost::shared_ptr<Region> next_region;
3318 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
3320 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*x);
3326 AudioTimeAxisView* atav = dynamic_cast<AudioTimeAxisView*> (&arv->get_time_axis_view());
3334 if (atav->track() != 0) {
3335 speed = atav->track()->speed();
3339 boost::shared_ptr<Region> region = arv->region();
3340 boost::shared_ptr<Playlist> playlist (region->playlist());
3342 region->clear_changes ();
3346 next_region = playlist->find_next_region (region->first_frame(), Start, 1);
3352 region->trim_end((framepos_t) ( (next_region->first_frame() - 1) * speed));
3353 arv->region_changed (PropertyChange (ARDOUR::Properties::length));
3357 next_region = playlist->find_next_region (region->first_frame(), Start, 0);
3363 region->trim_front((framepos_t) ((next_region->last_frame() + 1) * speed));
3365 arv->region_changed (ARDOUR::bounds_change);
3368 _session->add_command(new StatefulDiffCommand (region));
3371 commit_reversible_command ();
3375 Editor::unfreeze_route ()
3377 if (clicked_routeview == 0 || !clicked_routeview->is_track()) {
3381 clicked_routeview->track()->unfreeze ();
3385 Editor::_freeze_thread (void* arg)
3387 return static_cast<Editor*>(arg)->freeze_thread ();
3391 Editor::freeze_thread ()
3393 /* create event pool because we may need to talk to the session */
3394 SessionEvent::create_per_thread_pool ("freeze events", 64);
3395 /* create per-thread buffers for process() tree to use */
3396 current_interthread_info->process_thread.init ();
3397 current_interthread_info->process_thread.get_buffers ();
3398 clicked_routeview->audio_track()->freeze_me (*current_interthread_info);
3399 current_interthread_info->done = true;
3400 current_interthread_info->process_thread.drop_buffers();
3405 Editor::freeze_route ()
3411 /* stop transport before we start. this is important */
3413 _session->request_transport_speed (0.0);
3415 /* wait for just a little while, because the above call is asynchronous */
3419 if (clicked_routeview == 0 || !clicked_routeview->is_audio_track()) {
3423 if (!clicked_routeview->track()->bounceable (clicked_routeview->track()->main_outs(), true)) {
3425 _("This track/bus cannot be frozen because the signal adds or loses channels before reaching the outputs.\n"
3426 "This is typically caused by plugins that generate stereo output from mono input or vice versa.")
3428 d.set_title (_("Cannot freeze"));
3433 if (clicked_routeview->track()->has_external_redirects()) {
3434 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"
3435 "Freezing will only process the signal as far as the first send/insert/return."),
3436 clicked_routeview->track()->name()), true, MESSAGE_INFO, BUTTONS_NONE, true);
3438 d.add_button (_("Freeze anyway"), Gtk::RESPONSE_OK);
3439 d.add_button (_("Don't freeze"), Gtk::RESPONSE_CANCEL);
3440 d.set_title (_("Freeze Limits"));
3442 int response = d.run ();
3445 case Gtk::RESPONSE_CANCEL:
3452 InterThreadInfo itt;
3453 current_interthread_info = &itt;
3455 InterthreadProgressWindow ipw (current_interthread_info, _("Freeze"), _("Cancel Freeze"));
3457 pthread_create_and_store (X_("freezer"), &itt.thread, _freeze_thread, this);
3459 set_canvas_cursor (_cursors->wait);
3461 while (!itt.done && !itt.cancel) {
3462 gtk_main_iteration ();
3465 current_interthread_info = 0;
3466 set_canvas_cursor (current_canvas_cursor);
3470 Editor::bounce_range_selection (bool replace, bool enable_processing)
3472 if (selection->time.empty()) {
3476 TrackSelection views = selection->tracks;
3478 for (TrackViewList::iterator i = views.begin(); i != views.end(); ++i) {
3480 if (enable_processing) {
3482 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*i);
3484 if (rtv && rtv->track() && replace && enable_processing && !rtv->track()->bounceable (rtv->track()->main_outs(), false)) {
3486 _("You can't perform this operation because the processing of the signal "
3487 "will cause one or more of the tracks will end up with a region with more channels than this track has inputs.\n\n"
3488 "You can do this without processing, which is a different operation.")
3490 d.set_title (_("Cannot bounce"));
3497 framepos_t start = selection->time[clicked_selection].start;
3498 framepos_t end = selection->time[clicked_selection].end;
3499 framepos_t cnt = end - start + 1;
3501 begin_reversible_command (_("bounce range"));
3503 for (TrackViewList::iterator i = views.begin(); i != views.end(); ++i) {
3505 RouteTimeAxisView* rtv;
3507 if ((rtv = dynamic_cast<RouteTimeAxisView*> (*i)) == 0) {
3511 boost::shared_ptr<Playlist> playlist;
3513 if ((playlist = rtv->playlist()) == 0) {
3517 InterThreadInfo itt;
3519 playlist->clear_changes ();
3520 playlist->clear_owned_changes ();
3522 boost::shared_ptr<Region> r;
3524 if (enable_processing) {
3525 r = rtv->track()->bounce_range (start, start+cnt, itt, rtv->track()->main_outs(), false);
3527 r = rtv->track()->bounce_range (start, start+cnt, itt, boost::shared_ptr<Processor>(), false);
3535 list<AudioRange> ranges;
3536 ranges.push_back (AudioRange (start, start+cnt, 0));
3537 playlist->cut (ranges); // discard result
3538 playlist->add_region (r, start);
3541 vector<Command*> cmds;
3542 playlist->rdiff (cmds);
3543 _session->add_commands (cmds);
3545 _session->add_command (new StatefulDiffCommand (playlist));
3548 commit_reversible_command ();
3551 /** Delete selected regions, automation points or a time range */
3558 /** Cut selected regions, automation points or a time range */
3565 /** Copy selected regions, automation points or a time range */
3573 /** @return true if a Cut, Copy or Clear is possible */
3575 Editor::can_cut_copy () const
3577 switch (current_mouse_mode()) {
3580 if (!selection->regions.empty() || !selection->points.empty()) {
3586 if (!selection->time.empty()) {
3599 /** Cut, copy or clear selected regions, automation points or a time range.
3600 * @param op Operation (Cut, Copy or Clear)
3603 Editor::cut_copy (CutCopyOp op)
3605 /* only cancel selection if cut/copy is successful.*/
3611 opname = _("delete");
3620 opname = _("clear");
3624 /* if we're deleting something, and the mouse is still pressed,
3625 the thing we started a drag for will be gone when we release
3626 the mouse button(s). avoid this. see part 2 at the end of
3630 if (op == Delete || op == Cut || op == Clear) {
3631 if (_drags->active ()) {
3636 cut_buffer->clear ();
3638 if (entered_marker) {
3640 /* cut/delete op while pointing at a marker */
3643 Location* loc = find_location_from_marker (entered_marker, ignored);
3645 if (_session && loc) {
3646 Glib::signal_idle().connect (sigc::bind (sigc::mem_fun(*this, &Editor::really_remove_marker), loc));
3653 if (internal_editing()) {
3655 switch (current_mouse_mode()) {
3668 /* we only want to cut regions if some are selected */
3670 if (doing_object_stuff()) {
3671 rs = get_regions_from_selection ();
3672 if (!rs.empty() || !selection->points.empty()) {
3674 begin_reversible_command (opname + _(" objects"));
3677 cut_copy_regions (op, rs);
3679 if (op == Cut || op == Delete) {
3680 selection->clear_regions ();
3684 if (!selection->points.empty()) {
3685 cut_copy_points (op);
3687 if (op == Cut || op == Delete) {
3688 selection->clear_points ();
3691 commit_reversible_command ();
3694 if (!selection->time.empty() && (_join_object_range_state == JOIN_OBJECT_RANGE_NONE)) {
3695 /* don't cause suprises */
3700 if (doing_range_stuff()) {
3701 if (selection->time.empty()) {
3702 framepos_t start, end;
3703 if (!get_edit_op_range (start, end)) {
3706 selection->set (start, end);
3709 begin_reversible_command (opname + _(" range"));
3710 cut_copy_ranges (op);
3711 commit_reversible_command ();
3713 if (op == Cut || op == Delete) {
3714 selection->clear_time ();
3720 if (op == Delete || op == Cut || op == Clear) {
3725 struct AutomationRecord {
3726 AutomationRecord () : state (0) {}
3727 AutomationRecord (XMLNode* s) : state (s) {}
3729 XMLNode* state; ///< state before any operation
3730 boost::shared_ptr<Evoral::ControlList> copy; ///< copied events for the cut buffer
3733 /** Cut, copy or clear selected automation points.
3734 * @param op Operation (Cut, Copy or Clear)
3737 Editor::cut_copy_points (CutCopyOp op)
3739 if (selection->points.empty ()) {
3743 /* XXX: not ideal, as there may be more than one track involved in the point selection */
3744 _last_cut_copy_source_track = &selection->points.front()->line().trackview;
3746 /* Keep a record of the AutomationLists that we end up using in this operation */
3747 typedef std::map<boost::shared_ptr<AutomationList>, AutomationRecord> Lists;
3750 /* Go through all selected points, making an AutomationRecord for each distinct AutomationList */
3751 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
3752 boost::shared_ptr<AutomationList> al = (*i)->line().the_list();
3753 if (lists.find (al) == lists.end ()) {
3754 /* We haven't seen this list yet, so make a record for it. This includes
3755 taking a copy of its current state, in case this is needed for undo later.
3757 lists[al] = AutomationRecord (&al->get_state ());
3761 if (op == Cut || op == Copy) {
3762 /* This operation will involve putting things in the cut buffer, so create an empty
3763 ControlList for each of our source lists to put the cut buffer data in.
3765 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
3766 i->second.copy = i->first->create (i->first->parameter ());
3769 /* Add all selected points to the relevant copy ControlLists */
3770 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
3771 boost::shared_ptr<AutomationList> al = (*i)->line().the_list();
3772 AutomationList::const_iterator j = (*i)->model ();
3773 lists[al].copy->add ((*j)->when, (*j)->value);
3776 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
3777 /* Correct this copy list so that it starts at time 0 */
3778 double const start = i->second.copy->front()->when;
3779 for (AutomationList::iterator j = i->second.copy->begin(); j != i->second.copy->end(); ++j) {
3780 (*j)->when -= start;
3783 /* And add it to the cut buffer */
3784 cut_buffer->add (i->second.copy);
3788 if (op == Delete || op == Cut) {
3789 /* This operation needs to remove things from the main AutomationList, so do that now */
3791 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
3792 i->first->freeze ();
3795 /* Remove each selected point from its AutomationList */
3796 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
3797 boost::shared_ptr<AutomationList> al = (*i)->line().the_list();
3798 al->erase ((*i)->model ());
3801 /* Thaw the lists and add undo records for them */
3802 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
3803 boost::shared_ptr<AutomationList> al = i->first;
3805 _session->add_command (new MementoCommand<AutomationList> (*al.get(), i->second.state, &(al->get_state ())));
3810 /** Cut, copy or clear selected automation points.
3811 * @param op Operation (Cut, Copy or Clear)
3814 Editor::cut_copy_midi (CutCopyOp op)
3816 for (MidiRegionSelection::iterator i = selection->midi_regions.begin(); i != selection->midi_regions.end(); ++i) {
3817 MidiRegionView* mrv = *i;
3818 mrv->cut_copy_clear (op);
3824 struct lt_playlist {
3825 bool operator () (const PlaylistState& a, const PlaylistState& b) {
3826 return a.playlist < b.playlist;
3830 struct PlaylistMapping {
3832 boost::shared_ptr<Playlist> pl;
3834 PlaylistMapping (TimeAxisView* tvp) : tv (tvp) {}
3837 /** Remove `clicked_regionview' */
3839 Editor::remove_clicked_region ()
3841 if (clicked_routeview == 0 || clicked_regionview == 0) {
3845 boost::shared_ptr<Playlist> playlist = clicked_routeview->playlist();
3847 begin_reversible_command (_("remove region"));
3848 playlist->clear_changes ();
3849 playlist->clear_owned_changes ();
3850 playlist->remove_region (clicked_regionview->region());
3852 /* We might have removed regions, which alters other regions' layering_index,
3853 so we need to do a recursive diff here.
3855 vector<Command*> cmds;
3856 playlist->rdiff (cmds);
3857 _session->add_commands (cmds);
3859 _session->add_command(new StatefulDiffCommand (playlist));
3860 commit_reversible_command ();
3864 /** Remove the selected regions */
3866 Editor::remove_selected_regions ()
3868 RegionSelection rs = get_regions_from_selection_and_entered ();
3870 if (!_session || rs.empty()) {
3874 begin_reversible_command (_("remove region"));
3876 list<boost::shared_ptr<Region> > regions_to_remove;
3878 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3879 // we can't just remove the region(s) in this loop because
3880 // this removes them from the RegionSelection, and they thus
3881 // disappear from underneath the iterator, and the ++i above
3882 // SEGVs in a puzzling fashion.
3884 // so, first iterate over the regions to be removed from rs and
3885 // add them to the regions_to_remove list, and then
3886 // iterate over the list to actually remove them.
3888 regions_to_remove.push_back ((*i)->region());
3891 vector<boost::shared_ptr<Playlist> > playlists;
3893 for (list<boost::shared_ptr<Region> >::iterator rl = regions_to_remove.begin(); rl != regions_to_remove.end(); ++rl) {
3895 boost::shared_ptr<Playlist> playlist = (*rl)->playlist();
3898 // is this check necessary?
3902 /* get_regions_from_selection_and_entered() guarantees that
3903 the playlists involved are unique, so there is no need
3907 playlists.push_back (playlist);
3909 playlist->clear_changes ();
3910 playlist->clear_owned_changes ();
3911 playlist->freeze ();
3912 playlist->remove_region (*rl);
3915 vector<boost::shared_ptr<Playlist> >::iterator pl;
3917 for (pl = playlists.begin(); pl != playlists.end(); ++pl) {
3920 /* We might have removed regions, which alters other regions' layering_index,
3921 so we need to do a recursive diff here.
3923 vector<Command*> cmds;
3924 (*pl)->rdiff (cmds);
3925 _session->add_commands (cmds);
3927 _session->add_command(new StatefulDiffCommand (*pl));
3930 commit_reversible_command ();
3933 /** Cut, copy or clear selected regions.
3934 * @param op Operation (Cut, Copy or Clear)
3937 Editor::cut_copy_regions (CutCopyOp op, RegionSelection& rs)
3939 /* we can't use a std::map here because the ordering is important, and we can't trivially sort
3940 a map when we want ordered access to both elements. i think.
3943 vector<PlaylistMapping> pmap;
3945 framepos_t first_position = max_framepos;
3947 typedef set<boost::shared_ptr<Playlist> > FreezeList;
3948 FreezeList freezelist;
3950 /* get ordering correct before we cut/copy */
3952 rs.sort_by_position_and_track ();
3954 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
3956 first_position = min ((framepos_t) (*x)->region()->position(), first_position);
3958 if (op == Cut || op == Clear || op == Delete) {
3959 boost::shared_ptr<Playlist> pl = (*x)->region()->playlist();
3962 FreezeList::iterator fl;
3964 // only take state if this is a new playlist.
3965 for (fl = freezelist.begin(); fl != freezelist.end(); ++fl) {
3971 if (fl == freezelist.end()) {
3972 pl->clear_changes();
3973 pl->clear_owned_changes ();
3975 freezelist.insert (pl);
3980 TimeAxisView* tv = &(*x)->get_time_axis_view();
3981 vector<PlaylistMapping>::iterator z;
3983 for (z = pmap.begin(); z != pmap.end(); ++z) {
3984 if ((*z).tv == tv) {
3989 if (z == pmap.end()) {
3990 pmap.push_back (PlaylistMapping (tv));
3994 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ) {
3996 boost::shared_ptr<Playlist> pl = (*x)->region()->playlist();
3999 /* region not yet associated with a playlist (e.g. unfinished
4006 TimeAxisView& tv = (*x)->get_time_axis_view();
4007 boost::shared_ptr<Playlist> npl;
4008 RegionSelection::iterator tmp;
4015 vector<PlaylistMapping>::iterator z;
4017 for (z = pmap.begin(); z != pmap.end(); ++z) {
4018 if ((*z).tv == &tv) {
4023 assert (z != pmap.end());
4026 npl = PlaylistFactory::create (pl->data_type(), *_session, "cutlist", true);
4034 boost::shared_ptr<Region> r = (*x)->region();
4035 boost::shared_ptr<Region> _xx;
4041 pl->remove_region (r);
4045 _xx = RegionFactory::create (r);
4046 npl->add_region (_xx, r->position() - first_position);
4047 pl->remove_region (r);
4051 /* copy region before adding, so we're not putting same object into two different playlists */
4052 npl->add_region (RegionFactory::create (r), r->position() - first_position);
4056 pl->remove_region (r);
4065 list<boost::shared_ptr<Playlist> > foo;
4067 /* the pmap is in the same order as the tracks in which selected regions occured */
4069 for (vector<PlaylistMapping>::iterator i = pmap.begin(); i != pmap.end(); ++i) {
4072 foo.push_back ((*i).pl);
4077 cut_buffer->set (foo);
4081 _last_cut_copy_source_track = 0;
4083 _last_cut_copy_source_track = pmap.front().tv;
4087 for (FreezeList::iterator pl = freezelist.begin(); pl != freezelist.end(); ++pl) {
4090 /* We might have removed regions, which alters other regions' layering_index,
4091 so we need to do a recursive diff here.
4093 vector<Command*> cmds;
4094 (*pl)->rdiff (cmds);
4095 _session->add_commands (cmds);
4097 _session->add_command (new StatefulDiffCommand (*pl));
4102 Editor::cut_copy_ranges (CutCopyOp op)
4104 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4106 /* Sort the track selection now, so that it if is used, the playlists
4107 selected by the calls below to cut_copy_clear are in the order that
4108 their tracks appear in the editor. This makes things like paste
4109 of ranges work properly.
4112 sort_track_selection (ts);
4115 if (!entered_track) {
4118 ts.push_back (entered_track);
4121 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4122 (*i)->cut_copy_clear (*selection, op);
4127 Editor::paste (float times, bool from_context)
4129 DEBUG_TRACE (DEBUG::CutNPaste, "paste to preferred edit pos\n");
4131 paste_internal (get_preferred_edit_position (false, from_context), times);
4135 Editor::mouse_paste ()
4140 if (!mouse_frame (where, ignored)) {
4145 paste_internal (where, 1);
4149 Editor::paste_internal (framepos_t position, float times)
4151 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("apparent paste position is %1\n", position));
4153 if (internal_editing()) {
4154 if (cut_buffer->midi_notes.empty()) {
4158 if (cut_buffer->empty()) {
4163 if (position == max_framepos) {
4164 position = get_preferred_edit_position();
4165 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("preferred edit position is %1\n", position));
4169 TrackViewList::iterator i;
4172 /* get everything in the correct order */
4174 if (!selection->tracks.empty()) {
4175 /* there are some selected tracks, so paste to them */
4176 ts = selection->tracks.filter_to_unique_playlists ();
4177 sort_track_selection (ts);
4178 } else if (_last_cut_copy_source_track) {
4179 /* otherwise paste to the track that the cut/copy came from;
4180 see discussion in mantis #3333.
4182 ts.push_back (_last_cut_copy_source_track);
4185 if (internal_editing ()) {
4187 /* undo/redo is handled by individual tracks/regions */
4189 for (nth = 0, i = ts.begin(); i != ts.end(); ++i, ++nth) {
4192 RegionSelection::iterator r;
4193 MidiNoteSelection::iterator cb;
4195 get_regions_at (rs, position, ts);
4197 for (cb = cut_buffer->midi_notes.begin(), r = rs.begin();
4198 cb != cut_buffer->midi_notes.end() && r != rs.end(); ++r) {
4199 MidiRegionView* mrv = dynamic_cast<MidiRegionView*> (*r);
4201 mrv->paste (position, times, **cb);
4209 /* we do redo (do you do voodoo?) */
4211 begin_reversible_command (Operations::paste);
4213 for (nth = 0, i = ts.begin(); i != ts.end(); ++i, ++nth) {
4214 (*i)->paste (position, times, *cut_buffer, nth);
4217 commit_reversible_command ();
4222 Editor::duplicate_some_regions (RegionSelection& regions, float times)
4224 boost::shared_ptr<Playlist> playlist;
4225 RegionSelection sel = regions; // clear (below) may clear the argument list if its the current region selection
4226 RegionSelection foo;
4228 framepos_t const start_frame = regions.start ();
4229 framepos_t const end_frame = regions.end_frame ();
4231 begin_reversible_command (Operations::duplicate_region);
4233 selection->clear_regions ();
4235 for (RegionSelection::iterator i = sel.begin(); i != sel.end(); ++i) {
4237 boost::shared_ptr<Region> r ((*i)->region());
4239 TimeAxisView& tv = (*i)->get_time_axis_view();
4240 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (&tv);
4241 latest_regionviews.clear ();
4242 sigc::connection c = rtv->view()->RegionViewAdded.connect (sigc::mem_fun(*this, &Editor::collect_new_region_view));
4244 playlist = (*i)->region()->playlist();
4245 playlist->clear_changes ();
4246 playlist->duplicate (r, end_frame + (r->first_frame() - start_frame), times);
4247 _session->add_command(new StatefulDiffCommand (playlist));
4251 foo.insert (foo.end(), latest_regionviews.begin(), latest_regionviews.end());
4254 commit_reversible_command ();
4257 selection->set (foo);
4262 Editor::duplicate_selection (float times)
4264 if (selection->time.empty() || selection->tracks.empty()) {
4268 boost::shared_ptr<Playlist> playlist;
4269 vector<boost::shared_ptr<Region> > new_regions;
4270 vector<boost::shared_ptr<Region> >::iterator ri;
4272 create_region_from_selection (new_regions);
4274 if (new_regions.empty()) {
4278 begin_reversible_command (_("duplicate selection"));
4280 ri = new_regions.begin();
4282 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4284 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4285 if ((playlist = (*i)->playlist()) == 0) {
4288 playlist->clear_changes ();
4289 playlist->duplicate (*ri, selection->time[clicked_selection].end, times);
4290 _session->add_command (new StatefulDiffCommand (playlist));
4293 if (ri == new_regions.end()) {
4298 commit_reversible_command ();
4301 /** Reset all selected points to the relevant default value */
4303 Editor::reset_point_selection ()
4305 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
4306 ARDOUR::AutomationList::iterator j = (*i)->model ();
4307 (*j)->value = (*i)->line().the_list()->default_value ();
4312 Editor::center_playhead ()
4314 float page = _canvas_width * frames_per_unit;
4315 center_screen_internal (playhead_cursor->current_frame, page);
4319 Editor::center_edit_point ()
4321 float page = _canvas_width * frames_per_unit;
4322 center_screen_internal (get_preferred_edit_position(), page);
4325 /** Caller must begin and commit a reversible command */
4327 Editor::clear_playlist (boost::shared_ptr<Playlist> playlist)
4329 playlist->clear_changes ();
4331 _session->add_command (new StatefulDiffCommand (playlist));
4335 Editor::nudge_track (bool use_edit, bool forwards)
4337 boost::shared_ptr<Playlist> playlist;
4338 framepos_t distance;
4339 framepos_t next_distance;
4343 start = get_preferred_edit_position();
4348 if ((distance = get_nudge_distance (start, next_distance)) == 0) {
4352 if (selection->tracks.empty()) {
4356 begin_reversible_command (_("nudge track"));
4358 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4360 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4362 if ((playlist = (*i)->playlist()) == 0) {
4366 playlist->clear_changes ();
4367 playlist->clear_owned_changes ();
4369 playlist->nudge_after (start, distance, forwards);
4371 vector<Command*> cmds;
4373 playlist->rdiff (cmds);
4374 _session->add_commands (cmds);
4376 _session->add_command (new StatefulDiffCommand (playlist));
4379 commit_reversible_command ();
4383 Editor::remove_last_capture ()
4385 vector<string> choices;
4392 if (Config->get_verify_remove_last_capture()) {
4393 prompt = _("Do you really want to destroy the last capture?"
4394 "\n(This is destructive and cannot be undone)");
4396 choices.push_back (_("No, do nothing."));
4397 choices.push_back (_("Yes, destroy it."));
4399 Gtkmm2ext::Choice prompter (_("Destroy last capture"), prompt, choices);
4401 if (prompter.run () == 1) {
4402 _session->remove_last_capture ();
4403 _regions->redisplay ();
4407 _session->remove_last_capture();
4408 _regions->redisplay ();
4413 Editor::normalize_region ()
4419 RegionSelection rs = get_regions_from_selection_and_entered ();
4425 NormalizeDialog dialog (rs.size() > 1);
4427 if (dialog.run () == RESPONSE_CANCEL) {
4431 set_canvas_cursor (_cursors->wait);
4434 /* XXX: should really only count audio regions here */
4435 int const regions = rs.size ();
4437 /* Make a list of the selected audio regions' maximum amplitudes, and also
4438 obtain the maximum amplitude of them all.
4440 list<double> max_amps;
4442 for (RegionSelection::const_iterator i = rs.begin(); i != rs.end(); ++i) {
4443 AudioRegionView const * arv = dynamic_cast<AudioRegionView const *> (*i);
4445 dialog.descend (1.0 / regions);
4446 double const a = arv->audio_region()->maximum_amplitude (&dialog);
4449 /* the user cancelled the operation */
4450 set_canvas_cursor (current_canvas_cursor);
4454 max_amps.push_back (a);
4455 max_amp = max (max_amp, a);
4460 begin_reversible_command (_("normalize"));
4462 list<double>::const_iterator a = max_amps.begin ();
4464 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
4465 AudioRegionView* const arv = dynamic_cast<AudioRegionView*> (*r);
4470 arv->region()->clear_changes ();
4472 double const amp = dialog.normalize_individually() ? *a : max_amp;
4474 arv->audio_region()->normalize (amp, dialog.target ());
4475 _session->add_command (new StatefulDiffCommand (arv->region()));
4480 commit_reversible_command ();
4481 set_canvas_cursor (current_canvas_cursor);
4486 Editor::reset_region_scale_amplitude ()
4492 RegionSelection rs = get_regions_from_selection_and_entered ();
4498 begin_reversible_command ("reset gain");
4500 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
4501 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
4504 arv->region()->clear_changes ();
4505 arv->audio_region()->set_scale_amplitude (1.0f);
4506 _session->add_command (new StatefulDiffCommand (arv->region()));
4509 commit_reversible_command ();
4513 Editor::adjust_region_gain (bool up)
4515 RegionSelection rs = get_regions_from_selection_and_entered ();
4517 if (!_session || rs.empty()) {
4521 begin_reversible_command ("adjust region gain");
4523 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
4524 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
4529 arv->region()->clear_changes ();
4531 double dB = accurate_coefficient_to_dB (arv->audio_region()->scale_amplitude ());
4539 arv->audio_region()->set_scale_amplitude (dB_to_coefficient (dB));
4540 _session->add_command (new StatefulDiffCommand (arv->region()));
4543 commit_reversible_command ();
4548 Editor::reverse_region ()
4554 Reverse rev (*_session);
4555 apply_filter (rev, _("reverse regions"));
4559 Editor::strip_region_silence ()
4565 RegionSelection rs = get_regions_from_selection_and_entered ();
4571 std::list<RegionView*> audio_only;
4573 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
4574 AudioRegionView* const arv = dynamic_cast<AudioRegionView*> (*i);
4576 audio_only.push_back (arv);
4580 StripSilenceDialog d (_session, audio_only);
4581 int const r = d.run ();
4585 if (r == Gtk::RESPONSE_OK) {
4586 ARDOUR::AudioIntervalMap silences;
4587 d.silences (silences);
4588 StripSilence s (*_session, silences, d.fade_length());
4589 apply_filter (s, _("strip silence"), &d);
4594 Editor::apply_midi_note_edit_op_to_region (MidiOperator& op, MidiRegionView& mrv)
4596 Evoral::Sequence<Evoral::MusicalTime>::Notes selected;
4597 mrv.selection_as_notelist (selected, true);
4599 vector<Evoral::Sequence<Evoral::MusicalTime>::Notes> v;
4600 v.push_back (selected);
4602 framepos_t pos_frames = mrv.midi_region()->position();
4603 double pos_beats = _session->tempo_map().framewalk_to_beats(0, pos_frames);
4605 return op (mrv.midi_region()->model(), pos_beats, v);
4609 Editor::apply_midi_note_edit_op (MidiOperator& op)
4613 RegionSelection rs = get_regions_from_selection_and_entered ();
4619 begin_reversible_command (op.name ());
4621 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
4622 RegionSelection::iterator tmp = r;
4625 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*r);
4628 cmd = apply_midi_note_edit_op_to_region (op, *mrv);
4631 _session->add_command (cmd);
4638 commit_reversible_command ();
4642 Editor::fork_region ()
4644 RegionSelection rs = get_regions_from_selection_and_entered ();
4650 begin_reversible_command (_("Fork Region(s)"));
4652 set_canvas_cursor (_cursors->wait);
4655 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
4656 RegionSelection::iterator tmp = r;
4659 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*>(*r);
4662 boost::shared_ptr<Playlist> playlist = mrv->region()->playlist();
4663 boost::shared_ptr<MidiRegion> newregion = mrv->midi_region()->clone ();
4665 playlist->clear_changes ();
4666 playlist->replace_region (mrv->region(), newregion, mrv->region()->position());
4667 _session->add_command(new StatefulDiffCommand (playlist));
4673 commit_reversible_command ();
4675 set_canvas_cursor (current_canvas_cursor);
4679 Editor::quantize_region ()
4681 int selected_midi_region_cnt = 0;
4687 RegionSelection rs = get_regions_from_selection_and_entered ();
4693 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
4694 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*r);
4696 selected_midi_region_cnt++;
4700 if (selected_midi_region_cnt == 0) {
4704 QuantizeDialog* qd = new QuantizeDialog (*this);
4707 const int r = qd->run ();
4710 if (r == Gtk::RESPONSE_OK) {
4711 Quantize quant (*_session, qd->snap_start(), qd->snap_end(),
4712 qd->start_grid_size(), qd->end_grid_size(),
4713 qd->strength(), qd->swing(), qd->threshold());
4715 apply_midi_note_edit_op (quant);
4720 Editor::insert_patch_change (bool from_context)
4722 RegionSelection rs = get_regions_from_selection_and_entered ();
4728 const framepos_t p = get_preferred_edit_position (false, from_context);
4730 Evoral::PatchChange<Evoral::MusicalTime> empty (0, 0, 0, 0);
4731 PatchChangeDialog d (0, _session, empty, Gtk::Stock::ADD);
4733 if (d.run() == RESPONSE_CANCEL) {
4737 for (RegionSelection::iterator i = rs.begin (); i != rs.end(); ++i) {
4738 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*i);
4740 if (p >= mrv->region()->first_frame() && p <= mrv->region()->last_frame()) {
4741 mrv->add_patch_change (p - mrv->region()->position(), d.patch ());
4748 Editor::apply_filter (Filter& filter, string command, ProgressReporter* progress)
4750 RegionSelection rs = get_regions_from_selection_and_entered ();
4756 begin_reversible_command (command);
4758 set_canvas_cursor (_cursors->wait);
4762 int const N = rs.size ();
4764 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
4765 RegionSelection::iterator tmp = r;
4768 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
4770 boost::shared_ptr<Playlist> playlist = arv->region()->playlist();
4773 progress->descend (1.0 / N);
4776 if (arv->audio_region()->apply (filter, progress) == 0) {
4778 playlist->clear_changes ();
4779 playlist->clear_owned_changes ();
4781 if (filter.results.empty ()) {
4783 /* no regions returned; remove the old one */
4784 playlist->remove_region (arv->region ());
4788 std::vector<boost::shared_ptr<Region> >::iterator res = filter.results.begin ();
4790 /* first region replaces the old one */
4791 playlist->replace_region (arv->region(), *res, (*res)->position());
4795 while (res != filter.results.end()) {
4796 playlist->add_region (*res, (*res)->position());
4802 /* We might have removed regions, which alters other regions' layering_index,
4803 so we need to do a recursive diff here.
4805 vector<Command*> cmds;
4806 playlist->rdiff (cmds);
4807 _session->add_commands (cmds);
4809 _session->add_command(new StatefulDiffCommand (playlist));
4815 progress->ascend ();
4823 commit_reversible_command ();
4826 set_canvas_cursor (current_canvas_cursor);
4830 Editor::external_edit_region ()
4836 Editor::reset_region_gain_envelopes ()
4838 RegionSelection rs = get_regions_from_selection_and_entered ();
4840 if (!_session || rs.empty()) {
4844 _session->begin_reversible_command (_("reset region gain"));
4846 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
4847 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
4849 boost::shared_ptr<AutomationList> alist (arv->audio_region()->envelope());
4850 XMLNode& before (alist->get_state());
4852 arv->audio_region()->set_default_envelope ();
4853 _session->add_command (new MementoCommand<AutomationList>(*arv->audio_region()->envelope().get(), &before, &alist->get_state()));
4857 _session->commit_reversible_command ();
4861 Editor::set_region_gain_visibility (RegionView* rv, bool yn)
4863 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (rv);
4865 arv->set_envelope_visible (yn);
4870 Editor::set_gain_envelope_visibility (bool yn)
4876 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4877 AudioTimeAxisView* v = dynamic_cast<AudioTimeAxisView*>(*i);
4879 v->audio_view()->foreach_regionview (sigc::bind (sigc::mem_fun (this, &Editor::set_region_gain_visibility), yn));
4885 Editor::toggle_gain_envelope_active ()
4887 if (_ignore_region_action) {
4891 RegionSelection rs = get_regions_from_selection_and_entered ();
4893 if (!_session || rs.empty()) {
4897 _session->begin_reversible_command (_("region gain envelope active"));
4899 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
4900 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
4902 arv->region()->clear_changes ();
4903 arv->audio_region()->set_envelope_active (!arv->audio_region()->envelope_active());
4904 _session->add_command (new StatefulDiffCommand (arv->region()));
4908 _session->commit_reversible_command ();
4912 Editor::toggle_region_lock ()
4914 if (_ignore_region_action) {
4918 RegionSelection rs = get_regions_from_selection_and_entered ();
4920 if (!_session || rs.empty()) {
4924 _session->begin_reversible_command (_("toggle region lock"));
4926 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
4927 (*i)->region()->clear_changes ();
4928 (*i)->region()->set_locked (!(*i)->region()->locked());
4929 _session->add_command (new StatefulDiffCommand ((*i)->region()));
4932 _session->commit_reversible_command ();
4936 Editor::toggle_region_lock_style ()
4938 if (_ignore_region_action) {
4942 RegionSelection rs = get_regions_from_selection_and_entered ();
4944 if (!_session || rs.empty()) {
4948 _session->begin_reversible_command (_("region lock style"));
4950 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
4951 (*i)->region()->clear_changes ();
4952 PositionLockStyle const ns = (*i)->region()->position_lock_style() == AudioTime ? MusicTime : AudioTime;
4953 (*i)->region()->set_position_lock_style (ns);
4954 _session->add_command (new StatefulDiffCommand ((*i)->region()));
4957 _session->commit_reversible_command ();
4961 Editor::toggle_opaque_region ()
4963 if (_ignore_region_action) {
4967 RegionSelection rs = get_regions_from_selection_and_entered ();
4969 if (!_session || rs.empty()) {
4973 _session->begin_reversible_command (_("change region opacity"));
4975 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
4976 (*i)->region()->clear_changes ();
4977 (*i)->region()->set_opaque (!(*i)->region()->opaque());
4978 _session->add_command (new StatefulDiffCommand ((*i)->region()));
4981 _session->commit_reversible_command ();
4985 Editor::toggle_record_enable ()
4987 bool new_state = false;
4989 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4990 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
4993 if (!rtav->is_track())
4997 new_state = !rtav->track()->record_enabled();
5001 rtav->track()->set_record_enabled (new_state, this);
5006 Editor::toggle_solo ()
5008 bool new_state = false;
5010 boost::shared_ptr<RouteList> rl (new RouteList);
5012 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5013 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5020 new_state = !rtav->route()->soloed ();
5024 rl->push_back (rtav->route());
5027 _session->set_solo (rl, new_state, Session::rt_cleanup, true);
5031 Editor::toggle_mute ()
5033 bool new_state = false;
5035 boost::shared_ptr<RouteList> rl (new RouteList);
5037 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5038 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5045 new_state = !rtav->route()->muted();
5049 rl->push_back (rtav->route());
5052 _session->set_mute (rl, new_state, Session::rt_cleanup, true);
5056 Editor::toggle_solo_isolate ()
5061 Editor::set_fade_length (bool in)
5063 RegionSelection rs = get_regions_from_selection_and_entered ();
5069 /* we need a region to measure the offset from the start */
5071 RegionView* rv = rs.front ();
5073 framepos_t pos = get_preferred_edit_position();
5077 if (pos > rv->region()->last_frame() || pos < rv->region()->first_frame()) {
5078 /* edit point is outside the relevant region */
5083 if (pos <= rv->region()->position()) {
5087 len = pos - rv->region()->position();
5088 cmd = _("set fade in length");
5090 if (pos >= rv->region()->last_frame()) {
5094 len = rv->region()->last_frame() - pos;
5095 cmd = _("set fade out length");
5098 begin_reversible_command (cmd);
5100 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5101 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5107 boost::shared_ptr<AutomationList> alist;
5109 alist = tmp->audio_region()->fade_in();
5111 alist = tmp->audio_region()->fade_out();
5114 XMLNode &before = alist->get_state();
5117 tmp->audio_region()->set_fade_in_length (len);
5118 tmp->audio_region()->set_fade_in_active (true);
5120 tmp->audio_region()->set_fade_out_length (len);
5121 tmp->audio_region()->set_fade_out_active (true);
5124 XMLNode &after = alist->get_state();
5125 _session->add_command(new MementoCommand<AutomationList>(*alist, &before, &after));
5128 commit_reversible_command ();
5132 Editor::set_fade_in_shape (FadeShape shape)
5134 RegionSelection rs = get_regions_from_selection_and_entered ();
5140 begin_reversible_command (_("set fade in shape"));
5142 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5143 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5149 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_in();
5150 XMLNode &before = alist->get_state();
5152 tmp->audio_region()->set_fade_in_shape (shape);
5154 XMLNode &after = alist->get_state();
5155 _session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
5158 commit_reversible_command ();
5163 Editor::set_fade_out_shape (FadeShape shape)
5165 RegionSelection rs = get_regions_from_selection_and_entered ();
5171 begin_reversible_command (_("set fade out shape"));
5173 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5174 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5180 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_out();
5181 XMLNode &before = alist->get_state();
5183 tmp->audio_region()->set_fade_out_shape (shape);
5185 XMLNode &after = alist->get_state();
5186 _session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
5189 commit_reversible_command ();
5193 Editor::set_fade_in_active (bool yn)
5195 RegionSelection rs = get_regions_from_selection_and_entered ();
5201 begin_reversible_command (_("set fade in active"));
5203 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5204 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5211 boost::shared_ptr<AudioRegion> ar (tmp->audio_region());
5213 ar->clear_changes ();
5214 ar->set_fade_in_active (yn);
5215 _session->add_command (new StatefulDiffCommand (ar));
5218 commit_reversible_command ();
5222 Editor::set_fade_out_active (bool yn)
5224 RegionSelection rs = get_regions_from_selection_and_entered ();
5230 begin_reversible_command (_("set fade out active"));
5232 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5233 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5239 boost::shared_ptr<AudioRegion> ar (tmp->audio_region());
5241 ar->clear_changes ();
5242 ar->set_fade_out_active (yn);
5243 _session->add_command(new StatefulDiffCommand (ar));
5246 commit_reversible_command ();
5250 Editor::toggle_region_fades (int dir)
5252 boost::shared_ptr<AudioRegion> ar;
5255 RegionSelection rs = get_regions_from_selection_and_entered ();
5261 RegionSelection::iterator i;
5262 for (i = rs.begin(); i != rs.end(); ++i) {
5263 if ((ar = boost::dynamic_pointer_cast<AudioRegion>((*i)->region())) != 0) {
5265 yn = ar->fade_out_active ();
5267 yn = ar->fade_in_active ();
5273 if (i == rs.end()) {
5277 /* XXX should this undo-able? */
5279 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5280 if ((ar = boost::dynamic_pointer_cast<AudioRegion>((*i)->region())) == 0) {
5283 if (dir == 1 || dir == 0) {
5284 ar->set_fade_in_active (!yn);
5287 if (dir == -1 || dir == 0) {
5288 ar->set_fade_out_active (!yn);
5294 /** Update region fade visibility after its configuration has been changed */
5296 Editor::update_region_fade_visibility ()
5298 bool _fade_visibility = _session->config.get_show_region_fades ();
5300 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5301 AudioTimeAxisView* v = dynamic_cast<AudioTimeAxisView*>(*i);
5303 if (_fade_visibility) {
5304 v->audio_view()->show_all_fades ();
5306 v->audio_view()->hide_all_fades ();
5313 Editor::set_edit_point ()
5318 if (!mouse_frame (where, ignored)) {
5324 if (selection->markers.empty()) {
5326 mouse_add_new_marker (where);
5331 Location* loc = find_location_from_marker (selection->markers.front(), ignored);
5334 loc->move_to (where);
5340 Editor::set_playhead_cursor ()
5342 if (entered_marker) {
5343 _session->request_locate (entered_marker->position(), _session->transport_rolling());
5348 if (!mouse_frame (where, ignored)) {
5355 _session->request_locate (where, _session->transport_rolling());
5361 Editor::split_region ()
5363 if (((mouse_mode == MouseRange) ||
5364 (mouse_mode != MouseObject && _join_object_range_state == JOIN_OBJECT_RANGE_RANGE)) &&
5365 !selection->time.empty()) {
5366 separate_regions_between (selection->time);
5370 RegionSelection rs = get_regions_from_selection_and_edit_point ();
5372 framepos_t where = get_preferred_edit_position ();
5378 split_regions_at (where, rs);
5382 Editor::ensure_entered_track_selected (bool op_really_wants_one_track_if_none_are_selected)
5384 if (entered_track && mouse_mode == MouseObject) {
5385 if (!selection->tracks.empty()) {
5386 if (!selection->selected (entered_track)) {
5387 selection->add (entered_track);
5390 /* there is no selection, but this operation requires/prefers selected objects */
5392 if (op_really_wants_one_track_if_none_are_selected) {
5393 selection->set (entered_track);
5399 struct EditorOrderRouteSorter {
5400 bool operator() (boost::shared_ptr<Route> a, boost::shared_ptr<Route> b) {
5401 /* use of ">" forces the correct sort order */
5402 return a->order_key ("editor") < b->order_key ("editor");
5407 Editor::select_next_route()
5409 if (selection->tracks.empty()) {
5410 selection->set (track_views.front());
5414 TimeAxisView* current = selection->tracks.front();
5418 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5419 if (*i == current) {
5421 if (i != track_views.end()) {
5424 current = (*(track_views.begin()));
5425 //selection->set (*(track_views.begin()));
5430 rui = dynamic_cast<RouteUI *>(current);
5431 } while ( current->hidden() || (rui != NULL && !rui->route()->active()));
5433 selection->set(current);
5435 ensure_track_visible(current);
5439 Editor::select_prev_route()
5441 if (selection->tracks.empty()) {
5442 selection->set (track_views.front());
5446 TimeAxisView* current = selection->tracks.front();
5450 for (TrackViewList::reverse_iterator i = track_views.rbegin(); i != track_views.rend(); ++i) {
5451 if (*i == current) {
5453 if (i != track_views.rend()) {
5456 current = *(track_views.rbegin());
5461 rui = dynamic_cast<RouteUI *>(current);
5462 } while ( current->hidden() || (rui != NULL && !rui->route()->active()));
5464 selection->set (current);
5466 ensure_track_visible(current);
5470 Editor::ensure_track_visible(TimeAxisView *track)
5472 if (track->hidden())
5475 double const current_view_min_y = vertical_adjustment.get_value();
5476 double const current_view_max_y = vertical_adjustment.get_value() + vertical_adjustment.get_page_size() - canvas_timebars_vsize;
5478 double const track_min_y = track->y_position ();
5479 double const track_max_y = track->y_position () + track->effective_height ();
5481 if (track_min_y >= current_view_min_y &&
5482 track_max_y <= current_view_max_y) {
5488 if (track_min_y < current_view_min_y) {
5489 // Track is above the current view
5490 new_value = track_min_y;
5492 // Track is below the current view
5493 new_value = track->y_position () + track->effective_height() + canvas_timebars_vsize - vertical_adjustment.get_page_size();
5496 vertical_adjustment.set_value(new_value);
5500 Editor::set_loop_from_selection (bool play)
5502 if (_session == 0 || selection->time.empty()) {
5506 framepos_t start = selection->time[clicked_selection].start;
5507 framepos_t end = selection->time[clicked_selection].end;
5509 set_loop_range (start, end, _("set loop range from selection"));
5512 _session->request_play_loop (true);
5513 _session->request_locate (start, true);
5518 Editor::set_loop_from_edit_range (bool play)
5520 if (_session == 0) {
5527 if (!get_edit_op_range (start, end)) {
5531 set_loop_range (start, end, _("set loop range from edit range"));
5534 _session->request_play_loop (true);
5535 _session->request_locate (start, true);
5540 Editor::set_loop_from_region (bool play)
5542 framepos_t start = max_framepos;
5545 RegionSelection rs = get_regions_from_selection_and_entered ();
5551 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5552 if ((*i)->region()->position() < start) {
5553 start = (*i)->region()->position();
5555 if ((*i)->region()->last_frame() + 1 > end) {
5556 end = (*i)->region()->last_frame() + 1;
5560 set_loop_range (start, end, _("set loop range from region"));
5563 _session->request_play_loop (true);
5564 _session->request_locate (start, true);
5569 Editor::set_punch_from_selection ()
5571 if (_session == 0 || selection->time.empty()) {
5575 framepos_t start = selection->time[clicked_selection].start;
5576 framepos_t end = selection->time[clicked_selection].end;
5578 set_punch_range (start, end, _("set punch range from selection"));
5582 Editor::set_punch_from_edit_range ()
5584 if (_session == 0) {
5591 if (!get_edit_op_range (start, end)) {
5595 set_punch_range (start, end, _("set punch range from edit range"));
5599 Editor::set_punch_from_region ()
5601 framepos_t start = max_framepos;
5604 RegionSelection rs = get_regions_from_selection_and_entered ();
5610 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5611 if ((*i)->region()->position() < start) {
5612 start = (*i)->region()->position();
5614 if ((*i)->region()->last_frame() + 1 > end) {
5615 end = (*i)->region()->last_frame() + 1;
5619 set_punch_range (start, end, _("set punch range from region"));
5623 Editor::pitch_shift_region ()
5625 RegionSelection rs = get_regions_from_selection_and_entered ();
5627 RegionSelection audio_rs;
5628 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5629 if (dynamic_cast<AudioRegionView*> (*i)) {
5630 audio_rs.push_back (*i);
5634 if (audio_rs.empty()) {
5638 pitch_shift (audio_rs, 1.2);
5642 Editor::transpose_region ()
5644 RegionSelection rs = get_regions_from_selection_and_entered ();
5646 list<MidiRegionView*> midi_region_views;
5647 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5648 MidiRegionView* mrv = dynamic_cast<MidiRegionView*> (*i);
5650 midi_region_views.push_back (mrv);
5655 int const r = d.run ();
5656 if (r != RESPONSE_ACCEPT) {
5660 for (list<MidiRegionView*>::iterator i = midi_region_views.begin(); i != midi_region_views.end(); ++i) {
5661 (*i)->midi_region()->transpose (d.semitones ());
5666 Editor::set_tempo_from_region ()
5668 RegionSelection rs = get_regions_from_selection_and_entered ();
5670 if (!_session || rs.empty()) {
5674 RegionView* rv = rs.front();
5676 define_one_bar (rv->region()->position(), rv->region()->last_frame() + 1);
5680 Editor::use_range_as_bar ()
5682 framepos_t start, end;
5683 if (get_edit_op_range (start, end)) {
5684 define_one_bar (start, end);
5689 Editor::define_one_bar (framepos_t start, framepos_t end)
5691 framepos_t length = end - start;
5693 const Meter& m (_session->tempo_map().meter_at (start));
5695 /* length = 1 bar */
5697 /* now we want frames per beat.
5698 we have frames per bar, and beats per bar, so ...
5701 /* XXXX METER MATH */
5703 double frames_per_beat = length / m.divisions_per_bar();
5705 /* beats per minute = */
5707 double beats_per_minute = (_session->frame_rate() * 60.0) / frames_per_beat;
5709 /* now decide whether to:
5711 (a) set global tempo
5712 (b) add a new tempo marker
5716 const TempoSection& t (_session->tempo_map().tempo_section_at (start));
5718 bool do_global = false;
5720 if ((_session->tempo_map().n_tempos() == 1) && (_session->tempo_map().n_meters() == 1)) {
5722 /* only 1 tempo & 1 meter: ask if the user wants to set the tempo
5723 at the start, or create a new marker
5726 vector<string> options;
5727 options.push_back (_("Cancel"));
5728 options.push_back (_("Add new marker"));
5729 options.push_back (_("Set global tempo"));
5732 _("Define one bar"),
5733 _("Do you want to set the global tempo or add a new tempo marker?"),
5737 c.set_default_response (2);
5753 /* more than 1 tempo and/or meter section already, go ahead do the "usual":
5754 if the marker is at the region starter, change it, otherwise add
5759 begin_reversible_command (_("set tempo from region"));
5760 XMLNode& before (_session->tempo_map().get_state());
5763 _session->tempo_map().change_initial_tempo (beats_per_minute, t.note_type());
5764 } else if (t.frame() == start) {
5765 _session->tempo_map().change_existing_tempo_at (start, beats_per_minute, t.note_type());
5767 _session->tempo_map().add_tempo (Tempo (beats_per_minute, t.note_type()), start);
5770 XMLNode& after (_session->tempo_map().get_state());
5772 _session->add_command (new MementoCommand<TempoMap>(_session->tempo_map(), &before, &after));
5773 commit_reversible_command ();
5777 Editor::split_region_at_transients ()
5779 AnalysisFeatureList positions;
5781 RegionSelection rs = get_regions_from_selection_and_entered ();
5783 if (!_session || rs.empty()) {
5787 _session->begin_reversible_command (_("split regions"));
5789 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ) {
5791 RegionSelection::iterator tmp;
5796 boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion> ((*i)->region());
5798 if (ar && (ar->get_transients (positions) == 0)) {
5799 split_region_at_points ((*i)->region(), positions, true);
5806 _session->commit_reversible_command ();
5811 Editor::split_region_at_points (boost::shared_ptr<Region> r, AnalysisFeatureList& positions, bool can_ferret, bool select_new)
5813 bool use_rhythmic_rodent = false;
5815 boost::shared_ptr<Playlist> pl = r->playlist();
5817 list<boost::shared_ptr<Region> > new_regions;
5823 if (positions.empty()) {
5828 if (positions.size() > 20 && can_ferret) {
5829 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);
5830 MessageDialog msg (msgstr,
5833 Gtk::BUTTONS_OK_CANCEL);
5836 msg.add_button (_("Call for the Ferret!"), RESPONSE_APPLY);
5837 msg.set_secondary_text (_("Press OK to continue with this split operation\nor ask the Ferret dialog to tune the analysis"));
5839 msg.set_secondary_text (_("Press OK to continue with this split operation"));
5842 msg.set_title (_("Excessive split?"));
5845 int response = msg.run();
5851 case RESPONSE_APPLY:
5852 use_rhythmic_rodent = true;
5859 if (use_rhythmic_rodent) {
5860 show_rhythm_ferret ();
5864 AnalysisFeatureList::const_iterator x;
5866 pl->clear_changes ();
5867 pl->clear_owned_changes ();
5869 x = positions.begin();
5871 if (x == positions.end()) {
5876 pl->remove_region (r);
5880 while (x != positions.end()) {
5882 /* deal with positons that are out of scope of present region bounds */
5883 if (*x <= 0 || *x > r->length()) {
5888 /* file start = original start + how far we from the initial position ?
5891 framepos_t file_start = r->start() + pos;
5893 /* length = next position - current position
5896 framepos_t len = (*x) - pos;
5898 /* XXX we do we really want to allow even single-sample regions?
5899 shouldn't we have some kind of lower limit on region size?
5908 if (RegionFactory::region_name (new_name, r->name())) {
5912 /* do NOT announce new regions 1 by one, just wait till they are all done */
5916 plist.add (ARDOUR::Properties::start, file_start);
5917 plist.add (ARDOUR::Properties::length, len);
5918 plist.add (ARDOUR::Properties::name, new_name);
5919 plist.add (ARDOUR::Properties::layer, 0);
5921 boost::shared_ptr<Region> nr = RegionFactory::create (r->sources(), plist, false);
5923 pl->add_region (nr, r->position() + pos);
5926 new_regions.push_front(nr);
5935 RegionFactory::region_name (new_name, r->name());
5937 /* Add the final region */
5940 plist.add (ARDOUR::Properties::start, r->start() + pos);
5941 plist.add (ARDOUR::Properties::length, r->last_frame() - (r->position() + pos) + 1);
5942 plist.add (ARDOUR::Properties::name, new_name);
5943 plist.add (ARDOUR::Properties::layer, 0);
5945 boost::shared_ptr<Region> nr = RegionFactory::create (r->sources(), plist, false);
5946 pl->add_region (nr, r->position() + pos);
5949 new_regions.push_front(nr);
5954 /* We might have removed regions, which alters other regions' layering_index,
5955 so we need to do a recursive diff here.
5957 vector<Command*> cmds;
5959 _session->add_commands (cmds);
5961 _session->add_command (new StatefulDiffCommand (pl));
5965 for (list<boost::shared_ptr<Region> >::iterator i = new_regions.begin(); i != new_regions.end(); ++i){
5966 set_selected_regionview_from_region_list ((*i), Selection::Add);
5972 Editor::place_transient()
5978 RegionSelection rs = get_regions_from_selection_and_edit_point ();
5984 framepos_t where = get_preferred_edit_position();
5986 _session->begin_reversible_command (_("place transient"));
5988 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
5989 framepos_t position = (*r)->region()->position();
5990 (*r)->region()->add_transient(where - position);
5993 _session->commit_reversible_command ();
5997 Editor::remove_transient(ArdourCanvas::Item* item)
6003 ArdourCanvas::Line* _line = reinterpret_cast<ArdourCanvas::Line*> (item);
6006 AudioRegionView* _arv = reinterpret_cast<AudioRegionView*> (item->get_data ("regionview"));
6007 _arv->remove_transient (*(float*) _line->get_data ("position"));
6011 Editor::snap_regions_to_grid ()
6013 list <boost::shared_ptr<Playlist > > used_playlists;
6015 RegionSelection rs = get_regions_from_selection_and_entered ();
6017 if (!_session || rs.empty()) {
6021 _session->begin_reversible_command (_("snap regions to grid"));
6023 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6025 boost::shared_ptr<Playlist> pl = (*r)->region()->playlist();
6027 if (!pl->frozen()) {
6028 /* we haven't seen this playlist before */
6030 /* remember used playlists so we can thaw them later */
6031 used_playlists.push_back(pl);
6035 framepos_t start_frame = (*r)->region()->first_frame ();
6036 snap_to (start_frame);
6037 (*r)->region()->set_position (start_frame);
6040 while (used_playlists.size() > 0) {
6041 list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
6043 used_playlists.pop_front();
6046 _session->commit_reversible_command ();
6050 Editor::close_region_gaps ()
6052 list <boost::shared_ptr<Playlist > > used_playlists;
6054 RegionSelection rs = get_regions_from_selection_and_entered ();
6056 if (!_session || rs.empty()) {
6060 Dialog dialog (_("Close Region Gaps"));
6063 table.set_spacings (12);
6064 table.set_border_width (12);
6065 Label* l = manage (new Label (_("Crossfade length")));
6066 l->set_alignment (0, 0.5);
6067 table.attach (*l, 0, 1, 0, 1);
6069 SpinButton spin_crossfade (1, 0);
6070 spin_crossfade.set_range (0, 15);
6071 spin_crossfade.set_increments (1, 1);
6072 spin_crossfade.set_value (5);
6073 table.attach (spin_crossfade, 1, 2, 0, 1);
6075 table.attach (*manage (new Label (_("ms"))), 2, 3, 0, 1);
6077 l = manage (new Label (_("Pull-back length")));
6078 l->set_alignment (0, 0.5);
6079 table.attach (*l, 0, 1, 1, 2);
6081 SpinButton spin_pullback (1, 0);
6082 spin_pullback.set_range (0, 100);
6083 spin_pullback.set_increments (1, 1);
6084 spin_pullback.set_value(30);
6085 table.attach (spin_pullback, 1, 2, 1, 2);
6087 table.attach (*manage (new Label (_("ms"))), 2, 3, 1, 2);
6089 dialog.get_vbox()->pack_start (table);
6090 dialog.add_button (Stock::CANCEL, RESPONSE_CANCEL);
6091 dialog.add_button (_("Ok"), RESPONSE_ACCEPT);
6094 if (dialog.run () == RESPONSE_CANCEL) {
6098 framepos_t crossfade_len = spin_crossfade.get_value();
6099 framepos_t pull_back_frames = spin_pullback.get_value();
6101 crossfade_len = lrintf (crossfade_len * _session->frame_rate()/1000);
6102 pull_back_frames = lrintf (pull_back_frames * _session->frame_rate()/1000);
6104 /* Iterate over the region list and make adjacent regions overlap by crossfade_len_ms */
6106 _session->begin_reversible_command (_("close region gaps"));
6109 boost::shared_ptr<Region> last_region;
6111 rs.sort_by_position_and_track();
6113 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6115 boost::shared_ptr<Playlist> pl = (*r)->region()->playlist();
6117 if (!pl->frozen()) {
6118 /* we haven't seen this playlist before */
6120 /* remember used playlists so we can thaw them later */
6121 used_playlists.push_back(pl);
6125 framepos_t position = (*r)->region()->position();
6127 if (idx == 0 || position < last_region->position()){
6128 last_region = (*r)->region();
6133 (*r)->region()->trim_front( (position - pull_back_frames));
6134 last_region->trim_end( (position - pull_back_frames + crossfade_len));
6136 last_region = (*r)->region();
6141 while (used_playlists.size() > 0) {
6142 list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
6144 used_playlists.pop_front();
6147 _session->commit_reversible_command ();
6151 Editor::tab_to_transient (bool forward)
6153 AnalysisFeatureList positions;
6155 RegionSelection rs = get_regions_from_selection_and_entered ();
6161 framepos_t pos = _session->audible_frame ();
6163 if (!selection->tracks.empty()) {
6165 /* don't waste time searching for transients in duplicate playlists.
6168 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
6170 for (TrackViewList::iterator t = ts.begin(); t != ts.end(); ++t) {
6172 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*t);
6175 boost::shared_ptr<Track> tr = rtv->track();
6177 boost::shared_ptr<Playlist> pl = tr->playlist ();
6179 framepos_t result = pl->find_next_transient (pos, forward ? 1 : -1);
6182 positions.push_back (result);
6195 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6196 (*r)->region()->get_transients (positions);
6200 TransientDetector::cleanup_transients (positions, _session->frame_rate(), 3.0);
6203 AnalysisFeatureList::iterator x;
6205 for (x = positions.begin(); x != positions.end(); ++x) {
6211 if (x != positions.end ()) {
6212 _session->request_locate (*x);
6216 AnalysisFeatureList::reverse_iterator x;
6218 for (x = positions.rbegin(); x != positions.rend(); ++x) {
6224 if (x != positions.rend ()) {
6225 _session->request_locate (*x);
6231 Editor::playhead_forward_to_grid ()
6233 if (!_session) return;
6234 framepos_t pos = playhead_cursor->current_frame;
6235 if (pos < max_framepos - 1) {
6237 snap_to_internal (pos, 1, false);
6238 _session->request_locate (pos);
6244 Editor::playhead_backward_to_grid ()
6246 if (!_session) return;
6247 framepos_t pos = playhead_cursor->current_frame;
6250 snap_to_internal (pos, -1, false);
6251 _session->request_locate (pos);
6256 Editor::set_track_height (Height h)
6258 TrackSelection& ts (selection->tracks);
6260 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
6261 (*x)->set_height_enum (h);
6266 Editor::toggle_tracks_active ()
6268 TrackSelection& ts (selection->tracks);
6270 bool target = false;
6276 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
6277 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*x);
6281 target = !rtv->_route->active();
6284 rtv->_route->set_active (target, this);
6290 Editor::remove_tracks ()
6292 TrackSelection& ts (selection->tracks);
6298 vector<string> choices;
6302 const char* trackstr;
6304 vector<boost::shared_ptr<Route> > routes;
6305 bool special_bus = false;
6307 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
6308 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*x);
6310 if (rtv->is_track()) {
6316 routes.push_back (rtv->_route);
6318 if (rtv->route()->is_master() || rtv->route()->is_monitor()) {
6323 if (special_bus && !Config->get_allow_special_bus_removal()) {
6324 MessageDialog msg (_("That would be bad news ...."),
6328 msg.set_secondary_text (string_compose (_(
6329 "Removing the master or monitor bus is such a bad idea\n\
6330 that %1 is not going to allow it.\n\
6332 If you really want to do this sort of thing\n\
6333 edit your ardour.rc file to set the\n\
6334 \"allow-special-bus-removal\" option to be \"yes\""), PROGRAM_NAME));
6341 if (ntracks + nbusses == 0) {
6346 trackstr = _("tracks");
6348 trackstr = _("track");
6352 busstr = _("busses");
6359 prompt = string_compose (_("Do you really want to remove %1 %2 and %3 %4?\n"
6360 "(You may also lose the playlists associated with the %2)\n\n"
6361 "This action cannot be undone, and the session file will be overwritten!"),
6362 ntracks, trackstr, nbusses, busstr);
6364 prompt = string_compose (_("Do you really want to remove %1 %2?\n"
6365 "(You may also lose the playlists associated with the %2)\n\n"
6366 "This action cannot be undone, and the session file will be overwritten!"),
6369 } else if (nbusses) {
6370 prompt = string_compose (_("Do you really want to remove %1 %2?\n\n"
6371 "This action cannot be undon, and the session file will be overwritten"),
6375 choices.push_back (_("No, do nothing."));
6376 if (ntracks + nbusses > 1) {
6377 choices.push_back (_("Yes, remove them."));
6379 choices.push_back (_("Yes, remove it."));
6384 title = string_compose (_("Remove %1"), trackstr);
6386 title = string_compose (_("Remove %1"), busstr);
6389 Choice prompter (title, prompt, choices);
6391 if (prompter.run () != 1) {
6395 for (vector<boost::shared_ptr<Route> >::iterator x = routes.begin(); x != routes.end(); ++x) {
6396 _session->remove_route (*x);
6401 Editor::do_insert_time ()
6403 if (selection->tracks.empty()) {
6407 InsertTimeDialog d (*this);
6408 int response = d.run ();
6410 if (response != RESPONSE_OK) {
6414 if (d.distance() == 0) {
6418 InsertTimeOption opt = d.intersected_region_action ();
6421 get_preferred_edit_position(),
6427 d.move_glued_markers(),
6428 d.move_locked_markers(),
6434 Editor::insert_time (
6435 framepos_t pos, framecnt_t frames, InsertTimeOption opt,
6436 bool all_playlists, bool ignore_music_glue, bool markers_too, bool glued_markers_too, bool locked_markers_too, bool tempo_too
6439 bool commit = false;
6441 if (Config->get_edit_mode() == Lock) {
6445 begin_reversible_command (_("insert time"));
6447 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
6449 for (TrackViewList::iterator x = ts.begin(); x != ts.end(); ++x) {
6453 /* don't operate on any playlist more than once, which could
6454 * happen if "all playlists" is enabled, but there is more
6455 * than 1 track using playlists "from" a given track.
6458 set<boost::shared_ptr<Playlist> > pl;
6460 if (all_playlists) {
6461 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*x);
6463 vector<boost::shared_ptr<Playlist> > all = _session->playlists->playlists_for_track (rtav->track ());
6464 for (vector<boost::shared_ptr<Playlist> >::iterator p = all.begin(); p != all.end(); ++p) {
6469 if ((*x)->playlist ()) {
6470 pl.insert ((*x)->playlist ());
6474 for (set<boost::shared_ptr<Playlist> >::iterator i = pl.begin(); i != pl.end(); ++i) {
6476 (*i)->clear_changes ();
6477 (*i)->clear_owned_changes ();
6479 if (opt == SplitIntersected) {
6483 (*i)->shift (pos, frames, (opt == MoveIntersected), ignore_music_glue);
6485 vector<Command*> cmds;
6487 _session->add_commands (cmds);
6489 _session->add_command (new StatefulDiffCommand (*i));
6494 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*x);
6496 rtav->route ()->shift (pos, frames);
6504 XMLNode& before (_session->locations()->get_state());
6505 Locations::LocationList copy (_session->locations()->list());
6507 for (Locations::LocationList::iterator i = copy.begin(); i != copy.end(); ++i) {
6509 Locations::LocationList::const_iterator tmp;
6511 bool const was_locked = (*i)->locked ();
6512 if (locked_markers_too) {
6516 if ((*i)->position_lock_style() == AudioTime || glued_markers_too) {
6518 if ((*i)->start() >= pos) {
6519 (*i)->set_start ((*i)->start() + frames);
6520 if (!(*i)->is_mark()) {
6521 (*i)->set_end ((*i)->end() + frames);
6534 XMLNode& after (_session->locations()->get_state());
6535 _session->add_command (new MementoCommand<Locations>(*_session->locations(), &before, &after));
6540 _session->tempo_map().insert_time (pos, frames);
6544 commit_reversible_command ();
6549 Editor::fit_selected_tracks ()
6551 if (!selection->tracks.empty()) {
6552 fit_tracks (selection->tracks);
6556 /* no selected tracks - use tracks with selected regions */
6558 if (!selection->regions.empty()) {
6559 for (RegionSelection::iterator r = selection->regions.begin(); r != selection->regions.end(); ++r) {
6560 tvl.push_back (&(*r)->get_time_axis_view ());
6566 } else if (internal_editing()) {
6567 /* no selected tracks, or regions, but in internal edit mode, so follow the mouse and use
6570 if (entered_track) {
6571 tvl.push_back (entered_track);
6579 Editor::fit_tracks (TrackViewList & tracks)
6581 if (tracks.empty()) {
6585 uint32_t child_heights = 0;
6586 int visible_tracks = 0;
6588 for (TrackSelection::iterator t = tracks.begin(); t != tracks.end(); ++t) {
6590 if (!(*t)->marked_for_display()) {
6594 child_heights += (*t)->effective_height() - (*t)->current_height();
6598 uint32_t h = (uint32_t) floor ((_canvas_height - child_heights - canvas_timebars_vsize) / visible_tracks);
6599 double first_y_pos = DBL_MAX;
6601 if (h < TimeAxisView::preset_height (HeightSmall)) {
6602 MessageDialog msg (*this, _("There are too many tracks to fit in the current window"));
6603 /* too small to be displayed */
6607 undo_visual_stack.push_back (current_visual_state (true));
6608 no_save_visual = true;
6610 /* build a list of all tracks, including children */
6613 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
6615 TimeAxisView::Children c = (*i)->get_child_list ();
6616 for (TimeAxisView::Children::iterator j = c.begin(); j != c.end(); ++j) {
6617 all.push_back (j->get());
6621 /* operate on all tracks, hide unselected ones that are in the middle of selected ones */
6623 bool prev_was_selected = false;
6624 bool is_selected = tracks.contains (all.front());
6625 bool next_is_selected;
6627 for (TrackViewList::iterator t = all.begin(); t != all.end(); ++t) {
6629 TrackViewList::iterator next;
6634 if (next != all.end()) {
6635 next_is_selected = tracks.contains (*next);
6637 next_is_selected = false;
6640 if ((*t)->marked_for_display ()) {
6642 (*t)->set_height (h);
6643 first_y_pos = std::min ((*t)->y_position (), first_y_pos);
6645 if (prev_was_selected && next_is_selected) {
6646 hide_track_in_display (*t);
6651 prev_was_selected = is_selected;
6652 is_selected = next_is_selected;
6656 set the controls_layout height now, because waiting for its size
6657 request signal handler will cause the vertical adjustment setting to fail
6660 controls_layout.property_height () = full_canvas_height - canvas_timebars_vsize;
6661 vertical_adjustment.set_value (first_y_pos);
6663 redo_visual_stack.push_back (current_visual_state (true));
6667 Editor::save_visual_state (uint32_t n)
6669 while (visual_states.size() <= n) {
6670 visual_states.push_back (0);
6673 if (visual_states[n] != 0) {
6674 delete visual_states[n];
6677 visual_states[n] = current_visual_state (true);
6682 Editor::goto_visual_state (uint32_t n)
6684 if (visual_states.size() <= n) {
6688 if (visual_states[n] == 0) {
6692 use_visual_state (*visual_states[n]);
6696 Editor::start_visual_state_op (uint32_t n)
6698 save_visual_state (n);
6700 PopUp* pup = new PopUp (WIN_POS_MOUSE, 1000, true);
6702 snprintf (buf, sizeof (buf), _("Saved view %u"), n+1);
6703 pup->set_text (buf);
6708 Editor::cancel_visual_state_op (uint32_t n)
6710 goto_visual_state (n);
6714 Editor::toggle_region_mute ()
6716 if (_ignore_region_action) {
6720 RegionSelection rs = get_regions_from_selection_and_entered ();
6726 if (rs.size() > 1) {
6727 begin_reversible_command (_("mute regions"));
6729 begin_reversible_command (_("mute region"));
6732 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
6734 (*i)->region()->playlist()->clear_changes ();
6735 (*i)->region()->set_muted (!(*i)->region()->muted ());
6736 _session->add_command (new StatefulDiffCommand ((*i)->region()->playlist()));
6740 commit_reversible_command ();
6744 Editor::combine_regions ()
6746 /* foreach track with selected regions, take all selected regions
6747 and join them into a new region containing the subregions (as a
6751 typedef set<RouteTimeAxisView*> RTVS;
6754 if (selection->regions.empty()) {
6758 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
6759 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(&(*i)->get_time_axis_view());
6762 tracks.insert (rtv);
6766 begin_reversible_command (_("combine regions"));
6768 vector<RegionView*> new_selection;
6770 for (RTVS::iterator i = tracks.begin(); i != tracks.end(); ++i) {
6773 if ((rv = (*i)->combine_regions ()) != 0) {
6774 new_selection.push_back (rv);
6778 selection->clear_regions ();
6779 for (vector<RegionView*>::iterator i = new_selection.begin(); i != new_selection.end(); ++i) {
6780 selection->add (*i);
6783 commit_reversible_command ();
6787 Editor::uncombine_regions ()
6789 typedef set<RouteTimeAxisView*> RTVS;
6792 if (selection->regions.empty()) {
6796 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
6797 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(&(*i)->get_time_axis_view());
6800 tracks.insert (rtv);
6804 begin_reversible_command (_("uncombine regions"));
6806 for (RTVS::iterator i = tracks.begin(); i != tracks.end(); ++i) {
6807 (*i)->uncombine_regions ();
6810 commit_reversible_command ();