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/midi_track.h"
48 #include "ardour/operations.h"
49 #include "ardour/playlist_factory.h"
50 #include "ardour/quantize.h"
51 #include "ardour/region_factory.h"
52 #include "ardour/reverse.h"
53 #include "ardour/session.h"
54 #include "ardour/session_playlists.h"
55 #include "ardour/strip_silence.h"
56 #include "ardour/transient_detector.h"
58 #include "canvas/canvas.h"
60 #include "ardour_ui.h"
63 #include "time_axis_view.h"
64 #include "route_time_axis.h"
65 #include "audio_time_axis.h"
66 #include "automation_time_axis.h"
67 #include "control_point.h"
68 #include "streamview.h"
69 #include "audio_streamview.h"
70 #include "audio_region_view.h"
71 #include "midi_region_view.h"
72 #include "rgb_macros.h"
73 #include "selection_templates.h"
74 #include "selection.h"
76 #include "gtk-custom-hruler.h"
77 #include "gui_thread.h"
80 #include "editor_drag.h"
81 #include "strip_silence_dialog.h"
82 #include "editor_routes.h"
83 #include "editor_regions.h"
84 #include "quantize_dialog.h"
85 #include "interthread_progress_window.h"
86 #include "insert_time_dialog.h"
87 #include "normalize_dialog.h"
88 #include "editor_cursors.h"
89 #include "mouse_cursors.h"
90 #include "patch_change_dialog.h"
91 #include "transpose_dialog.h"
96 using namespace ARDOUR;
99 using namespace Gtkmm2ext;
100 using namespace Editing;
101 using Gtkmm2ext::Keyboard;
103 /***********************************************************************
105 ***********************************************************************/
108 Editor::undo (uint32_t n)
110 if (_drags->active ()) {
120 Editor::redo (uint32_t n)
122 if (_drags->active ()) {
132 Editor::split_regions_at (framepos_t where, RegionSelection& regions)
136 list <boost::shared_ptr<Playlist > > used_playlists;
138 if (regions.empty()) {
142 begin_reversible_command (_("split"));
144 // if splitting a single region, and snap-to is using
145 // region boundaries, don't pay attention to them
147 if (regions.size() == 1) {
148 switch (_snap_type) {
149 case SnapToRegionStart:
150 case SnapToRegionSync:
151 case SnapToRegionEnd:
160 EditorFreeze(); /* Emit Signal */
163 for (RegionSelection::iterator a = regions.begin(); a != regions.end(); ) {
165 RegionSelection::iterator tmp;
167 /* XXX this test needs to be more complicated, to make sure we really
168 have something to split.
171 if (!(*a)->region()->covers (where)) {
179 boost::shared_ptr<Playlist> pl = (*a)->region()->playlist();
187 /* we haven't seen this playlist before */
189 /* remember used playlists so we can thaw them later */
190 used_playlists.push_back(pl);
195 pl->clear_changes ();
196 pl->split_region ((*a)->region(), where);
197 _session->add_command (new StatefulDiffCommand (pl));
203 while (used_playlists.size() > 0) {
204 list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
206 used_playlists.pop_front();
209 commit_reversible_command ();
212 EditorThaw(); /* Emit Signal */
216 /** Move one extreme of the current range selection. If more than one range is selected,
217 * the start of the earliest range or the end of the latest range is moved.
219 * @param move_end true to move the end of the current range selection, false to move
221 * @param next true to move the extreme to the next region boundary, false to move to
225 Editor::move_range_selection_start_or_end_to_region_boundary (bool move_end, bool next)
227 if (selection->time.start() == selection->time.end_frame()) {
231 framepos_t start = selection->time.start ();
232 framepos_t end = selection->time.end_frame ();
234 /* the position of the thing we may move */
235 framepos_t pos = move_end ? end : start;
236 int dir = next ? 1 : -1;
238 /* so we don't find the current region again */
239 if (dir > 0 || pos > 0) {
243 framepos_t const target = get_region_boundary (pos, dir, true, false);
258 begin_reversible_command (_("alter selection"));
259 selection->set_preserving_all_ranges (start, end);
260 commit_reversible_command ();
264 Editor::nudge_forward_release (GdkEventButton* ev)
266 if (ev->state & Keyboard::PrimaryModifier) {
267 nudge_forward (false, true);
269 nudge_forward (false, false);
275 Editor::nudge_backward_release (GdkEventButton* ev)
277 if (ev->state & Keyboard::PrimaryModifier) {
278 nudge_backward (false, true);
280 nudge_backward (false, false);
287 Editor::nudge_forward (bool next, bool force_playhead)
290 framepos_t next_distance;
296 RegionSelection rs = get_regions_from_selection_and_entered ();
298 if (!force_playhead && !rs.empty()) {
300 begin_reversible_command (_("nudge regions forward"));
302 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
303 boost::shared_ptr<Region> r ((*i)->region());
305 distance = get_nudge_distance (r->position(), next_distance);
308 distance = next_distance;
312 r->set_position (r->position() + distance);
313 _session->add_command (new StatefulDiffCommand (r));
316 commit_reversible_command ();
319 } else if (!force_playhead && !selection->markers.empty()) {
323 begin_reversible_command (_("nudge location forward"));
325 for (MarkerSelection::iterator i = selection->markers.begin(); i != selection->markers.end(); ++i) {
327 Location* loc = find_location_from_marker ((*i), is_start);
331 XMLNode& before (loc->get_state());
334 distance = get_nudge_distance (loc->start(), next_distance);
336 distance = next_distance;
338 if (max_framepos - distance > loc->start() + loc->length()) {
339 loc->set_start (loc->start() + distance);
341 loc->set_start (max_framepos - loc->length());
344 distance = get_nudge_distance (loc->end(), next_distance);
346 distance = next_distance;
348 if (max_framepos - distance > loc->end()) {
349 loc->set_end (loc->end() + distance);
351 loc->set_end (max_framepos);
354 XMLNode& after (loc->get_state());
355 _session->add_command (new MementoCommand<Location>(*loc, &before, &after));
359 commit_reversible_command ();
362 distance = get_nudge_distance (playhead_cursor->current_frame (), next_distance);
363 _session->request_locate (playhead_cursor->current_frame () + distance);
368 Editor::nudge_backward (bool next, bool force_playhead)
371 framepos_t next_distance;
377 RegionSelection rs = get_regions_from_selection_and_entered ();
379 if (!force_playhead && !rs.empty()) {
381 begin_reversible_command (_("nudge regions backward"));
383 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
384 boost::shared_ptr<Region> r ((*i)->region());
386 distance = get_nudge_distance (r->position(), next_distance);
389 distance = next_distance;
394 if (r->position() > distance) {
395 r->set_position (r->position() - distance);
399 _session->add_command (new StatefulDiffCommand (r));
402 commit_reversible_command ();
404 } else if (!force_playhead && !selection->markers.empty()) {
408 begin_reversible_command (_("nudge location forward"));
410 for (MarkerSelection::iterator i = selection->markers.begin(); i != selection->markers.end(); ++i) {
412 Location* loc = find_location_from_marker ((*i), is_start);
416 XMLNode& before (loc->get_state());
419 distance = get_nudge_distance (loc->start(), next_distance);
421 distance = next_distance;
423 if (distance < loc->start()) {
424 loc->set_start (loc->start() - distance);
429 distance = get_nudge_distance (loc->end(), next_distance);
432 distance = next_distance;
435 if (distance < loc->end() - loc->length()) {
436 loc->set_end (loc->end() - distance);
438 loc->set_end (loc->length());
442 XMLNode& after (loc->get_state());
443 _session->add_command (new MementoCommand<Location>(*loc, &before, &after));
447 commit_reversible_command ();
451 distance = get_nudge_distance (playhead_cursor->current_frame (), next_distance);
453 if (playhead_cursor->current_frame () > distance) {
454 _session->request_locate (playhead_cursor->current_frame () - distance);
456 _session->goto_start();
462 Editor::nudge_forward_capture_offset ()
464 RegionSelection rs = get_regions_from_selection_and_entered ();
466 if (!_session || rs.empty()) {
470 begin_reversible_command (_("nudge forward"));
472 framepos_t const distance = _session->worst_output_latency();
474 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
475 boost::shared_ptr<Region> r ((*i)->region());
478 r->set_position (r->position() + distance);
479 _session->add_command(new StatefulDiffCommand (r));
482 commit_reversible_command ();
486 Editor::nudge_backward_capture_offset ()
488 RegionSelection rs = get_regions_from_selection_and_entered ();
490 if (!_session || rs.empty()) {
494 begin_reversible_command (_("nudge backward"));
496 framepos_t const distance = _session->worst_output_latency();
498 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
499 boost::shared_ptr<Region> r ((*i)->region());
503 if (r->position() > distance) {
504 r->set_position (r->position() - distance);
508 _session->add_command(new StatefulDiffCommand (r));
511 commit_reversible_command ();
517 Editor::move_to_start ()
519 _session->goto_start ();
523 Editor::move_to_end ()
526 _session->request_locate (_session->current_end_frame());
530 Editor::build_region_boundary_cache ()
533 vector<RegionPoint> interesting_points;
534 boost::shared_ptr<Region> r;
535 TrackViewList tracks;
538 region_boundary_cache.clear ();
544 switch (_snap_type) {
545 case SnapToRegionStart:
546 interesting_points.push_back (Start);
548 case SnapToRegionEnd:
549 interesting_points.push_back (End);
551 case SnapToRegionSync:
552 interesting_points.push_back (SyncPoint);
554 case SnapToRegionBoundary:
555 interesting_points.push_back (Start);
556 interesting_points.push_back (End);
559 fatal << string_compose (_("build_region_boundary_cache called with snap_type = %1"), _snap_type) << endmsg;
564 TimeAxisView *ontrack = 0;
567 if (!selection->tracks.empty()) {
568 tlist = selection->tracks.filter_to_unique_playlists ();
570 tlist = track_views.filter_to_unique_playlists ();
573 while (pos < _session->current_end_frame() && !at_end) {
576 framepos_t lpos = max_framepos;
578 for (vector<RegionPoint>::iterator p = interesting_points.begin(); p != interesting_points.end(); ++p) {
580 if ((r = find_next_region (pos, *p, 1, tlist, &ontrack)) == 0) {
581 if (*p == interesting_points.back()) {
584 /* move to next point type */
590 rpos = r->first_frame();
594 rpos = r->last_frame();
598 rpos = r->sync_position ();
606 RouteTimeAxisView *rtav;
608 if (ontrack != 0 && (rtav = dynamic_cast<RouteTimeAxisView*>(ontrack)) != 0 ) {
609 if (rtav->track() != 0) {
610 speed = rtav->track()->speed();
614 rpos = track_frame_to_session_frame (rpos, speed);
620 /* prevent duplicates, but we don't use set<> because we want to be able
624 vector<framepos_t>::iterator ri;
626 for (ri = region_boundary_cache.begin(); ri != region_boundary_cache.end(); ++ri) {
632 if (ri == region_boundary_cache.end()) {
633 region_boundary_cache.push_back (rpos);
640 /* finally sort to be sure that the order is correct */
642 sort (region_boundary_cache.begin(), region_boundary_cache.end());
645 boost::shared_ptr<Region>
646 Editor::find_next_region (framepos_t frame, RegionPoint point, int32_t dir, TrackViewList& tracks, TimeAxisView **ontrack)
648 TrackViewList::iterator i;
649 framepos_t closest = max_framepos;
650 boost::shared_ptr<Region> ret;
654 framepos_t track_frame;
655 RouteTimeAxisView *rtav;
657 for (i = tracks.begin(); i != tracks.end(); ++i) {
660 boost::shared_ptr<Region> r;
663 if ( (rtav = dynamic_cast<RouteTimeAxisView*>(*i)) != 0 ) {
664 if (rtav->track()!=0)
665 track_speed = rtav->track()->speed();
668 track_frame = session_frame_to_track_frame(frame, track_speed);
670 if ((r = (*i)->find_next_region (track_frame, point, dir)) == 0) {
676 rpos = r->first_frame ();
680 rpos = r->last_frame ();
684 rpos = r->sync_position ();
688 // rpos is a "track frame", converting it to "_session frame"
689 rpos = track_frame_to_session_frame(rpos, track_speed);
692 distance = rpos - frame;
694 distance = frame - rpos;
697 if (distance < closest) {
709 Editor::find_next_region_boundary (framepos_t pos, int32_t dir, const TrackViewList& tracks)
711 framecnt_t distance = max_framepos;
712 framepos_t current_nearest = -1;
714 for (TrackViewList::const_iterator i = tracks.begin(); i != tracks.end(); ++i) {
715 framepos_t contender;
718 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*i);
724 if ((contender = rtv->find_next_region_boundary (pos, dir)) < 0) {
728 d = ::llabs (pos - contender);
731 current_nearest = contender;
736 return current_nearest;
740 Editor::get_region_boundary (framepos_t pos, int32_t dir, bool with_selection, bool only_onscreen)
745 if (with_selection && Config->get_region_boundaries_from_selected_tracks()) {
747 if (!selection->tracks.empty()) {
749 target = find_next_region_boundary (pos, dir, selection->tracks);
753 if (only_onscreen || Config->get_region_boundaries_from_onscreen_tracks()) {
754 get_onscreen_tracks (tvl);
755 target = find_next_region_boundary (pos, dir, tvl);
757 target = find_next_region_boundary (pos, dir, track_views);
763 if (only_onscreen || Config->get_region_boundaries_from_onscreen_tracks()) {
764 get_onscreen_tracks (tvl);
765 target = find_next_region_boundary (pos, dir, tvl);
767 target = find_next_region_boundary (pos, dir, track_views);
775 Editor::cursor_to_region_boundary (bool with_selection, int32_t dir)
777 framepos_t pos = playhead_cursor->current_frame ();
784 // so we don't find the current region again..
785 if (dir > 0 || pos > 0) {
789 if ((target = get_region_boundary (pos, dir, with_selection, false)) < 0) {
793 _session->request_locate (target);
797 Editor::cursor_to_next_region_boundary (bool with_selection)
799 cursor_to_region_boundary (with_selection, 1);
803 Editor::cursor_to_previous_region_boundary (bool with_selection)
805 cursor_to_region_boundary (with_selection, -1);
809 Editor::cursor_to_region_point (EditorCursor* cursor, RegionPoint point, int32_t dir)
811 boost::shared_ptr<Region> r;
812 framepos_t pos = cursor->current_frame ();
818 TimeAxisView *ontrack = 0;
820 // so we don't find the current region again..
824 if (!selection->tracks.empty()) {
826 r = find_next_region (pos, point, dir, selection->tracks, &ontrack);
828 } else if (clicked_axisview) {
831 t.push_back (clicked_axisview);
833 r = find_next_region (pos, point, dir, t, &ontrack);
837 r = find_next_region (pos, point, dir, track_views, &ontrack);
846 pos = r->first_frame ();
850 pos = r->last_frame ();
854 pos = r->sync_position ();
859 RouteTimeAxisView *rtav;
861 if ( ontrack != 0 && (rtav = dynamic_cast<RouteTimeAxisView*>(ontrack)) != 0 ) {
862 if (rtav->track() != 0) {
863 speed = rtav->track()->speed();
867 pos = track_frame_to_session_frame(pos, speed);
869 if (cursor == playhead_cursor) {
870 _session->request_locate (pos);
872 cursor->set_position (pos);
877 Editor::cursor_to_next_region_point (EditorCursor* cursor, RegionPoint point)
879 cursor_to_region_point (cursor, point, 1);
883 Editor::cursor_to_previous_region_point (EditorCursor* cursor, RegionPoint point)
885 cursor_to_region_point (cursor, point, -1);
889 Editor::cursor_to_selection_start (EditorCursor *cursor)
893 switch (mouse_mode) {
895 if (!selection->regions.empty()) {
896 pos = selection->regions.start();
901 if (!selection->time.empty()) {
902 pos = selection->time.start ();
910 if (cursor == playhead_cursor) {
911 _session->request_locate (pos);
913 cursor->set_position (pos);
918 Editor::cursor_to_selection_end (EditorCursor *cursor)
922 switch (mouse_mode) {
924 if (!selection->regions.empty()) {
925 pos = selection->regions.end_frame();
930 if (!selection->time.empty()) {
931 pos = selection->time.end_frame ();
939 if (cursor == playhead_cursor) {
940 _session->request_locate (pos);
942 cursor->set_position (pos);
947 Editor::selected_marker_to_region_boundary (bool with_selection, int32_t dir)
957 if (selection->markers.empty()) {
961 if (!mouse_frame (mouse, ignored)) {
965 add_location_mark (mouse);
968 if ((loc = find_location_from_marker (selection->markers.front(), ignored)) == 0) {
972 framepos_t pos = loc->start();
974 // so we don't find the current region again..
975 if (dir > 0 || pos > 0) {
979 if ((target = get_region_boundary (pos, dir, with_selection, false)) < 0) {
983 loc->move_to (target);
987 Editor::selected_marker_to_next_region_boundary (bool with_selection)
989 selected_marker_to_region_boundary (with_selection, 1);
993 Editor::selected_marker_to_previous_region_boundary (bool with_selection)
995 selected_marker_to_region_boundary (with_selection, -1);
999 Editor::selected_marker_to_region_point (RegionPoint point, int32_t dir)
1001 boost::shared_ptr<Region> r;
1006 if (!_session || selection->markers.empty()) {
1010 if ((loc = find_location_from_marker (selection->markers.front(), ignored)) == 0) {
1014 TimeAxisView *ontrack = 0;
1018 // so we don't find the current region again..
1022 if (!selection->tracks.empty()) {
1024 r = find_next_region (pos, point, dir, selection->tracks, &ontrack);
1028 r = find_next_region (pos, point, dir, track_views, &ontrack);
1037 pos = r->first_frame ();
1041 pos = r->last_frame ();
1045 pos = r->adjust_to_sync (r->first_frame());
1050 RouteTimeAxisView *rtav;
1052 if (ontrack != 0 && (rtav = dynamic_cast<RouteTimeAxisView*>(ontrack)) != 0) {
1053 if (rtav->track() != 0) {
1054 speed = rtav->track()->speed();
1058 pos = track_frame_to_session_frame(pos, speed);
1064 Editor::selected_marker_to_next_region_point (RegionPoint point)
1066 selected_marker_to_region_point (point, 1);
1070 Editor::selected_marker_to_previous_region_point (RegionPoint point)
1072 selected_marker_to_region_point (point, -1);
1076 Editor::selected_marker_to_selection_start ()
1082 if (!_session || selection->markers.empty()) {
1086 if ((loc = find_location_from_marker (selection->markers.front(), ignored)) == 0) {
1090 switch (mouse_mode) {
1092 if (!selection->regions.empty()) {
1093 pos = selection->regions.start();
1098 if (!selection->time.empty()) {
1099 pos = selection->time.start ();
1111 Editor::selected_marker_to_selection_end ()
1117 if (!_session || selection->markers.empty()) {
1121 if ((loc = find_location_from_marker (selection->markers.front(), ignored)) == 0) {
1125 switch (mouse_mode) {
1127 if (!selection->regions.empty()) {
1128 pos = selection->regions.end_frame();
1133 if (!selection->time.empty()) {
1134 pos = selection->time.end_frame ();
1146 Editor::scroll_playhead (bool forward)
1148 framepos_t pos = playhead_cursor->current_frame ();
1149 framecnt_t delta = (framecnt_t) floor (current_page_samples() / 0.8);
1152 if (pos == max_framepos) {
1156 if (pos < max_framepos - delta) {
1175 _session->request_locate (pos);
1179 Editor::cursor_align (bool playhead_to_edit)
1185 if (playhead_to_edit) {
1187 if (selection->markers.empty()) {
1191 _session->request_locate (selection->markers.front()->position(), _session->transport_rolling());
1194 /* move selected markers to playhead */
1196 for (MarkerSelection::iterator i = selection->markers.begin(); i != selection->markers.end(); ++i) {
1199 Location* loc = find_location_from_marker (*i, ignored);
1201 if (loc->is_mark()) {
1202 loc->set_start (playhead_cursor->current_frame ());
1204 loc->set (playhead_cursor->current_frame (),
1205 playhead_cursor->current_frame () + loc->length());
1212 Editor::scroll_backward (float pages)
1214 framepos_t const one_page = (framepos_t) rint (_visible_canvas_width * samples_per_pixel);
1215 framepos_t const cnt = (framepos_t) floor (pages * one_page);
1218 if (leftmost_frame < cnt) {
1221 frame = leftmost_frame - cnt;
1224 reset_x_origin (frame);
1228 Editor::scroll_forward (float pages)
1230 framepos_t const one_page = (framepos_t) rint (_visible_canvas_width * samples_per_pixel);
1231 framepos_t const cnt = (framepos_t) floor (pages * one_page);
1234 if (max_framepos - cnt < leftmost_frame) {
1235 frame = max_framepos - cnt;
1237 frame = leftmost_frame + cnt;
1240 reset_x_origin (frame);
1244 Editor::scroll_tracks_down ()
1246 double vert_value = vertical_adjustment.get_value() + vertical_adjustment.get_page_size();
1247 if (vert_value > vertical_adjustment.get_upper() - _visible_canvas_height) {
1248 vert_value = vertical_adjustment.get_upper() - _visible_canvas_height;
1251 vertical_adjustment.set_value (vert_value);
1255 Editor::scroll_tracks_up ()
1257 vertical_adjustment.set_value (vertical_adjustment.get_value() - vertical_adjustment.get_page_size());
1261 Editor::scroll_tracks_down_line ()
1263 double vert_value = vertical_adjustment.get_value() + 60;
1265 if (vert_value > vertical_adjustment.get_upper() - _visible_canvas_height) {
1266 vert_value = vertical_adjustment.get_upper() - _visible_canvas_height;
1269 vertical_adjustment.set_value (vert_value);
1273 Editor::scroll_tracks_up_line ()
1275 reset_y_origin (vertical_adjustment.get_value() - 60);
1281 Editor::tav_zoom_step (bool coarser)
1283 _routes->suspend_redisplay ();
1287 if (selection->tracks.empty()) {
1290 ts = &selection->tracks;
1293 for (TrackViewList::iterator i = ts->begin(); i != ts->end(); ++i) {
1294 TimeAxisView *tv = (static_cast<TimeAxisView*>(*i));
1295 tv->step_height (coarser);
1298 _routes->resume_redisplay ();
1302 Editor::tav_zoom_smooth (bool coarser, bool force_all)
1304 _routes->suspend_redisplay ();
1308 if (selection->tracks.empty() || force_all) {
1311 ts = &selection->tracks;
1314 for (TrackViewList::iterator i = ts->begin(); i != ts->end(); ++i) {
1315 TimeAxisView *tv = (static_cast<TimeAxisView*>(*i));
1316 uint32_t h = tv->current_height ();
1321 if (h >= TimeAxisView::preset_height (HeightSmall)) {
1326 tv->set_height (h + 5);
1330 _routes->resume_redisplay ();
1334 Editor::clamp_samples_per_pixel (framecnt_t& fpp) const
1336 bool clamped = false;
1343 if (max_framepos / fpp < 800) {
1344 fpp = max_framepos / 800;
1352 Editor::temporal_zoom_step (bool coarser)
1354 ENSURE_GUI_THREAD (*this, &Editor::temporal_zoom_step, coarser)
1356 framecnt_t nspp = samples_per_pixel;
1364 temporal_zoom (nspp);
1368 Editor::temporal_zoom (framecnt_t fpp)
1374 framepos_t current_page = current_page_samples();
1375 framepos_t current_leftmost = leftmost_frame;
1376 framepos_t current_rightmost;
1377 framepos_t current_center;
1378 framepos_t new_page_size;
1379 framepos_t half_page_size;
1380 framepos_t leftmost_after_zoom = 0;
1382 bool in_track_canvas;
1386 clamp_samples_per_pixel (fpp);
1387 if (fpp == samples_per_pixel) {
1391 // Imposing an arbitrary limit to zoom out as too much zoom out produces
1392 // segfaults for lack of memory. If somebody decides this is not high enough I
1393 // believe it can be raisen to higher values but some limit must be in place.
1395 // This constant represents 1 day @ 48kHz on a 1600 pixel wide display
1396 // all of which is used for the editor track displays. The whole day
1397 // would be 4147200000 samples, so 2592000 samples per pixel.
1399 nfpp = min (fpp, (framecnt_t) 2592000);
1400 nfpp = max ((framecnt_t) 1, fpp);
1402 new_page_size = (framepos_t) floor (_visible_canvas_width * nfpp);
1403 half_page_size = new_page_size / 2;
1405 switch (zoom_focus) {
1407 leftmost_after_zoom = current_leftmost;
1410 case ZoomFocusRight:
1411 current_rightmost = leftmost_frame + current_page;
1412 if (current_rightmost < new_page_size) {
1413 leftmost_after_zoom = 0;
1415 leftmost_after_zoom = current_rightmost - new_page_size;
1419 case ZoomFocusCenter:
1420 current_center = current_leftmost + (current_page/2);
1421 if (current_center < half_page_size) {
1422 leftmost_after_zoom = 0;
1424 leftmost_after_zoom = current_center - half_page_size;
1428 case ZoomFocusPlayhead:
1429 /* centre playhead */
1430 l = playhead_cursor->current_frame () - (new_page_size * 0.5);
1433 leftmost_after_zoom = 0;
1434 } else if (l > max_framepos) {
1435 leftmost_after_zoom = max_framepos - new_page_size;
1437 leftmost_after_zoom = (framepos_t) l;
1441 case ZoomFocusMouse:
1442 /* try to keep the mouse over the same point in the display */
1444 if (!mouse_frame (where, in_track_canvas)) {
1445 /* use playhead instead */
1446 where = playhead_cursor->current_frame ();
1448 if (where < half_page_size) {
1449 leftmost_after_zoom = 0;
1451 leftmost_after_zoom = where - half_page_size;
1456 l = - ((new_page_size * ((where - current_leftmost)/(double)current_page)) - where);
1459 leftmost_after_zoom = 0;
1460 } else if (l > max_framepos) {
1461 leftmost_after_zoom = max_framepos - new_page_size;
1463 leftmost_after_zoom = (framepos_t) l;
1470 /* try to keep the edit point in the same place */
1471 where = get_preferred_edit_position ();
1475 double l = - ((new_page_size * ((where - current_leftmost)/(double)current_page)) - where);
1478 leftmost_after_zoom = 0;
1479 } else if (l > max_framepos) {
1480 leftmost_after_zoom = max_framepos - new_page_size;
1482 leftmost_after_zoom = (framepos_t) l;
1486 /* edit point not defined */
1493 // leftmost_after_zoom = min (leftmost_after_zoom, _session->current_end_frame());
1495 reposition_and_zoom (leftmost_after_zoom, nfpp);
1499 Editor::temporal_zoom_region (bool both_axes)
1501 framepos_t start = max_framepos;
1503 set<TimeAxisView*> tracks;
1505 RegionSelection rs = get_regions_from_selection_and_entered ();
1511 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
1513 if ((*i)->region()->position() < start) {
1514 start = (*i)->region()->position();
1517 if ((*i)->region()->last_frame() + 1 > end) {
1518 end = (*i)->region()->last_frame() + 1;
1521 tracks.insert (&((*i)->get_time_axis_view()));
1524 /* now comes an "interesting" hack ... make sure we leave a little space
1525 at each end of the editor so that the zoom doesn't fit the region
1526 precisely to the screen.
1529 GdkScreen* screen = gdk_screen_get_default ();
1530 gint pixwidth = gdk_screen_get_width (screen);
1531 gint mmwidth = gdk_screen_get_width_mm (screen);
1532 double pix_per_mm = (double) pixwidth/ (double) mmwidth;
1533 double one_centimeter_in_pixels = pix_per_mm * 10.0;
1535 if ((start == 0 && end == 0) || end < start) {
1539 framepos_t range = end - start;
1540 double new_fpp = (double) range / (double) _visible_canvas_width;
1541 framepos_t extra_samples = (framepos_t) floor (one_centimeter_in_pixels * new_fpp);
1543 if (start > extra_samples) {
1544 start -= extra_samples;
1549 if (max_framepos - extra_samples > end) {
1550 end += extra_samples;
1555 /* if we're zooming on both axes we need to save track heights etc.
1558 undo_visual_stack.push_back (current_visual_state (both_axes));
1560 PBD::Unwinder<bool> nsv (no_save_visual, true);
1562 temporal_zoom_by_frame (start, end);
1565 uint32_t per_track_height = (uint32_t) floor ((_visible_canvas_height - 10.0) / tracks.size());
1567 /* set visible track heights appropriately */
1569 for (set<TimeAxisView*>::iterator t = tracks.begin(); t != tracks.end(); ++t) {
1570 (*t)->set_height (per_track_height);
1573 /* hide irrelevant tracks */
1575 _routes->suspend_redisplay ();
1577 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1578 if (find (tracks.begin(), tracks.end(), (*i)) == tracks.end()) {
1579 hide_track_in_display (*i);
1583 _routes->resume_redisplay ();
1585 vertical_adjustment.set_value (0.0);
1588 redo_visual_stack.push_back (current_visual_state (both_axes));
1592 Editor::zoom_to_region (bool both_axes)
1594 temporal_zoom_region (both_axes);
1598 Editor::temporal_zoom_selection ()
1600 if (!selection) return;
1602 if (selection->time.empty()) {
1606 framepos_t start = selection->time[clicked_selection].start;
1607 framepos_t end = selection->time[clicked_selection].end;
1609 temporal_zoom_by_frame (start, end);
1613 Editor::temporal_zoom_session ()
1615 ENSURE_GUI_THREAD (*this, &Editor::temporal_zoom_session)
1618 framecnt_t const l = _session->current_end_frame() - _session->current_start_frame();
1619 double s = _session->current_start_frame() - l * 0.01;
1623 framecnt_t const e = _session->current_end_frame() + l * 0.01;
1624 temporal_zoom_by_frame (framecnt_t (s), e);
1629 Editor::temporal_zoom_by_frame (framepos_t start, framepos_t end)
1631 if (!_session) return;
1633 if ((start == 0 && end == 0) || end < start) {
1637 framepos_t range = end - start;
1639 double const new_fpp = (double) range / (double) _visible_canvas_width;
1641 framepos_t new_page = (framepos_t) floor (_visible_canvas_width * new_fpp);
1642 framepos_t middle = (framepos_t) floor ((double) start + ((double) range / 2.0f));
1643 framepos_t new_leftmost = (framepos_t) floor ((double) middle - ((double) new_page / 2.0f));
1645 if (new_leftmost > middle) {
1649 if (new_leftmost < 0) {
1653 reposition_and_zoom (new_leftmost, new_fpp);
1657 Editor::temporal_zoom_to_frame (bool coarser, framepos_t frame)
1662 double range_before = frame - leftmost_frame;
1665 new_fpp = samples_per_pixel;
1668 new_fpp *= 1.61803399;
1669 range_before *= 1.61803399;
1671 new_fpp = max(1.0,(new_fpp/1.61803399));
1672 range_before /= 1.61803399;
1675 if (new_fpp == samples_per_pixel) {
1679 framepos_t new_leftmost = frame - (framepos_t)range_before;
1681 if (new_leftmost > frame) {
1685 if (new_leftmost < 0) {
1689 reposition_and_zoom (new_leftmost, new_fpp);
1694 Editor::choose_new_marker_name(string &name) {
1696 if (!Config->get_name_new_markers()) {
1697 /* don't prompt user for a new name */
1701 ArdourPrompter dialog (true);
1703 dialog.set_prompt (_("New Name:"));
1705 dialog.set_title (_("New Location Marker"));
1707 dialog.set_name ("MarkNameWindow");
1708 dialog.set_size_request (250, -1);
1709 dialog.set_position (Gtk::WIN_POS_MOUSE);
1711 dialog.add_button (Stock::OK, RESPONSE_ACCEPT);
1712 dialog.set_initial_text (name);
1716 switch (dialog.run ()) {
1717 case RESPONSE_ACCEPT:
1723 dialog.get_result(name);
1730 Editor::add_location_from_selection ()
1734 if (selection->time.empty()) {
1738 if (_session == 0 || clicked_axisview == 0) {
1742 framepos_t start = selection->time[clicked_selection].start;
1743 framepos_t end = selection->time[clicked_selection].end;
1745 _session->locations()->next_available_name(rangename,"selection");
1746 Location *location = new Location (*_session, start, end, rangename, Location::IsRangeMarker);
1748 _session->begin_reversible_command (_("add marker"));
1749 XMLNode &before = _session->locations()->get_state();
1750 _session->locations()->add (location, true);
1751 XMLNode &after = _session->locations()->get_state();
1752 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
1753 _session->commit_reversible_command ();
1757 Editor::add_location_mark (framepos_t where)
1761 select_new_marker = true;
1763 _session->locations()->next_available_name(markername,"mark");
1764 if (!choose_new_marker_name(markername)) {
1767 Location *location = new Location (*_session, where, where, markername, Location::IsMark);
1768 _session->begin_reversible_command (_("add marker"));
1769 XMLNode &before = _session->locations()->get_state();
1770 _session->locations()->add (location, true);
1771 XMLNode &after = _session->locations()->get_state();
1772 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
1773 _session->commit_reversible_command ();
1777 Editor::add_location_from_playhead_cursor ()
1779 add_location_mark (_session->audible_frame());
1782 /** Add a range marker around each selected region */
1784 Editor::add_locations_from_region ()
1786 RegionSelection rs = get_regions_from_selection_and_entered ();
1792 _session->begin_reversible_command (selection->regions.size () > 1 ? _("add markers") : _("add marker"));
1793 XMLNode &before = _session->locations()->get_state();
1795 for (RegionSelection::iterator i = rs.begin (); i != rs.end (); ++i) {
1797 boost::shared_ptr<Region> region = (*i)->region ();
1799 Location *location = new Location (*_session, region->position(), region->last_frame(), region->name(), Location::IsRangeMarker);
1801 _session->locations()->add (location, true);
1804 XMLNode &after = _session->locations()->get_state();
1805 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
1806 _session->commit_reversible_command ();
1809 /** Add a single range marker around all selected regions */
1811 Editor::add_location_from_region ()
1813 RegionSelection rs = get_regions_from_selection_and_entered ();
1819 _session->begin_reversible_command (_("add marker"));
1820 XMLNode &before = _session->locations()->get_state();
1824 if (rs.size() > 1) {
1825 _session->locations()->next_available_name(markername, "regions");
1827 RegionView* rv = *(rs.begin());
1828 boost::shared_ptr<Region> region = rv->region();
1829 markername = region->name();
1832 if (!choose_new_marker_name(markername)) {
1836 // single range spanning all selected
1837 Location *location = new Location (*_session, selection->regions.start(), selection->regions.end_frame(), markername, Location::IsRangeMarker);
1838 _session->locations()->add (location, true);
1840 XMLNode &after = _session->locations()->get_state();
1841 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
1842 _session->commit_reversible_command ();
1848 Editor::jump_forward_to_mark ()
1854 framepos_t pos = _session->locations()->first_mark_after (playhead_cursor->current_frame());
1860 _session->request_locate (pos, _session->transport_rolling());
1864 Editor::jump_backward_to_mark ()
1870 framepos_t pos = _session->locations()->first_mark_before (playhead_cursor->current_frame());
1876 _session->request_locate (pos, _session->transport_rolling());
1882 framepos_t const pos = _session->audible_frame ();
1885 _session->locations()->next_available_name (markername, "mark");
1887 if (!choose_new_marker_name (markername)) {
1891 _session->locations()->add (new Location (*_session, pos, 0, markername, Location::IsMark), true);
1895 Editor::clear_markers ()
1898 _session->begin_reversible_command (_("clear markers"));
1899 XMLNode &before = _session->locations()->get_state();
1900 _session->locations()->clear_markers ();
1901 XMLNode &after = _session->locations()->get_state();
1902 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
1903 _session->commit_reversible_command ();
1908 Editor::clear_ranges ()
1911 _session->begin_reversible_command (_("clear ranges"));
1912 XMLNode &before = _session->locations()->get_state();
1914 Location * looploc = _session->locations()->auto_loop_location();
1915 Location * punchloc = _session->locations()->auto_punch_location();
1916 Location * sessionloc = _session->locations()->session_range_location();
1918 _session->locations()->clear_ranges ();
1920 if (looploc) _session->locations()->add (looploc);
1921 if (punchloc) _session->locations()->add (punchloc);
1922 if (sessionloc) _session->locations()->add (sessionloc);
1924 XMLNode &after = _session->locations()->get_state();
1925 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
1926 _session->commit_reversible_command ();
1931 Editor::clear_locations ()
1933 _session->begin_reversible_command (_("clear locations"));
1934 XMLNode &before = _session->locations()->get_state();
1935 _session->locations()->clear ();
1936 XMLNode &after = _session->locations()->get_state();
1937 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
1938 _session->commit_reversible_command ();
1939 _session->locations()->clear ();
1943 Editor::unhide_markers ()
1945 for (LocationMarkerMap::iterator i = location_markers.begin(); i != location_markers.end(); ++i) {
1946 Location *l = (*i).first;
1947 if (l->is_hidden() && l->is_mark()) {
1948 l->set_hidden(false, this);
1954 Editor::unhide_ranges ()
1956 for (LocationMarkerMap::iterator i = location_markers.begin(); i != location_markers.end(); ++i) {
1957 Location *l = (*i).first;
1958 if (l->is_hidden() && l->is_range_marker()) {
1959 l->set_hidden(false, this);
1964 /* INSERT/REPLACE */
1967 Editor::insert_region_list_drag (boost::shared_ptr<Region> region, int x, int y)
1971 RouteTimeAxisView *rtv = 0;
1972 boost::shared_ptr<Playlist> playlist;
1975 event.type = GDK_BUTTON_RELEASE;
1979 where = window_event_frame (&event, &cx, &cy);
1981 if (where < leftmost_frame || where > leftmost_frame + current_page_samples()) {
1982 /* clearly outside canvas area */
1986 std::pair<TimeAxisView*, int> tv = trackview_by_y_position (cy);
1987 if (tv.first == 0) {
1991 if ((rtv = dynamic_cast<RouteTimeAxisView*> (tv.first)) == 0) {
1995 if ((playlist = rtv->playlist()) == 0) {
2001 begin_reversible_command (_("insert dragged region"));
2002 playlist->clear_changes ();
2003 playlist->add_region (RegionFactory::create (region, true), where, 1.0);
2004 _session->add_command(new StatefulDiffCommand (playlist));
2005 commit_reversible_command ();
2009 Editor::insert_route_list_drag (boost::shared_ptr<Route> route, int x, int y)
2012 RouteTimeAxisView *dest_rtv = 0;
2013 RouteTimeAxisView *source_rtv = 0;
2016 event.type = GDK_BUTTON_RELEASE;
2020 window_event_frame (&event, &cx, &cy);
2022 std::pair<TimeAxisView*, int> const tv = trackview_by_y_position (cy);
2023 if (tv.first == 0) {
2027 if ((dest_rtv = dynamic_cast<RouteTimeAxisView*> (tv.first)) == 0) {
2031 /* use this drag source to add underlay to a track. But we really don't care
2032 about the Route, only the view of the route, so find it first */
2033 for(TrackViewList::iterator it = track_views.begin(); it != track_views.end(); ++it) {
2034 if((source_rtv = dynamic_cast<RouteTimeAxisView*>(*it)) == 0) {
2038 if(source_rtv->route() == route && source_rtv != dest_rtv) {
2039 dest_rtv->add_underlay(source_rtv->view());
2046 Editor::insert_region_list_selection (float times)
2048 RouteTimeAxisView *tv = 0;
2049 boost::shared_ptr<Playlist> playlist;
2051 if (clicked_routeview != 0) {
2052 tv = clicked_routeview;
2053 } else if (!selection->tracks.empty()) {
2054 if ((tv = dynamic_cast<RouteTimeAxisView*>(selection->tracks.front())) == 0) {
2057 } else if (entered_track != 0) {
2058 if ((tv = dynamic_cast<RouteTimeAxisView*>(entered_track)) == 0) {
2065 if ((playlist = tv->playlist()) == 0) {
2069 boost::shared_ptr<Region> region = _regions->get_single_selection ();
2074 begin_reversible_command (_("insert region"));
2075 playlist->clear_changes ();
2076 playlist->add_region ((RegionFactory::create (region, true)), get_preferred_edit_position(), times);
2077 _session->add_command(new StatefulDiffCommand (playlist));
2078 commit_reversible_command ();
2081 /* BUILT-IN EFFECTS */
2084 Editor::reverse_selection ()
2089 /* GAIN ENVELOPE EDITING */
2092 Editor::edit_envelope ()
2099 Editor::transition_to_rolling (bool fwd)
2105 if (_session->config.get_external_sync()) {
2106 switch (Config->get_sync_source()) {
2110 /* transport controlled by the master */
2115 if (_session->is_auditioning()) {
2116 _session->cancel_audition ();
2120 _session->request_transport_speed (fwd ? 1.0f : -1.0f);
2124 Editor::play_from_start ()
2126 _session->request_locate (_session->current_start_frame(), true);
2130 Editor::play_from_edit_point ()
2132 _session->request_locate (get_preferred_edit_position(), true);
2136 Editor::play_from_edit_point_and_return ()
2138 framepos_t start_frame;
2139 framepos_t return_frame;
2141 start_frame = get_preferred_edit_position (true);
2143 if (_session->transport_rolling()) {
2144 _session->request_locate (start_frame, false);
2148 /* don't reset the return frame if its already set */
2150 if ((return_frame = _session->requested_return_frame()) < 0) {
2151 return_frame = _session->audible_frame();
2154 if (start_frame >= 0) {
2155 _session->request_roll_at_and_return (start_frame, return_frame);
2160 Editor::play_selection ()
2162 if (selection->time.empty()) {
2166 _session->request_play_range (&selection->time, true);
2170 Editor::get_preroll ()
2172 return 1.0 /*Config->get_edit_preroll_seconds()*/ * _session->frame_rate();
2177 Editor::maybe_locate_with_edit_preroll ( framepos_t location )
2179 if ( _session->transport_rolling() || !Config->get_always_play_range() )
2182 location -= get_preroll();
2184 //don't try to locate before the beginning of time
2188 //if follow_playhead is on, keep the playhead on the screen
2189 if ( _follow_playhead )
2190 if ( location < leftmost_frame )
2191 location = leftmost_frame;
2193 _session->request_locate( location );
2197 Editor::play_with_preroll ()
2199 if (selection->time.empty()) {
2202 framepos_t preroll = get_preroll();
2204 framepos_t start = 0;
2205 if (selection->time[clicked_selection].start > preroll)
2206 start = selection->time[clicked_selection].start - preroll;
2208 framepos_t end = selection->time[clicked_selection].end + preroll;
2210 AudioRange ar (start, end, 0);
2211 list<AudioRange> lar;
2214 _session->request_play_range (&lar, true);
2219 Editor::play_location (Location& location)
2221 if (location.start() <= location.end()) {
2225 _session->request_bounded_roll (location.start(), location.end());
2229 Editor::loop_location (Location& location)
2231 if (location.start() <= location.end()) {
2237 if ((tll = transport_loop_location()) != 0) {
2238 tll->set (location.start(), location.end());
2240 // enable looping, reposition and start rolling
2241 _session->request_play_loop (true);
2242 _session->request_locate (tll->start(), true);
2247 Editor::do_layer_operation (LayerOperation op)
2249 if (selection->regions.empty ()) {
2253 bool const multiple = selection->regions.size() > 1;
2257 begin_reversible_command (_("raise regions"));
2259 begin_reversible_command (_("raise region"));
2265 begin_reversible_command (_("raise regions to top"));
2267 begin_reversible_command (_("raise region to top"));
2273 begin_reversible_command (_("lower regions"));
2275 begin_reversible_command (_("lower region"));
2281 begin_reversible_command (_("lower regions to bottom"));
2283 begin_reversible_command (_("lower region"));
2288 set<boost::shared_ptr<Playlist> > playlists = selection->regions.playlists ();
2289 for (set<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
2290 (*i)->clear_owned_changes ();
2293 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
2294 boost::shared_ptr<Region> r = (*i)->region ();
2306 r->lower_to_bottom ();
2310 for (set<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
2311 vector<Command*> cmds;
2313 _session->add_commands (cmds);
2316 commit_reversible_command ();
2320 Editor::raise_region ()
2322 do_layer_operation (Raise);
2326 Editor::raise_region_to_top ()
2328 do_layer_operation (RaiseToTop);
2332 Editor::lower_region ()
2334 do_layer_operation (Lower);
2338 Editor::lower_region_to_bottom ()
2340 do_layer_operation (LowerToBottom);
2343 /** Show the region editor for the selected regions */
2345 Editor::show_region_properties ()
2347 selection->foreach_regionview (&RegionView::show_region_editor);
2350 /** Show the midi list editor for the selected MIDI regions */
2352 Editor::show_midi_list_editor ()
2354 selection->foreach_midi_regionview (&MidiRegionView::show_list_editor);
2358 Editor::rename_region ()
2360 RegionSelection rs = get_regions_from_selection_and_entered ();
2366 ArdourDialog d (*this, _("Rename Region"), true, false);
2368 Label label (_("New name:"));
2371 hbox.set_spacing (6);
2372 hbox.pack_start (label, false, false);
2373 hbox.pack_start (entry, true, true);
2375 d.get_vbox()->set_border_width (12);
2376 d.get_vbox()->pack_start (hbox, false, false);
2378 d.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
2379 d.add_button(Gtk::Stock::OK, Gtk::RESPONSE_OK);
2381 d.set_size_request (300, -1);
2383 entry.set_text (rs.front()->region()->name());
2384 entry.select_region (0, -1);
2386 entry.signal_activate().connect (sigc::bind (sigc::mem_fun (d, &Dialog::response), RESPONSE_OK));
2392 int const ret = d.run();
2396 if (ret != RESPONSE_OK) {
2400 std::string str = entry.get_text();
2401 strip_whitespace_edges (str);
2403 rs.front()->region()->set_name (str);
2404 _regions->redisplay ();
2409 Editor::audition_playlist_region_via_route (boost::shared_ptr<Region> region, Route& route)
2411 if (_session->is_auditioning()) {
2412 _session->cancel_audition ();
2415 // note: some potential for creativity here, because region doesn't
2416 // have to belong to the playlist that Route is handling
2418 // bool was_soloed = route.soloed();
2420 route.set_solo (true, this);
2422 _session->request_bounded_roll (region->position(), region->position() + region->length());
2424 /* XXX how to unset the solo state ? */
2427 /** Start an audition of the first selected region */
2429 Editor::play_edit_range ()
2431 framepos_t start, end;
2433 if (get_edit_op_range (start, end)) {
2434 _session->request_bounded_roll (start, end);
2439 Editor::play_selected_region ()
2441 framepos_t start = max_framepos;
2444 RegionSelection rs = get_regions_from_selection_and_entered ();
2450 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
2451 if ((*i)->region()->position() < start) {
2452 start = (*i)->region()->position();
2454 if ((*i)->region()->last_frame() + 1 > end) {
2455 end = (*i)->region()->last_frame() + 1;
2459 _session->request_bounded_roll (start, end);
2463 Editor::audition_playlist_region_standalone (boost::shared_ptr<Region> region)
2465 _session->audition_region (region);
2469 Editor::region_from_selection ()
2471 if (clicked_axisview == 0) {
2475 if (selection->time.empty()) {
2479 framepos_t start = selection->time[clicked_selection].start;
2480 framepos_t end = selection->time[clicked_selection].end;
2482 TrackViewList tracks = get_tracks_for_range_action ();
2484 framepos_t selection_cnt = end - start + 1;
2486 for (TrackSelection::iterator i = tracks.begin(); i != tracks.end(); ++i) {
2487 boost::shared_ptr<Region> current;
2488 boost::shared_ptr<Playlist> pl;
2489 framepos_t internal_start;
2492 if ((pl = (*i)->playlist()) == 0) {
2496 if ((current = pl->top_region_at (start)) == 0) {
2500 internal_start = start - current->position();
2501 RegionFactory::region_name (new_name, current->name(), true);
2505 plist.add (ARDOUR::Properties::start, current->start() + internal_start);
2506 plist.add (ARDOUR::Properties::length, selection_cnt);
2507 plist.add (ARDOUR::Properties::name, new_name);
2508 plist.add (ARDOUR::Properties::layer, 0);
2510 boost::shared_ptr<Region> region (RegionFactory::create (current, plist));
2515 Editor::create_region_from_selection (vector<boost::shared_ptr<Region> >& new_regions)
2517 if (selection->time.empty() || selection->tracks.empty()) {
2521 framepos_t start = selection->time[clicked_selection].start;
2522 framepos_t end = selection->time[clicked_selection].end;
2524 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
2525 sort_track_selection (ts);
2527 for (TrackSelection::iterator i = ts.begin(); i != ts.end(); ++i) {
2528 boost::shared_ptr<Region> current;
2529 boost::shared_ptr<Playlist> playlist;
2530 framepos_t internal_start;
2533 if ((playlist = (*i)->playlist()) == 0) {
2537 if ((current = playlist->top_region_at(start)) == 0) {
2541 internal_start = start - current->position();
2542 RegionFactory::region_name (new_name, current->name(), true);
2546 plist.add (ARDOUR::Properties::start, current->start() + internal_start);
2547 plist.add (ARDOUR::Properties::length, end - start + 1);
2548 plist.add (ARDOUR::Properties::name, new_name);
2550 new_regions.push_back (RegionFactory::create (current, plist));
2555 Editor::split_multichannel_region ()
2557 RegionSelection rs = get_regions_from_selection_and_entered ();
2563 vector< boost::shared_ptr<Region> > v;
2565 for (list<RegionView*>::iterator x = rs.begin(); x != rs.end(); ++x) {
2566 (*x)->region()->separate_by_channel (*_session, v);
2571 Editor::new_region_from_selection ()
2573 region_from_selection ();
2574 cancel_selection ();
2578 add_if_covered (RegionView* rv, const AudioRange* ar, RegionSelection* rs)
2580 switch (rv->region()->coverage (ar->start, ar->end - 1)) {
2581 case Evoral::OverlapNone:
2589 * - selected tracks, or if there are none...
2590 * - tracks containing selected regions, or if there are none...
2595 Editor::get_tracks_for_range_action () const
2599 if (selection->tracks.empty()) {
2601 /* use tracks with selected regions */
2603 RegionSelection rs = selection->regions;
2605 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
2606 TimeAxisView* tv = &(*i)->get_time_axis_view();
2608 if (!t.contains (tv)) {
2614 /* no regions and no tracks: use all tracks */
2620 t = selection->tracks;
2623 return t.filter_to_unique_playlists();
2627 Editor::separate_regions_between (const TimeSelection& ts)
2629 bool in_command = false;
2630 boost::shared_ptr<Playlist> playlist;
2631 RegionSelection new_selection;
2633 TrackViewList tmptracks = get_tracks_for_range_action ();
2634 sort_track_selection (tmptracks);
2636 for (TrackSelection::iterator i = tmptracks.begin(); i != tmptracks.end(); ++i) {
2638 RouteTimeAxisView* rtv;
2640 if ((rtv = dynamic_cast<RouteTimeAxisView*> ((*i))) != 0) {
2642 if (rtv->is_track()) {
2644 /* no edits to destructive tracks */
2646 if (rtv->track()->destructive()) {
2650 if ((playlist = rtv->playlist()) != 0) {
2652 playlist->clear_changes ();
2654 /* XXX need to consider musical time selections here at some point */
2656 double speed = rtv->track()->speed();
2659 for (list<AudioRange>::const_iterator t = ts.begin(); t != ts.end(); ++t) {
2661 sigc::connection c = rtv->view()->RegionViewAdded.connect (
2662 sigc::mem_fun(*this, &Editor::collect_new_region_view));
2664 latest_regionviews.clear ();
2666 playlist->partition ((framepos_t)((*t).start * speed),
2667 (framepos_t)((*t).end * speed), false);
2671 if (!latest_regionviews.empty()) {
2673 rtv->view()->foreach_regionview (sigc::bind (
2674 sigc::ptr_fun (add_if_covered),
2675 &(*t), &new_selection));
2678 begin_reversible_command (_("separate"));
2682 /* pick up changes to existing regions */
2684 vector<Command*> cmds;
2685 playlist->rdiff (cmds);
2686 _session->add_commands (cmds);
2688 /* pick up changes to the playlist itself (adds/removes)
2691 _session->add_command(new StatefulDiffCommand (playlist));
2700 selection->set (new_selection);
2701 set_mouse_mode (MouseObject);
2703 commit_reversible_command ();
2707 struct PlaylistState {
2708 boost::shared_ptr<Playlist> playlist;
2712 /** Take tracks from get_tracks_for_range_action and cut any regions
2713 * on those tracks so that the tracks are empty over the time
2717 Editor::separate_region_from_selection ()
2719 /* preferentially use *all* ranges in the time selection if we're in range mode
2720 to allow discontiguous operation, since get_edit_op_range() currently
2721 returns a single range.
2724 if (!selection->time.empty()) {
2726 separate_regions_between (selection->time);
2733 if (get_edit_op_range (start, end)) {
2735 AudioRange ar (start, end, 1);
2739 separate_regions_between (ts);
2745 Editor::separate_region_from_punch ()
2747 Location* loc = _session->locations()->auto_punch_location();
2749 separate_regions_using_location (*loc);
2754 Editor::separate_region_from_loop ()
2756 Location* loc = _session->locations()->auto_loop_location();
2758 separate_regions_using_location (*loc);
2763 Editor::separate_regions_using_location (Location& loc)
2765 if (loc.is_mark()) {
2769 AudioRange ar (loc.start(), loc.end(), 1);
2774 separate_regions_between (ts);
2777 /** Separate regions under the selected region */
2779 Editor::separate_under_selected_regions ()
2781 vector<PlaylistState> playlists;
2785 rs = get_regions_from_selection_and_entered();
2787 if (!_session || rs.empty()) {
2791 begin_reversible_command (_("separate region under"));
2793 list<boost::shared_ptr<Region> > regions_to_remove;
2795 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
2796 // we can't just remove the region(s) in this loop because
2797 // this removes them from the RegionSelection, and they thus
2798 // disappear from underneath the iterator, and the ++i above
2799 // SEGVs in a puzzling fashion.
2801 // so, first iterate over the regions to be removed from rs and
2802 // add them to the regions_to_remove list, and then
2803 // iterate over the list to actually remove them.
2805 regions_to_remove.push_back ((*i)->region());
2808 for (list<boost::shared_ptr<Region> >::iterator rl = regions_to_remove.begin(); rl != regions_to_remove.end(); ++rl) {
2810 boost::shared_ptr<Playlist> playlist = (*rl)->playlist();
2813 // is this check necessary?
2817 vector<PlaylistState>::iterator i;
2819 //only take state if this is a new playlist.
2820 for (i = playlists.begin(); i != playlists.end(); ++i) {
2821 if ((*i).playlist == playlist) {
2826 if (i == playlists.end()) {
2828 PlaylistState before;
2829 before.playlist = playlist;
2830 before.before = &playlist->get_state();
2832 playlist->freeze ();
2833 playlists.push_back(before);
2836 //Partition on the region bounds
2837 playlist->partition ((*rl)->first_frame() - 1, (*rl)->last_frame() + 1, true);
2839 //Re-add region that was just removed due to the partition operation
2840 playlist->add_region( (*rl), (*rl)->first_frame() );
2843 vector<PlaylistState>::iterator pl;
2845 for (pl = playlists.begin(); pl != playlists.end(); ++pl) {
2846 (*pl).playlist->thaw ();
2847 _session->add_command(new MementoCommand<Playlist>(*(*pl).playlist, (*pl).before, &(*pl).playlist->get_state()));
2850 commit_reversible_command ();
2854 Editor::crop_region_to_selection ()
2856 if (!selection->time.empty()) {
2858 crop_region_to (selection->time.start(), selection->time.end_frame());
2865 if (get_edit_op_range (start, end)) {
2866 crop_region_to (start, end);
2873 Editor::crop_region_to (framepos_t start, framepos_t end)
2875 vector<boost::shared_ptr<Playlist> > playlists;
2876 boost::shared_ptr<Playlist> playlist;
2879 if (selection->tracks.empty()) {
2880 ts = track_views.filter_to_unique_playlists();
2882 ts = selection->tracks.filter_to_unique_playlists ();
2885 sort_track_selection (ts);
2887 for (TrackSelection::iterator i = ts.begin(); i != ts.end(); ++i) {
2889 RouteTimeAxisView* rtv;
2891 if ((rtv = dynamic_cast<RouteTimeAxisView*> ((*i))) != 0) {
2893 boost::shared_ptr<Track> t = rtv->track();
2895 if (t != 0 && ! t->destructive()) {
2897 if ((playlist = rtv->playlist()) != 0) {
2898 playlists.push_back (playlist);
2904 if (playlists.empty()) {
2908 framepos_t the_start;
2912 begin_reversible_command (_("trim to selection"));
2914 for (vector<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
2916 boost::shared_ptr<Region> region;
2920 if ((region = (*i)->top_region_at(the_start)) == 0) {
2924 /* now adjust lengths to that we do the right thing
2925 if the selection extends beyond the region
2928 the_start = max (the_start, (framepos_t) region->position());
2929 if (max_framepos - the_start < region->length()) {
2930 the_end = the_start + region->length() - 1;
2932 the_end = max_framepos;
2934 the_end = min (end, the_end);
2935 cnt = the_end - the_start + 1;
2937 region->clear_changes ();
2938 region->trim_to (the_start, cnt);
2939 _session->add_command (new StatefulDiffCommand (region));
2942 commit_reversible_command ();
2946 Editor::region_fill_track ()
2948 RegionSelection rs = get_regions_from_selection_and_entered ();
2950 if (!_session || rs.empty()) {
2954 framepos_t const end = _session->current_end_frame ();
2956 begin_reversible_command (Operations::region_fill);
2958 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
2960 boost::shared_ptr<Region> region ((*i)->region());
2962 boost::shared_ptr<Playlist> pl = region->playlist();
2964 if (end <= region->last_frame()) {
2968 double times = (double) (end - region->last_frame()) / (double) region->length();
2974 pl->clear_changes ();
2975 pl->add_region (RegionFactory::create (region, true), region->last_frame(), times);
2976 _session->add_command (new StatefulDiffCommand (pl));
2979 commit_reversible_command ();
2983 Editor::region_fill_selection ()
2985 if (clicked_routeview == 0 || !clicked_routeview->is_audio_track()) {
2989 if (selection->time.empty()) {
2993 boost::shared_ptr<Region> region = _regions->get_single_selection ();
2998 framepos_t start = selection->time[clicked_selection].start;
2999 framepos_t end = selection->time[clicked_selection].end;
3001 boost::shared_ptr<Playlist> playlist;
3003 if (selection->tracks.empty()) {
3007 framepos_t selection_length = end - start;
3008 float times = (float)selection_length / region->length();
3010 begin_reversible_command (Operations::fill_selection);
3012 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
3014 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
3016 if ((playlist = (*i)->playlist()) == 0) {
3020 playlist->clear_changes ();
3021 playlist->add_region (RegionFactory::create (region, true), start, times);
3022 _session->add_command (new StatefulDiffCommand (playlist));
3025 commit_reversible_command ();
3029 Editor::set_region_sync_position ()
3031 set_sync_point (get_preferred_edit_position (), get_regions_from_selection_and_edit_point ());
3035 Editor::set_sync_point (framepos_t where, const RegionSelection& rs)
3037 bool in_command = false;
3039 for (RegionSelection::const_iterator r = rs.begin(); r != rs.end(); ++r) {
3041 if (!(*r)->region()->covers (where)) {
3045 boost::shared_ptr<Region> region ((*r)->region());
3048 begin_reversible_command (_("set sync point"));
3052 region->clear_changes ();
3053 region->set_sync_position (where);
3054 _session->add_command(new StatefulDiffCommand (region));
3058 commit_reversible_command ();
3062 /** Remove the sync positions of the selection */
3064 Editor::remove_region_sync ()
3066 RegionSelection rs = get_regions_from_selection_and_entered ();
3072 begin_reversible_command (_("remove region sync"));
3074 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3076 (*i)->region()->clear_changes ();
3077 (*i)->region()->clear_sync_position ();
3078 _session->add_command(new StatefulDiffCommand ((*i)->region()));
3081 commit_reversible_command ();
3085 Editor::naturalize_region ()
3087 RegionSelection rs = get_regions_from_selection_and_entered ();
3093 if (rs.size() > 1) {
3094 begin_reversible_command (_("move regions to original position"));
3096 begin_reversible_command (_("move region to original position"));
3099 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3100 (*i)->region()->clear_changes ();
3101 (*i)->region()->move_to_natural_position ();
3102 _session->add_command (new StatefulDiffCommand ((*i)->region()));
3105 commit_reversible_command ();
3109 Editor::align_regions (RegionPoint what)
3111 RegionSelection const rs = get_regions_from_selection_and_edit_point ();
3117 begin_reversible_command (_("align selection"));
3119 framepos_t const position = get_preferred_edit_position ();
3121 for (RegionSelection::const_iterator i = rs.begin(); i != rs.end(); ++i) {
3122 align_region_internal ((*i)->region(), what, position);
3125 commit_reversible_command ();
3128 struct RegionSortByTime {
3129 bool operator() (const RegionView* a, const RegionView* b) {
3130 return a->region()->position() < b->region()->position();
3135 Editor::align_regions_relative (RegionPoint point)
3137 RegionSelection const rs = get_regions_from_selection_and_edit_point ();
3143 framepos_t const position = get_preferred_edit_position ();
3145 framepos_t distance = 0;
3149 list<RegionView*> sorted;
3150 rs.by_position (sorted);
3152 boost::shared_ptr<Region> r ((*sorted.begin())->region());
3157 if (position > r->position()) {
3158 distance = position - r->position();
3160 distance = r->position() - position;
3166 if (position > r->last_frame()) {
3167 distance = position - r->last_frame();
3168 pos = r->position() + distance;
3170 distance = r->last_frame() - position;
3171 pos = r->position() - distance;
3177 pos = r->adjust_to_sync (position);
3178 if (pos > r->position()) {
3179 distance = pos - r->position();
3181 distance = r->position() - pos;
3187 if (pos == r->position()) {
3191 begin_reversible_command (_("align selection (relative)"));
3193 /* move first one specially */
3195 r->clear_changes ();
3196 r->set_position (pos);
3197 _session->add_command(new StatefulDiffCommand (r));
3199 /* move rest by the same amount */
3203 for (list<RegionView*>::iterator i = sorted.begin(); i != sorted.end(); ++i) {
3205 boost::shared_ptr<Region> region ((*i)->region());
3207 region->clear_changes ();
3210 region->set_position (region->position() + distance);
3212 region->set_position (region->position() - distance);
3215 _session->add_command(new StatefulDiffCommand (region));
3219 commit_reversible_command ();
3223 Editor::align_region (boost::shared_ptr<Region> region, RegionPoint point, framepos_t position)
3225 begin_reversible_command (_("align region"));
3226 align_region_internal (region, point, position);
3227 commit_reversible_command ();
3231 Editor::align_region_internal (boost::shared_ptr<Region> region, RegionPoint point, framepos_t position)
3233 region->clear_changes ();
3237 region->set_position (region->adjust_to_sync (position));
3241 if (position > region->length()) {
3242 region->set_position (position - region->length());
3247 region->set_position (position);
3251 _session->add_command(new StatefulDiffCommand (region));
3255 Editor::trim_region_front ()
3261 Editor::trim_region_back ()
3263 trim_region (false);
3267 Editor::trim_region (bool front)
3269 framepos_t where = get_preferred_edit_position();
3270 RegionSelection rs = get_regions_from_selection_and_edit_point ();
3276 begin_reversible_command (front ? _("trim front") : _("trim back"));
3278 for (list<RegionView*>::const_iterator i = rs.by_layer().begin(); i != rs.by_layer().end(); ++i) {
3279 if (!(*i)->region()->locked()) {
3281 (*i)->region()->clear_changes ();
3284 (*i)->region()->trim_front (where);
3285 maybe_locate_with_edit_preroll ( where );
3287 (*i)->region()->trim_end (where);
3288 maybe_locate_with_edit_preroll ( where );
3291 _session->add_command (new StatefulDiffCommand ((*i)->region()));
3295 commit_reversible_command ();
3298 /** Trim the end of the selected regions to the position of the edit cursor */
3300 Editor::trim_region_to_loop ()
3302 Location* loc = _session->locations()->auto_loop_location();
3306 trim_region_to_location (*loc, _("trim to loop"));
3310 Editor::trim_region_to_punch ()
3312 Location* loc = _session->locations()->auto_punch_location();
3316 trim_region_to_location (*loc, _("trim to punch"));
3320 Editor::trim_region_to_location (const Location& loc, const char* str)
3322 RegionSelection rs = get_regions_from_selection_and_entered ();
3324 begin_reversible_command (str);
3326 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
3327 RegionView* rv = (*x);
3329 /* require region to span proposed trim */
3330 switch (rv->region()->coverage (loc.start(), loc.end())) {
3331 case Evoral::OverlapInternal:
3337 RouteTimeAxisView* tav = dynamic_cast<RouteTimeAxisView*> (&rv->get_time_axis_view());
3346 if (tav->track() != 0) {
3347 speed = tav->track()->speed();
3350 start = session_frame_to_track_frame (loc.start(), speed);
3351 end = session_frame_to_track_frame (loc.end(), speed);
3353 rv->region()->clear_changes ();
3354 rv->region()->trim_to (start, (end - start));
3355 _session->add_command(new StatefulDiffCommand (rv->region()));
3358 commit_reversible_command ();
3362 Editor::trim_region_to_previous_region_end ()
3364 return trim_to_region(false);
3368 Editor::trim_region_to_next_region_start ()
3370 return trim_to_region(true);
3374 Editor::trim_to_region(bool forward)
3376 RegionSelection rs = get_regions_from_selection_and_entered ();
3378 begin_reversible_command (_("trim to region"));
3380 boost::shared_ptr<Region> next_region;
3382 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
3384 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*x);
3390 AudioTimeAxisView* atav = dynamic_cast<AudioTimeAxisView*> (&arv->get_time_axis_view());
3398 if (atav->track() != 0) {
3399 speed = atav->track()->speed();
3403 boost::shared_ptr<Region> region = arv->region();
3404 boost::shared_ptr<Playlist> playlist (region->playlist());
3406 region->clear_changes ();
3410 next_region = playlist->find_next_region (region->first_frame(), Start, 1);
3416 region->trim_end((framepos_t) ( (next_region->first_frame() - 1) * speed));
3417 arv->region_changed (PropertyChange (ARDOUR::Properties::length));
3421 next_region = playlist->find_next_region (region->first_frame(), Start, 0);
3427 region->trim_front((framepos_t) ((next_region->last_frame() + 1) * speed));
3429 arv->region_changed (ARDOUR::bounds_change);
3432 _session->add_command(new StatefulDiffCommand (region));
3435 commit_reversible_command ();
3439 Editor::unfreeze_route ()
3441 if (clicked_routeview == 0 || !clicked_routeview->is_track()) {
3445 clicked_routeview->track()->unfreeze ();
3449 Editor::_freeze_thread (void* arg)
3451 return static_cast<Editor*>(arg)->freeze_thread ();
3455 Editor::freeze_thread ()
3457 /* create event pool because we may need to talk to the session */
3458 SessionEvent::create_per_thread_pool ("freeze events", 64);
3459 /* create per-thread buffers for process() tree to use */
3460 current_interthread_info->process_thread.get_buffers ();
3461 clicked_routeview->audio_track()->freeze_me (*current_interthread_info);
3462 current_interthread_info->done = true;
3463 current_interthread_info->process_thread.drop_buffers();
3468 Editor::freeze_route ()
3474 /* stop transport before we start. this is important */
3476 _session->request_transport_speed (0.0);
3478 /* wait for just a little while, because the above call is asynchronous */
3480 Glib::usleep (250000);
3482 if (clicked_routeview == 0 || !clicked_routeview->is_audio_track()) {
3486 if (!clicked_routeview->track()->bounceable (clicked_routeview->track()->main_outs(), true)) {
3488 _("This track/bus cannot be frozen because the signal adds or loses channels before reaching the outputs.\n"
3489 "This is typically caused by plugins that generate stereo output from mono input or vice versa.")
3491 d.set_title (_("Cannot freeze"));
3496 if (clicked_routeview->track()->has_external_redirects()) {
3497 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"
3498 "Freezing will only process the signal as far as the first send/insert/return."),
3499 clicked_routeview->track()->name()), true, MESSAGE_INFO, BUTTONS_NONE, true);
3501 d.add_button (_("Freeze anyway"), Gtk::RESPONSE_OK);
3502 d.add_button (_("Don't freeze"), Gtk::RESPONSE_CANCEL);
3503 d.set_title (_("Freeze Limits"));
3505 int response = d.run ();
3508 case Gtk::RESPONSE_CANCEL:
3515 InterThreadInfo itt;
3516 current_interthread_info = &itt;
3518 InterthreadProgressWindow ipw (current_interthread_info, _("Freeze"), _("Cancel Freeze"));
3520 pthread_create_and_store (X_("freezer"), &itt.thread, _freeze_thread, this);
3522 set_canvas_cursor (_cursors->wait);
3524 while (!itt.done && !itt.cancel) {
3525 gtk_main_iteration ();
3528 current_interthread_info = 0;
3529 set_canvas_cursor (current_canvas_cursor);
3533 Editor::bounce_range_selection (bool replace, bool enable_processing)
3535 if (selection->time.empty()) {
3539 TrackSelection views = selection->tracks;
3541 for (TrackViewList::iterator i = views.begin(); i != views.end(); ++i) {
3543 if (enable_processing) {
3545 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*i);
3547 if (rtv && rtv->track() && replace && enable_processing && !rtv->track()->bounceable (rtv->track()->main_outs(), false)) {
3549 _("You can't perform this operation because the processing of the signal "
3550 "will cause one or more of the tracks to end up with a region with more channels than this track has inputs.\n\n"
3551 "You can do this without processing, which is a different operation.")
3553 d.set_title (_("Cannot bounce"));
3560 framepos_t start = selection->time[clicked_selection].start;
3561 framepos_t end = selection->time[clicked_selection].end;
3562 framepos_t cnt = end - start + 1;
3564 begin_reversible_command (_("bounce range"));
3566 for (TrackViewList::iterator i = views.begin(); i != views.end(); ++i) {
3568 RouteTimeAxisView* rtv;
3570 if ((rtv = dynamic_cast<RouteTimeAxisView*> (*i)) == 0) {
3574 boost::shared_ptr<Playlist> playlist;
3576 if ((playlist = rtv->playlist()) == 0) {
3580 InterThreadInfo itt;
3582 playlist->clear_changes ();
3583 playlist->clear_owned_changes ();
3585 boost::shared_ptr<Region> r;
3587 if (enable_processing) {
3588 r = rtv->track()->bounce_range (start, start+cnt, itt, rtv->track()->main_outs(), false);
3590 r = rtv->track()->bounce_range (start, start+cnt, itt, boost::shared_ptr<Processor>(), false);
3598 list<AudioRange> ranges;
3599 ranges.push_back (AudioRange (start, start+cnt, 0));
3600 playlist->cut (ranges); // discard result
3601 playlist->add_region (r, start);
3604 vector<Command*> cmds;
3605 playlist->rdiff (cmds);
3606 _session->add_commands (cmds);
3608 _session->add_command (new StatefulDiffCommand (playlist));
3611 commit_reversible_command ();
3614 /** Delete selected regions, automation points or a time range */
3621 /** Cut selected regions, automation points or a time range */
3628 /** Copy selected regions, automation points or a time range */
3636 /** @return true if a Cut, Copy or Clear is possible */
3638 Editor::can_cut_copy () const
3640 switch (effective_mouse_mode()) {
3643 if (!selection->regions.empty() || !selection->points.empty()) {
3649 if (!selection->time.empty()) {
3662 /** Cut, copy or clear selected regions, automation points or a time range.
3663 * @param op Operation (Cut, Copy or Clear)
3666 Editor::cut_copy (CutCopyOp op)
3668 /* only cancel selection if cut/copy is successful.*/
3674 opname = _("delete");
3683 opname = _("clear");
3687 /* if we're deleting something, and the mouse is still pressed,
3688 the thing we started a drag for will be gone when we release
3689 the mouse button(s). avoid this. see part 2 at the end of
3693 if (op == Delete || op == Cut || op == Clear) {
3694 if (_drags->active ()) {
3699 if ( op != Clear ) //"Delete" doesn't change copy/paste buf
3700 cut_buffer->clear ();
3702 if (entered_marker) {
3704 /* cut/delete op while pointing at a marker */
3707 Location* loc = find_location_from_marker (entered_marker, ignored);
3709 if (_session && loc) {
3710 Glib::signal_idle().connect (sigc::bind (sigc::mem_fun(*this, &Editor::really_remove_marker), loc));
3717 if (internal_editing()) {
3719 switch (effective_mouse_mode()) {
3732 /* we only want to cut regions if some are selected */
3734 if (!selection->regions.empty()) {
3735 rs = selection->regions;
3738 switch (effective_mouse_mode()) {
3741 //find regions's gain line
3742 AudioRegionView *rview = dynamic_cast<AudioRegionView*>(clicked_regionview);
3743 AutomationTimeAxisView *tview = dynamic_cast<AutomationTimeAxisView*>(clicked_trackview);
3745 AudioRegionGainLine *line = rview->get_gain_line();
3748 //cut region gain points in the selection
3749 AutomationList& alist (line->the_list());
3750 XMLNode &before = alist.get_state();
3751 AutomationList* what_we_got = 0;
3752 if ((what_we_got = alist.cut (selection->time.front().start - rview->audio_region()->position(), selection->time.front().end - rview->audio_region()->position())) != 0) {
3753 session->add_command(new MementoCommand<AutomationList>(alist, &before, &alist.get_state()));
3758 rview->set_envelope_visible(true);
3759 rview->audio_region()->set_envelope_active(true);
3762 AutomationLine *line = *(tview->lines.begin());
3765 //cut auto points in the selection
3766 AutomationList& alist (line->the_list());
3767 XMLNode &before = alist.get_state();
3768 AutomationList* what_we_got = 0;
3769 if ((what_we_got = alist.cut (selection->time.front().start, selection->time.front().end)) != 0) {
3770 session->add_command(new MementoCommand<AutomationList>(alist, &before, &alist.get_state()));
3780 if (!rs.empty() || !selection->points.empty()) {
3781 begin_reversible_command (opname + _(" objects"));
3784 cut_copy_regions (op, rs);
3786 if (op == Cut || op == Delete) {
3787 selection->clear_regions ();
3791 if (!selection->points.empty()) {
3792 cut_copy_points (op);
3794 if (op == Cut || op == Delete) {
3795 selection->clear_points ();
3799 commit_reversible_command ();
3803 if (selection->time.empty()) {
3804 framepos_t start, end;
3805 if (!get_edit_op_range (start, end)) {
3808 selection->set (start, end);
3811 begin_reversible_command (opname + _(" range"));
3812 cut_copy_ranges (op);
3813 commit_reversible_command ();
3815 if (op == Cut || op == Delete) {
3816 selection->clear_time ();
3826 if (op == Delete || op == Cut || op == Clear) {
3831 struct AutomationRecord {
3832 AutomationRecord () : state (0) {}
3833 AutomationRecord (XMLNode* s) : state (s) {}
3835 XMLNode* state; ///< state before any operation
3836 boost::shared_ptr<Evoral::ControlList> copy; ///< copied events for the cut buffer
3839 /** Cut, copy or clear selected automation points.
3840 * @param op Operation (Cut, Copy or Clear)
3843 Editor::cut_copy_points (CutCopyOp op)
3845 if (selection->points.empty ()) {
3849 /* XXX: not ideal, as there may be more than one track involved in the point selection */
3850 _last_cut_copy_source_track = &selection->points.front()->line().trackview;
3852 /* Keep a record of the AutomationLists that we end up using in this operation */
3853 typedef std::map<boost::shared_ptr<AutomationList>, AutomationRecord> Lists;
3856 /* Go through all selected points, making an AutomationRecord for each distinct AutomationList */
3857 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
3858 boost::shared_ptr<AutomationList> al = (*i)->line().the_list();
3859 if (lists.find (al) == lists.end ()) {
3860 /* We haven't seen this list yet, so make a record for it. This includes
3861 taking a copy of its current state, in case this is needed for undo later.
3863 lists[al] = AutomationRecord (&al->get_state ());
3867 if (op == Cut || op == Copy) {
3868 /* This operation will involve putting things in the cut buffer, so create an empty
3869 ControlList for each of our source lists to put the cut buffer data in.
3871 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
3872 i->second.copy = i->first->create (i->first->parameter ());
3875 /* Add all selected points to the relevant copy ControlLists */
3876 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
3877 boost::shared_ptr<AutomationList> al = (*i)->line().the_list();
3878 AutomationList::const_iterator j = (*i)->model ();
3879 lists[al].copy->add ((*j)->when, (*j)->value);
3882 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
3883 /* Correct this copy list so that it starts at time 0 */
3884 double const start = i->second.copy->front()->when;
3885 for (AutomationList::iterator j = i->second.copy->begin(); j != i->second.copy->end(); ++j) {
3886 (*j)->when -= start;
3889 /* And add it to the cut buffer */
3890 cut_buffer->add (i->second.copy);
3894 if (op == Delete || op == Cut) {
3895 /* This operation needs to remove things from the main AutomationList, so do that now */
3897 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
3898 i->first->freeze ();
3901 /* Remove each selected point from its AutomationList */
3902 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
3903 boost::shared_ptr<AutomationList> al = (*i)->line().the_list();
3904 al->erase ((*i)->model ());
3907 /* Thaw the lists and add undo records for them */
3908 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
3909 boost::shared_ptr<AutomationList> al = i->first;
3911 _session->add_command (new MementoCommand<AutomationList> (*al.get(), i->second.state, &(al->get_state ())));
3916 /** Cut, copy or clear selected automation points.
3917 * @param op Operation (Cut, Copy or Clear)
3920 Editor::cut_copy_midi (CutCopyOp op)
3922 for (MidiRegionSelection::iterator i = selection->midi_regions.begin(); i != selection->midi_regions.end(); ++i) {
3923 MidiRegionView* mrv = *i;
3924 mrv->cut_copy_clear (op);
3930 struct lt_playlist {
3931 bool operator () (const PlaylistState& a, const PlaylistState& b) {
3932 return a.playlist < b.playlist;
3936 struct PlaylistMapping {
3938 boost::shared_ptr<Playlist> pl;
3940 PlaylistMapping (TimeAxisView* tvp) : tv (tvp) {}
3943 /** Remove `clicked_regionview' */
3945 Editor::remove_clicked_region ()
3947 if (clicked_routeview == 0 || clicked_regionview == 0) {
3951 boost::shared_ptr<Playlist> playlist = clicked_routeview->playlist();
3953 begin_reversible_command (_("remove region"));
3954 playlist->clear_changes ();
3955 playlist->clear_owned_changes ();
3956 playlist->remove_region (clicked_regionview->region());
3958 /* We might have removed regions, which alters other regions' layering_index,
3959 so we need to do a recursive diff here.
3961 vector<Command*> cmds;
3962 playlist->rdiff (cmds);
3963 _session->add_commands (cmds);
3965 _session->add_command(new StatefulDiffCommand (playlist));
3966 commit_reversible_command ();
3970 /** Remove the selected regions */
3972 Editor::remove_selected_regions ()
3974 RegionSelection rs = get_regions_from_selection_and_entered ();
3976 if (!_session || rs.empty()) {
3980 begin_reversible_command (_("remove region"));
3982 list<boost::shared_ptr<Region> > regions_to_remove;
3984 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3985 // we can't just remove the region(s) in this loop because
3986 // this removes them from the RegionSelection, and they thus
3987 // disappear from underneath the iterator, and the ++i above
3988 // SEGVs in a puzzling fashion.
3990 // so, first iterate over the regions to be removed from rs and
3991 // add them to the regions_to_remove list, and then
3992 // iterate over the list to actually remove them.
3994 regions_to_remove.push_back ((*i)->region());
3997 vector<boost::shared_ptr<Playlist> > playlists;
3999 for (list<boost::shared_ptr<Region> >::iterator rl = regions_to_remove.begin(); rl != regions_to_remove.end(); ++rl) {
4001 boost::shared_ptr<Playlist> playlist = (*rl)->playlist();
4004 // is this check necessary?
4008 /* get_regions_from_selection_and_entered() guarantees that
4009 the playlists involved are unique, so there is no need
4013 playlists.push_back (playlist);
4015 playlist->clear_changes ();
4016 playlist->clear_owned_changes ();
4017 playlist->freeze ();
4018 playlist->remove_region (*rl);
4021 vector<boost::shared_ptr<Playlist> >::iterator pl;
4023 for (pl = playlists.begin(); pl != playlists.end(); ++pl) {
4026 /* We might have removed regions, which alters other regions' layering_index,
4027 so we need to do a recursive diff here.
4029 vector<Command*> cmds;
4030 (*pl)->rdiff (cmds);
4031 _session->add_commands (cmds);
4033 _session->add_command(new StatefulDiffCommand (*pl));
4036 commit_reversible_command ();
4039 /** Cut, copy or clear selected regions.
4040 * @param op Operation (Cut, Copy or Clear)
4043 Editor::cut_copy_regions (CutCopyOp op, RegionSelection& rs)
4045 /* we can't use a std::map here because the ordering is important, and we can't trivially sort
4046 a map when we want ordered access to both elements. i think.
4049 vector<PlaylistMapping> pmap;
4051 framepos_t first_position = max_framepos;
4053 typedef set<boost::shared_ptr<Playlist> > FreezeList;
4054 FreezeList freezelist;
4056 /* get ordering correct before we cut/copy */
4058 rs.sort_by_position_and_track ();
4060 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
4062 first_position = min ((framepos_t) (*x)->region()->position(), first_position);
4064 if (op == Cut || op == Clear || op == Delete) {
4065 boost::shared_ptr<Playlist> pl = (*x)->region()->playlist();
4068 FreezeList::iterator fl;
4070 // only take state if this is a new playlist.
4071 for (fl = freezelist.begin(); fl != freezelist.end(); ++fl) {
4077 if (fl == freezelist.end()) {
4078 pl->clear_changes();
4079 pl->clear_owned_changes ();
4081 freezelist.insert (pl);
4086 TimeAxisView* tv = &(*x)->get_time_axis_view();
4087 vector<PlaylistMapping>::iterator z;
4089 for (z = pmap.begin(); z != pmap.end(); ++z) {
4090 if ((*z).tv == tv) {
4095 if (z == pmap.end()) {
4096 pmap.push_back (PlaylistMapping (tv));
4100 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ) {
4102 boost::shared_ptr<Playlist> pl = (*x)->region()->playlist();
4105 /* region not yet associated with a playlist (e.g. unfinished
4112 TimeAxisView& tv = (*x)->get_time_axis_view();
4113 boost::shared_ptr<Playlist> npl;
4114 RegionSelection::iterator tmp;
4121 vector<PlaylistMapping>::iterator z;
4123 for (z = pmap.begin(); z != pmap.end(); ++z) {
4124 if ((*z).tv == &tv) {
4129 assert (z != pmap.end());
4132 npl = PlaylistFactory::create (pl->data_type(), *_session, "cutlist", true);
4140 boost::shared_ptr<Region> r = (*x)->region();
4141 boost::shared_ptr<Region> _xx;
4147 pl->remove_region (r);
4151 _xx = RegionFactory::create (r);
4152 npl->add_region (_xx, r->position() - first_position);
4153 pl->remove_region (r);
4157 /* copy region before adding, so we're not putting same object into two different playlists */
4158 npl->add_region (RegionFactory::create (r), r->position() - first_position);
4162 pl->remove_region (r);
4171 list<boost::shared_ptr<Playlist> > foo;
4173 /* the pmap is in the same order as the tracks in which selected regions occured */
4175 for (vector<PlaylistMapping>::iterator i = pmap.begin(); i != pmap.end(); ++i) {
4178 foo.push_back ((*i).pl);
4183 cut_buffer->set (foo);
4187 _last_cut_copy_source_track = 0;
4189 _last_cut_copy_source_track = pmap.front().tv;
4193 for (FreezeList::iterator pl = freezelist.begin(); pl != freezelist.end(); ++pl) {
4196 /* We might have removed regions, which alters other regions' layering_index,
4197 so we need to do a recursive diff here.
4199 vector<Command*> cmds;
4200 (*pl)->rdiff (cmds);
4201 _session->add_commands (cmds);
4203 _session->add_command (new StatefulDiffCommand (*pl));
4208 Editor::cut_copy_ranges (CutCopyOp op)
4210 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4212 /* Sort the track selection now, so that it if is used, the playlists
4213 selected by the calls below to cut_copy_clear are in the order that
4214 their tracks appear in the editor. This makes things like paste
4215 of ranges work properly.
4218 sort_track_selection (ts);
4221 if (!entered_track) {
4224 ts.push_back (entered_track);
4227 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4228 (*i)->cut_copy_clear (*selection, op);
4233 Editor::paste (float times, bool from_context)
4235 DEBUG_TRACE (DEBUG::CutNPaste, "paste to preferred edit pos\n");
4237 paste_internal (get_preferred_edit_position (false, from_context), times);
4241 Editor::mouse_paste ()
4246 if (!mouse_frame (where, ignored)) {
4251 paste_internal (where, 1);
4255 Editor::paste_internal (framepos_t position, float times)
4257 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("apparent paste position is %1\n", position));
4259 if (internal_editing()) {
4260 if (cut_buffer->midi_notes.empty()) {
4264 if (cut_buffer->empty()) {
4269 if (position == max_framepos) {
4270 position = get_preferred_edit_position();
4271 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("preferred edit position is %1\n", position));
4275 TrackViewList::iterator i;
4278 /* get everything in the correct order */
4280 if (_edit_point == Editing::EditAtMouse && entered_track) {
4281 /* With the mouse edit point, paste onto the track under the mouse */
4282 ts.push_back (entered_track);
4283 } else if (!selection->tracks.empty()) {
4284 /* Otherwise, if there are some selected tracks, paste to them */
4285 ts = selection->tracks.filter_to_unique_playlists ();
4286 sort_track_selection (ts);
4287 } else if (_last_cut_copy_source_track) {
4288 /* Otherwise paste to the track that the cut/copy came from;
4289 see discussion in mantis #3333.
4291 ts.push_back (_last_cut_copy_source_track);
4294 if (internal_editing ()) {
4296 /* undo/redo is handled by individual tracks/regions */
4298 for (nth = 0, i = ts.begin(); i != ts.end(); ++i, ++nth) {
4301 RegionSelection::iterator r;
4302 MidiNoteSelection::iterator cb;
4304 get_regions_at (rs, position, ts);
4306 for (cb = cut_buffer->midi_notes.begin(), r = rs.begin();
4307 cb != cut_buffer->midi_notes.end() && r != rs.end(); ++r) {
4308 MidiRegionView* mrv = dynamic_cast<MidiRegionView*> (*r);
4310 mrv->paste (position, times, **cb);
4318 /* we do redo (do you do voodoo?) */
4320 begin_reversible_command (Operations::paste);
4322 for (nth = 0, i = ts.begin(); i != ts.end(); ++i, ++nth) {
4323 (*i)->paste (position, times, *cut_buffer, nth);
4326 commit_reversible_command ();
4331 Editor::duplicate_some_regions (RegionSelection& regions, float times)
4333 boost::shared_ptr<Playlist> playlist;
4334 RegionSelection sel = regions; // clear (below) may clear the argument list if its the current region selection
4335 RegionSelection foo;
4337 framepos_t const start_frame = regions.start ();
4338 framepos_t const end_frame = regions.end_frame ();
4340 begin_reversible_command (Operations::duplicate_region);
4342 selection->clear_regions ();
4344 for (RegionSelection::iterator i = sel.begin(); i != sel.end(); ++i) {
4346 boost::shared_ptr<Region> r ((*i)->region());
4348 TimeAxisView& tv = (*i)->get_time_axis_view();
4349 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (&tv);
4350 latest_regionviews.clear ();
4351 sigc::connection c = rtv->view()->RegionViewAdded.connect (sigc::mem_fun(*this, &Editor::collect_new_region_view));
4353 playlist = (*i)->region()->playlist();
4354 playlist->clear_changes ();
4355 playlist->duplicate (r, end_frame + (r->first_frame() - start_frame), times);
4356 _session->add_command(new StatefulDiffCommand (playlist));
4360 foo.insert (foo.end(), latest_regionviews.begin(), latest_regionviews.end());
4363 commit_reversible_command ();
4366 selection->set (foo);
4371 Editor::duplicate_selection (float times)
4373 if (selection->time.empty() || selection->tracks.empty()) {
4377 boost::shared_ptr<Playlist> playlist;
4378 vector<boost::shared_ptr<Region> > new_regions;
4379 vector<boost::shared_ptr<Region> >::iterator ri;
4381 create_region_from_selection (new_regions);
4383 if (new_regions.empty()) {
4387 begin_reversible_command (_("duplicate selection"));
4389 ri = new_regions.begin();
4391 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4393 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4394 if ((playlist = (*i)->playlist()) == 0) {
4397 playlist->clear_changes ();
4398 playlist->duplicate (*ri, selection->time[clicked_selection].end, times);
4399 _session->add_command (new StatefulDiffCommand (playlist));
4402 if (ri == new_regions.end()) {
4407 commit_reversible_command ();
4410 /** Reset all selected points to the relevant default value */
4412 Editor::reset_point_selection ()
4414 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
4415 ARDOUR::AutomationList::iterator j = (*i)->model ();
4416 (*j)->value = (*i)->line().the_list()->default_value ();
4421 Editor::center_playhead ()
4423 float const page = _visible_canvas_width * samples_per_pixel;
4424 center_screen_internal (playhead_cursor->current_frame (), page);
4428 Editor::center_edit_point ()
4430 float const page = _visible_canvas_width * samples_per_pixel;
4431 center_screen_internal (get_preferred_edit_position(), page);
4434 /** Caller must begin and commit a reversible command */
4436 Editor::clear_playlist (boost::shared_ptr<Playlist> playlist)
4438 playlist->clear_changes ();
4440 _session->add_command (new StatefulDiffCommand (playlist));
4444 Editor::nudge_track (bool use_edit, bool forwards)
4446 boost::shared_ptr<Playlist> playlist;
4447 framepos_t distance;
4448 framepos_t next_distance;
4452 start = get_preferred_edit_position();
4457 if ((distance = get_nudge_distance (start, next_distance)) == 0) {
4461 if (selection->tracks.empty()) {
4465 begin_reversible_command (_("nudge track"));
4467 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4469 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4471 if ((playlist = (*i)->playlist()) == 0) {
4475 playlist->clear_changes ();
4476 playlist->clear_owned_changes ();
4478 playlist->nudge_after (start, distance, forwards);
4480 vector<Command*> cmds;
4482 playlist->rdiff (cmds);
4483 _session->add_commands (cmds);
4485 _session->add_command (new StatefulDiffCommand (playlist));
4488 commit_reversible_command ();
4492 Editor::remove_last_capture ()
4494 vector<string> choices;
4501 if (Config->get_verify_remove_last_capture()) {
4502 prompt = _("Do you really want to destroy the last capture?"
4503 "\n(This is destructive and cannot be undone)");
4505 choices.push_back (_("No, do nothing."));
4506 choices.push_back (_("Yes, destroy it."));
4508 Gtkmm2ext::Choice prompter (_("Destroy last capture"), prompt, choices);
4510 if (prompter.run () == 1) {
4511 _session->remove_last_capture ();
4512 _regions->redisplay ();
4516 _session->remove_last_capture();
4517 _regions->redisplay ();
4522 Editor::normalize_region ()
4528 RegionSelection rs = get_regions_from_selection_and_entered ();
4534 NormalizeDialog dialog (rs.size() > 1);
4536 if (dialog.run () == RESPONSE_CANCEL) {
4540 set_canvas_cursor (_cursors->wait);
4543 /* XXX: should really only count audio regions here */
4544 int const regions = rs.size ();
4546 /* Make a list of the selected audio regions' maximum amplitudes, and also
4547 obtain the maximum amplitude of them all.
4549 list<double> max_amps;
4551 for (RegionSelection::const_iterator i = rs.begin(); i != rs.end(); ++i) {
4552 AudioRegionView const * arv = dynamic_cast<AudioRegionView const *> (*i);
4554 dialog.descend (1.0 / regions);
4555 double const a = arv->audio_region()->maximum_amplitude (&dialog);
4558 /* the user cancelled the operation */
4559 set_canvas_cursor (current_canvas_cursor);
4563 max_amps.push_back (a);
4564 max_amp = max (max_amp, a);
4569 begin_reversible_command (_("normalize"));
4571 list<double>::const_iterator a = max_amps.begin ();
4573 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
4574 AudioRegionView* const arv = dynamic_cast<AudioRegionView*> (*r);
4579 arv->region()->clear_changes ();
4581 double const amp = dialog.normalize_individually() ? *a : max_amp;
4583 arv->audio_region()->normalize (amp, dialog.target ());
4584 _session->add_command (new StatefulDiffCommand (arv->region()));
4589 commit_reversible_command ();
4590 set_canvas_cursor (current_canvas_cursor);
4595 Editor::reset_region_scale_amplitude ()
4601 RegionSelection rs = get_regions_from_selection_and_entered ();
4607 begin_reversible_command ("reset gain");
4609 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
4610 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
4613 arv->region()->clear_changes ();
4614 arv->audio_region()->set_scale_amplitude (1.0f);
4615 _session->add_command (new StatefulDiffCommand (arv->region()));
4618 commit_reversible_command ();
4622 Editor::adjust_region_gain (bool up)
4624 RegionSelection rs = get_regions_from_selection_and_entered ();
4626 if (!_session || rs.empty()) {
4630 begin_reversible_command ("adjust region gain");
4632 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
4633 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
4638 arv->region()->clear_changes ();
4640 double dB = accurate_coefficient_to_dB (arv->audio_region()->scale_amplitude ());
4648 arv->audio_region()->set_scale_amplitude (dB_to_coefficient (dB));
4649 _session->add_command (new StatefulDiffCommand (arv->region()));
4652 commit_reversible_command ();
4657 Editor::reverse_region ()
4663 Reverse rev (*_session);
4664 apply_filter (rev, _("reverse regions"));
4668 Editor::strip_region_silence ()
4674 RegionSelection rs = get_regions_from_selection_and_entered ();
4680 std::list<RegionView*> audio_only;
4682 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
4683 AudioRegionView* const arv = dynamic_cast<AudioRegionView*> (*i);
4685 audio_only.push_back (arv);
4689 StripSilenceDialog d (_session, audio_only);
4690 int const r = d.run ();
4694 if (r == Gtk::RESPONSE_OK) {
4695 ARDOUR::AudioIntervalMap silences;
4696 d.silences (silences);
4697 StripSilence s (*_session, silences, d.fade_length());
4698 apply_filter (s, _("strip silence"), &d);
4703 Editor::apply_midi_note_edit_op_to_region (MidiOperator& op, MidiRegionView& mrv)
4705 Evoral::Sequence<Evoral::MusicalTime>::Notes selected;
4706 mrv.selection_as_notelist (selected, true);
4708 vector<Evoral::Sequence<Evoral::MusicalTime>::Notes> v;
4709 v.push_back (selected);
4711 framepos_t pos_frames = mrv.midi_region()->position() - mrv.midi_region()->start();
4712 double pos_beats = _session->tempo_map().framewalk_to_beats(0, pos_frames);
4714 return op (mrv.midi_region()->model(), pos_beats, v);
4718 Editor::apply_midi_note_edit_op (MidiOperator& op)
4722 RegionSelection rs = get_regions_from_selection_and_entered ();
4728 begin_reversible_command (op.name ());
4730 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
4731 RegionSelection::iterator tmp = r;
4734 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*r);
4737 cmd = apply_midi_note_edit_op_to_region (op, *mrv);
4740 _session->add_command (cmd);
4747 commit_reversible_command ();
4751 Editor::fork_region ()
4753 RegionSelection rs = get_regions_from_selection_and_entered ();
4759 begin_reversible_command (_("Fork Region(s)"));
4761 set_canvas_cursor (_cursors->wait);
4764 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
4765 RegionSelection::iterator tmp = r;
4768 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*>(*r);
4771 boost::shared_ptr<Playlist> playlist = mrv->region()->playlist();
4772 boost::shared_ptr<MidiRegion> newregion = mrv->midi_region()->clone ();
4774 playlist->clear_changes ();
4775 playlist->replace_region (mrv->region(), newregion, mrv->region()->position());
4776 _session->add_command(new StatefulDiffCommand (playlist));
4782 commit_reversible_command ();
4784 set_canvas_cursor (current_canvas_cursor);
4788 Editor::quantize_region ()
4790 int selected_midi_region_cnt = 0;
4796 RegionSelection rs = get_regions_from_selection_and_entered ();
4802 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
4803 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*r);
4805 selected_midi_region_cnt++;
4809 if (selected_midi_region_cnt == 0) {
4813 QuantizeDialog* qd = new QuantizeDialog (*this);
4816 const int r = qd->run ();
4819 if (r == Gtk::RESPONSE_OK) {
4820 Quantize quant (*_session, qd->snap_start(), qd->snap_end(),
4821 qd->start_grid_size(), qd->end_grid_size(),
4822 qd->strength(), qd->swing(), qd->threshold());
4824 apply_midi_note_edit_op (quant);
4829 Editor::insert_patch_change (bool from_context)
4831 RegionSelection rs = get_regions_from_selection_and_entered ();
4837 const framepos_t p = get_preferred_edit_position (false, from_context);
4839 /* XXX: bit of a hack; use the MIDNAM from the first selected region;
4840 there may be more than one, but the PatchChangeDialog can only offer
4841 one set of patch menus.
4843 MidiRegionView* first = dynamic_cast<MidiRegionView*> (rs.front ());
4845 Evoral::PatchChange<Evoral::MusicalTime> empty (0, 0, 0, 0);
4846 PatchChangeDialog d (0, _session, empty, first->instrument_info(), Gtk::Stock::ADD);
4848 if (d.run() == RESPONSE_CANCEL) {
4852 for (RegionSelection::iterator i = rs.begin (); i != rs.end(); ++i) {
4853 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*i);
4855 if (p >= mrv->region()->first_frame() && p <= mrv->region()->last_frame()) {
4856 mrv->add_patch_change (p - mrv->region()->position(), d.patch ());
4863 Editor::apply_filter (Filter& filter, string command, ProgressReporter* progress)
4865 RegionSelection rs = get_regions_from_selection_and_entered ();
4871 begin_reversible_command (command);
4873 set_canvas_cursor (_cursors->wait);
4877 int const N = rs.size ();
4879 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
4880 RegionSelection::iterator tmp = r;
4883 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
4885 boost::shared_ptr<Playlist> playlist = arv->region()->playlist();
4888 progress->descend (1.0 / N);
4891 if (arv->audio_region()->apply (filter, progress) == 0) {
4893 playlist->clear_changes ();
4894 playlist->clear_owned_changes ();
4896 if (filter.results.empty ()) {
4898 /* no regions returned; remove the old one */
4899 playlist->remove_region (arv->region ());
4903 std::vector<boost::shared_ptr<Region> >::iterator res = filter.results.begin ();
4905 /* first region replaces the old one */
4906 playlist->replace_region (arv->region(), *res, (*res)->position());
4910 while (res != filter.results.end()) {
4911 playlist->add_region (*res, (*res)->position());
4917 /* We might have removed regions, which alters other regions' layering_index,
4918 so we need to do a recursive diff here.
4920 vector<Command*> cmds;
4921 playlist->rdiff (cmds);
4922 _session->add_commands (cmds);
4924 _session->add_command(new StatefulDiffCommand (playlist));
4930 progress->ascend ();
4938 commit_reversible_command ();
4941 set_canvas_cursor (current_canvas_cursor);
4945 Editor::external_edit_region ()
4951 Editor::reset_region_gain_envelopes ()
4953 RegionSelection rs = get_regions_from_selection_and_entered ();
4955 if (!_session || rs.empty()) {
4959 _session->begin_reversible_command (_("reset region gain"));
4961 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
4962 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
4964 boost::shared_ptr<AutomationList> alist (arv->audio_region()->envelope());
4965 XMLNode& before (alist->get_state());
4967 arv->audio_region()->set_default_envelope ();
4968 _session->add_command (new MementoCommand<AutomationList>(*arv->audio_region()->envelope().get(), &before, &alist->get_state()));
4972 _session->commit_reversible_command ();
4976 Editor::set_region_gain_visibility (RegionView* rv)
4978 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (rv);
4980 arv->update_envelope_visibility();
4985 Editor::set_gain_envelope_visibility ()
4991 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4992 AudioTimeAxisView* v = dynamic_cast<AudioTimeAxisView*>(*i);
4994 v->audio_view()->foreach_regionview (sigc::mem_fun (this, &Editor::set_region_gain_visibility));
5000 Editor::toggle_gain_envelope_active ()
5002 if (_ignore_region_action) {
5006 RegionSelection rs = get_regions_from_selection_and_entered ();
5008 if (!_session || rs.empty()) {
5012 _session->begin_reversible_command (_("region gain envelope active"));
5014 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5015 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
5017 arv->region()->clear_changes ();
5018 arv->audio_region()->set_envelope_active (!arv->audio_region()->envelope_active());
5019 _session->add_command (new StatefulDiffCommand (arv->region()));
5023 _session->commit_reversible_command ();
5027 Editor::toggle_region_lock ()
5029 if (_ignore_region_action) {
5033 RegionSelection rs = get_regions_from_selection_and_entered ();
5035 if (!_session || rs.empty()) {
5039 _session->begin_reversible_command (_("toggle region lock"));
5041 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5042 (*i)->region()->clear_changes ();
5043 (*i)->region()->set_locked (!(*i)->region()->locked());
5044 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5047 _session->commit_reversible_command ();
5051 Editor::toggle_region_video_lock ()
5053 if (_ignore_region_action) {
5057 RegionSelection rs = get_regions_from_selection_and_entered ();
5059 if (!_session || rs.empty()) {
5063 _session->begin_reversible_command (_("Toggle Video Lock"));
5065 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5066 (*i)->region()->clear_changes ();
5067 (*i)->region()->set_video_locked (!(*i)->region()->video_locked());
5068 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5071 _session->commit_reversible_command ();
5075 Editor::toggle_region_lock_style ()
5077 if (_ignore_region_action) {
5081 RegionSelection rs = get_regions_from_selection_and_entered ();
5083 if (!_session || rs.empty()) {
5087 _session->begin_reversible_command (_("region lock style"));
5089 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5090 (*i)->region()->clear_changes ();
5091 PositionLockStyle const ns = (*i)->region()->position_lock_style() == AudioTime ? MusicTime : AudioTime;
5092 (*i)->region()->set_position_lock_style (ns);
5093 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5096 _session->commit_reversible_command ();
5100 Editor::toggle_opaque_region ()
5102 if (_ignore_region_action) {
5106 RegionSelection rs = get_regions_from_selection_and_entered ();
5108 if (!_session || rs.empty()) {
5112 _session->begin_reversible_command (_("change region opacity"));
5114 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5115 (*i)->region()->clear_changes ();
5116 (*i)->region()->set_opaque (!(*i)->region()->opaque());
5117 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5120 _session->commit_reversible_command ();
5124 Editor::toggle_record_enable ()
5126 bool new_state = false;
5128 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5129 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5132 if (!rtav->is_track())
5136 new_state = !rtav->track()->record_enabled();
5140 rtav->track()->set_record_enabled (new_state, this);
5145 Editor::toggle_solo ()
5147 bool new_state = false;
5149 boost::shared_ptr<RouteList> rl (new RouteList);
5151 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5152 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5159 new_state = !rtav->route()->soloed ();
5163 rl->push_back (rtav->route());
5166 _session->set_solo (rl, new_state, Session::rt_cleanup, true);
5170 Editor::toggle_mute ()
5172 bool new_state = false;
5174 boost::shared_ptr<RouteList> rl (new RouteList);
5176 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5177 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5184 new_state = !rtav->route()->muted();
5188 rl->push_back (rtav->route());
5191 _session->set_mute (rl, new_state, Session::rt_cleanup, true);
5195 Editor::toggle_solo_isolate ()
5200 Editor::set_fade_length (bool in)
5202 RegionSelection rs = get_regions_from_selection_and_entered ();
5208 /* we need a region to measure the offset from the start */
5210 RegionView* rv = rs.front ();
5212 framepos_t pos = get_preferred_edit_position();
5216 if (pos > rv->region()->last_frame() || pos < rv->region()->first_frame()) {
5217 /* edit point is outside the relevant region */
5222 if (pos <= rv->region()->position()) {
5226 len = pos - rv->region()->position();
5227 cmd = _("set fade in length");
5229 if (pos >= rv->region()->last_frame()) {
5233 len = rv->region()->last_frame() - pos;
5234 cmd = _("set fade out length");
5237 begin_reversible_command (cmd);
5239 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5240 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5246 boost::shared_ptr<AutomationList> alist;
5248 alist = tmp->audio_region()->fade_in();
5250 alist = tmp->audio_region()->fade_out();
5253 XMLNode &before = alist->get_state();
5256 tmp->audio_region()->set_fade_in_length (len);
5257 tmp->audio_region()->set_fade_in_active (true);
5259 tmp->audio_region()->set_fade_out_length (len);
5260 tmp->audio_region()->set_fade_out_active (true);
5263 XMLNode &after = alist->get_state();
5264 _session->add_command(new MementoCommand<AutomationList>(*alist, &before, &after));
5267 commit_reversible_command ();
5271 Editor::set_fade_in_shape (FadeShape shape)
5273 RegionSelection rs = get_regions_from_selection_and_entered ();
5279 begin_reversible_command (_("set fade in shape"));
5281 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5282 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5288 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_in();
5289 XMLNode &before = alist->get_state();
5291 tmp->audio_region()->set_fade_in_shape (shape);
5293 XMLNode &after = alist->get_state();
5294 _session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
5297 commit_reversible_command ();
5302 Editor::set_fade_out_shape (FadeShape shape)
5304 RegionSelection rs = get_regions_from_selection_and_entered ();
5310 begin_reversible_command (_("set fade out shape"));
5312 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5313 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5319 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_out();
5320 XMLNode &before = alist->get_state();
5322 tmp->audio_region()->set_fade_out_shape (shape);
5324 XMLNode &after = alist->get_state();
5325 _session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
5328 commit_reversible_command ();
5332 Editor::set_fade_in_active (bool yn)
5334 RegionSelection rs = get_regions_from_selection_and_entered ();
5340 begin_reversible_command (_("set fade in active"));
5342 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5343 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5350 boost::shared_ptr<AudioRegion> ar (tmp->audio_region());
5352 ar->clear_changes ();
5353 ar->set_fade_in_active (yn);
5354 _session->add_command (new StatefulDiffCommand (ar));
5357 commit_reversible_command ();
5361 Editor::set_fade_out_active (bool yn)
5363 RegionSelection rs = get_regions_from_selection_and_entered ();
5369 begin_reversible_command (_("set fade out active"));
5371 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5372 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5378 boost::shared_ptr<AudioRegion> ar (tmp->audio_region());
5380 ar->clear_changes ();
5381 ar->set_fade_out_active (yn);
5382 _session->add_command(new StatefulDiffCommand (ar));
5385 commit_reversible_command ();
5389 Editor::toggle_region_fades (int dir)
5391 if (_ignore_region_action) {
5395 boost::shared_ptr<AudioRegion> ar;
5398 RegionSelection rs = get_regions_from_selection_and_entered ();
5404 RegionSelection::iterator i;
5405 for (i = rs.begin(); i != rs.end(); ++i) {
5406 if ((ar = boost::dynamic_pointer_cast<AudioRegion>((*i)->region())) != 0) {
5408 yn = ar->fade_out_active ();
5410 yn = ar->fade_in_active ();
5416 if (i == rs.end()) {
5420 /* XXX should this undo-able? */
5422 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5423 if ((ar = boost::dynamic_pointer_cast<AudioRegion>((*i)->region())) == 0) {
5426 if (dir == 1 || dir == 0) {
5427 ar->set_fade_in_active (!yn);
5430 if (dir == -1 || dir == 0) {
5431 ar->set_fade_out_active (!yn);
5437 /** Update region fade visibility after its configuration has been changed */
5439 Editor::update_region_fade_visibility ()
5441 bool _fade_visibility = _session->config.get_show_region_fades ();
5443 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5444 AudioTimeAxisView* v = dynamic_cast<AudioTimeAxisView*>(*i);
5446 if (_fade_visibility) {
5447 v->audio_view()->show_all_fades ();
5449 v->audio_view()->hide_all_fades ();
5456 Editor::set_edit_point ()
5461 if (!mouse_frame (where, ignored)) {
5467 if (selection->markers.empty()) {
5469 mouse_add_new_marker (where);
5474 Location* loc = find_location_from_marker (selection->markers.front(), ignored);
5477 loc->move_to (where);
5483 Editor::set_playhead_cursor ()
5485 if (entered_marker) {
5486 _session->request_locate (entered_marker->position(), _session->transport_rolling());
5491 if (!mouse_frame (where, ignored)) {
5498 _session->request_locate (where, _session->transport_rolling());
5502 if ( Config->get_always_play_range() )
5503 cancel_time_selection();
5507 Editor::split_region ()
5509 if ( !selection->time.empty()) {
5510 separate_regions_between (selection->time);
5514 RegionSelection rs = get_regions_from_selection_and_edit_point ();
5516 framepos_t where = get_preferred_edit_position ();
5522 split_regions_at (where, rs);
5525 struct EditorOrderRouteSorter {
5526 bool operator() (boost::shared_ptr<Route> a, boost::shared_ptr<Route> b) {
5527 return a->order_key () < b->order_key ();
5532 Editor::select_next_route()
5534 if (selection->tracks.empty()) {
5535 selection->set (track_views.front());
5539 TimeAxisView* current = selection->tracks.front();
5543 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5544 if (*i == current) {
5546 if (i != track_views.end()) {
5549 current = (*(track_views.begin()));
5550 //selection->set (*(track_views.begin()));
5555 rui = dynamic_cast<RouteUI *>(current);
5556 } while ( current->hidden() || (rui != NULL && !rui->route()->active()));
5558 selection->set(current);
5560 ensure_track_visible(current);
5564 Editor::select_prev_route()
5566 if (selection->tracks.empty()) {
5567 selection->set (track_views.front());
5571 TimeAxisView* current = selection->tracks.front();
5575 for (TrackViewList::reverse_iterator i = track_views.rbegin(); i != track_views.rend(); ++i) {
5576 if (*i == current) {
5578 if (i != track_views.rend()) {
5581 current = *(track_views.rbegin());
5586 rui = dynamic_cast<RouteUI *>(current);
5587 } while ( current->hidden() || (rui != NULL && !rui->route()->active()));
5589 selection->set (current);
5591 ensure_track_visible(current);
5595 Editor::ensure_track_visible(TimeAxisView *track)
5597 if (track->hidden())
5600 double const current_view_min_y = vertical_adjustment.get_value();
5601 double const current_view_max_y = vertical_adjustment.get_value() + vertical_adjustment.get_page_size();
5603 double const track_min_y = track->y_position ();
5604 double const track_max_y = track->y_position () + track->effective_height ();
5606 if (track_min_y >= current_view_min_y &&
5607 track_max_y <= current_view_max_y) {
5613 if (track_min_y < current_view_min_y) {
5614 // Track is above the current view
5615 new_value = track_min_y;
5617 // Track is below the current view
5618 new_value = track->y_position () + track->effective_height() - vertical_adjustment.get_page_size();
5621 vertical_adjustment.set_value(new_value);
5625 Editor::set_loop_from_selection (bool play)
5627 if (_session == 0 || selection->time.empty()) {
5631 framepos_t start = selection->time[clicked_selection].start;
5632 framepos_t end = selection->time[clicked_selection].end;
5634 set_loop_range (start, end, _("set loop range from selection"));
5637 _session->request_play_loop (true);
5638 _session->request_locate (start, true);
5643 Editor::set_loop_from_edit_range (bool play)
5645 if (_session == 0) {
5652 if (!get_edit_op_range (start, end)) {
5656 set_loop_range (start, end, _("set loop range from edit range"));
5659 _session->request_play_loop (true);
5660 _session->request_locate (start, true);
5665 Editor::set_loop_from_region (bool play)
5667 framepos_t start = max_framepos;
5670 RegionSelection rs = get_regions_from_selection_and_entered ();
5676 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5677 if ((*i)->region()->position() < start) {
5678 start = (*i)->region()->position();
5680 if ((*i)->region()->last_frame() + 1 > end) {
5681 end = (*i)->region()->last_frame() + 1;
5685 set_loop_range (start, end, _("set loop range from region"));
5688 _session->request_play_loop (true);
5689 _session->request_locate (start, true);
5694 Editor::set_punch_from_selection ()
5696 if (_session == 0 || selection->time.empty()) {
5700 framepos_t start = selection->time[clicked_selection].start;
5701 framepos_t end = selection->time[clicked_selection].end;
5703 set_punch_range (start, end, _("set punch range from selection"));
5707 Editor::set_punch_from_edit_range ()
5709 if (_session == 0) {
5716 if (!get_edit_op_range (start, end)) {
5720 set_punch_range (start, end, _("set punch range from edit range"));
5724 Editor::set_punch_from_region ()
5726 framepos_t start = max_framepos;
5729 RegionSelection rs = get_regions_from_selection_and_entered ();
5735 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5736 if ((*i)->region()->position() < start) {
5737 start = (*i)->region()->position();
5739 if ((*i)->region()->last_frame() + 1 > end) {
5740 end = (*i)->region()->last_frame() + 1;
5744 set_punch_range (start, end, _("set punch range from region"));
5748 Editor::pitch_shift_region ()
5750 RegionSelection rs = get_regions_from_selection_and_entered ();
5752 RegionSelection audio_rs;
5753 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5754 if (dynamic_cast<AudioRegionView*> (*i)) {
5755 audio_rs.push_back (*i);
5759 if (audio_rs.empty()) {
5763 pitch_shift (audio_rs, 1.2);
5767 Editor::transpose_region ()
5769 RegionSelection rs = get_regions_from_selection_and_entered ();
5771 list<MidiRegionView*> midi_region_views;
5772 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5773 MidiRegionView* mrv = dynamic_cast<MidiRegionView*> (*i);
5775 midi_region_views.push_back (mrv);
5780 int const r = d.run ();
5781 if (r != RESPONSE_ACCEPT) {
5785 for (list<MidiRegionView*>::iterator i = midi_region_views.begin(); i != midi_region_views.end(); ++i) {
5786 (*i)->midi_region()->transpose (d.semitones ());
5791 Editor::set_tempo_from_region ()
5793 RegionSelection rs = get_regions_from_selection_and_entered ();
5795 if (!_session || rs.empty()) {
5799 RegionView* rv = rs.front();
5801 define_one_bar (rv->region()->position(), rv->region()->last_frame() + 1);
5805 Editor::use_range_as_bar ()
5807 framepos_t start, end;
5808 if (get_edit_op_range (start, end)) {
5809 define_one_bar (start, end);
5814 Editor::define_one_bar (framepos_t start, framepos_t end)
5816 framepos_t length = end - start;
5818 const Meter& m (_session->tempo_map().meter_at (start));
5820 /* length = 1 bar */
5822 /* now we want frames per beat.
5823 we have frames per bar, and beats per bar, so ...
5826 /* XXXX METER MATH */
5828 double frames_per_beat = length / m.divisions_per_bar();
5830 /* beats per minute = */
5832 double beats_per_minute = (_session->frame_rate() * 60.0) / frames_per_beat;
5834 /* now decide whether to:
5836 (a) set global tempo
5837 (b) add a new tempo marker
5841 const TempoSection& t (_session->tempo_map().tempo_section_at (start));
5843 bool do_global = false;
5845 if ((_session->tempo_map().n_tempos() == 1) && (_session->tempo_map().n_meters() == 1)) {
5847 /* only 1 tempo & 1 meter: ask if the user wants to set the tempo
5848 at the start, or create a new marker
5851 vector<string> options;
5852 options.push_back (_("Cancel"));
5853 options.push_back (_("Add new marker"));
5854 options.push_back (_("Set global tempo"));
5857 _("Define one bar"),
5858 _("Do you want to set the global tempo or add a new tempo marker?"),
5862 c.set_default_response (2);
5878 /* more than 1 tempo and/or meter section already, go ahead do the "usual":
5879 if the marker is at the region starter, change it, otherwise add
5884 begin_reversible_command (_("set tempo from region"));
5885 XMLNode& before (_session->tempo_map().get_state());
5888 _session->tempo_map().change_initial_tempo (beats_per_minute, t.note_type());
5889 } else if (t.frame() == start) {
5890 _session->tempo_map().change_existing_tempo_at (start, beats_per_minute, t.note_type());
5892 Timecode::BBT_Time bbt;
5893 _session->tempo_map().bbt_time (start, bbt);
5894 _session->tempo_map().add_tempo (Tempo (beats_per_minute, t.note_type()), bbt);
5897 XMLNode& after (_session->tempo_map().get_state());
5899 _session->add_command (new MementoCommand<TempoMap>(_session->tempo_map(), &before, &after));
5900 commit_reversible_command ();
5904 Editor::split_region_at_transients ()
5906 AnalysisFeatureList positions;
5908 RegionSelection rs = get_regions_from_selection_and_entered ();
5910 if (!_session || rs.empty()) {
5914 _session->begin_reversible_command (_("split regions"));
5916 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ) {
5918 RegionSelection::iterator tmp;
5923 boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion> ((*i)->region());
5925 if (ar && (ar->get_transients (positions) == 0)) {
5926 split_region_at_points ((*i)->region(), positions, true);
5933 _session->commit_reversible_command ();
5938 Editor::split_region_at_points (boost::shared_ptr<Region> r, AnalysisFeatureList& positions, bool can_ferret, bool select_new)
5940 bool use_rhythmic_rodent = false;
5942 boost::shared_ptr<Playlist> pl = r->playlist();
5944 list<boost::shared_ptr<Region> > new_regions;
5950 if (positions.empty()) {
5955 if (positions.size() > 20 && can_ferret) {
5956 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);
5957 MessageDialog msg (msgstr,
5960 Gtk::BUTTONS_OK_CANCEL);
5963 msg.add_button (_("Call for the Ferret!"), RESPONSE_APPLY);
5964 msg.set_secondary_text (_("Press OK to continue with this split operation\nor ask the Ferret dialog to tune the analysis"));
5966 msg.set_secondary_text (_("Press OK to continue with this split operation"));
5969 msg.set_title (_("Excessive split?"));
5972 int response = msg.run();
5978 case RESPONSE_APPLY:
5979 use_rhythmic_rodent = true;
5986 if (use_rhythmic_rodent) {
5987 show_rhythm_ferret ();
5991 AnalysisFeatureList::const_iterator x;
5993 pl->clear_changes ();
5994 pl->clear_owned_changes ();
5996 x = positions.begin();
5998 if (x == positions.end()) {
6003 pl->remove_region (r);
6007 while (x != positions.end()) {
6009 /* deal with positons that are out of scope of present region bounds */
6010 if (*x <= 0 || *x > r->length()) {
6015 /* file start = original start + how far we from the initial position ?
6018 framepos_t file_start = r->start() + pos;
6020 /* length = next position - current position
6023 framepos_t len = (*x) - pos;
6025 /* XXX we do we really want to allow even single-sample regions?
6026 shouldn't we have some kind of lower limit on region size?
6035 if (RegionFactory::region_name (new_name, r->name())) {
6039 /* do NOT announce new regions 1 by one, just wait till they are all done */
6043 plist.add (ARDOUR::Properties::start, file_start);
6044 plist.add (ARDOUR::Properties::length, len);
6045 plist.add (ARDOUR::Properties::name, new_name);
6046 plist.add (ARDOUR::Properties::layer, 0);
6048 boost::shared_ptr<Region> nr = RegionFactory::create (r->sources(), plist, false);
6049 /* because we set annouce to false, manually add the new region to the
6052 RegionFactory::map_add (nr);
6054 pl->add_region (nr, r->position() + pos);
6057 new_regions.push_front(nr);
6066 RegionFactory::region_name (new_name, r->name());
6068 /* Add the final region */
6071 plist.add (ARDOUR::Properties::start, r->start() + pos);
6072 plist.add (ARDOUR::Properties::length, r->last_frame() - (r->position() + pos) + 1);
6073 plist.add (ARDOUR::Properties::name, new_name);
6074 plist.add (ARDOUR::Properties::layer, 0);
6076 boost::shared_ptr<Region> nr = RegionFactory::create (r->sources(), plist, false);
6077 /* because we set annouce to false, manually add the new region to the
6080 RegionFactory::map_add (nr);
6081 pl->add_region (nr, r->position() + pos);
6084 new_regions.push_front(nr);
6089 /* We might have removed regions, which alters other regions' layering_index,
6090 so we need to do a recursive diff here.
6092 vector<Command*> cmds;
6094 _session->add_commands (cmds);
6096 _session->add_command (new StatefulDiffCommand (pl));
6100 for (list<boost::shared_ptr<Region> >::iterator i = new_regions.begin(); i != new_regions.end(); ++i){
6101 set_selected_regionview_from_region_list ((*i), Selection::Add);
6107 Editor::place_transient()
6113 RegionSelection rs = get_regions_from_selection_and_edit_point ();
6119 framepos_t where = get_preferred_edit_position();
6121 _session->begin_reversible_command (_("place transient"));
6123 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6124 framepos_t position = (*r)->region()->position();
6125 (*r)->region()->add_transient(where - position);
6128 _session->commit_reversible_command ();
6132 Editor::remove_transient(ArdourCanvas::Item* item)
6138 ArdourCanvas::Line* _line = reinterpret_cast<ArdourCanvas::Line*> (item);
6141 AudioRegionView* _arv = reinterpret_cast<AudioRegionView*> (item->get_data ("regionview"));
6142 _arv->remove_transient (*(float*) _line->get_data ("position"));
6146 Editor::snap_regions_to_grid ()
6148 list <boost::shared_ptr<Playlist > > used_playlists;
6150 RegionSelection rs = get_regions_from_selection_and_entered ();
6152 if (!_session || rs.empty()) {
6156 _session->begin_reversible_command (_("snap regions to grid"));
6158 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6160 boost::shared_ptr<Playlist> pl = (*r)->region()->playlist();
6162 if (!pl->frozen()) {
6163 /* we haven't seen this playlist before */
6165 /* remember used playlists so we can thaw them later */
6166 used_playlists.push_back(pl);
6170 framepos_t start_frame = (*r)->region()->first_frame ();
6171 snap_to (start_frame);
6172 (*r)->region()->set_position (start_frame);
6175 while (used_playlists.size() > 0) {
6176 list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
6178 used_playlists.pop_front();
6181 _session->commit_reversible_command ();
6185 Editor::close_region_gaps ()
6187 list <boost::shared_ptr<Playlist > > used_playlists;
6189 RegionSelection rs = get_regions_from_selection_and_entered ();
6191 if (!_session || rs.empty()) {
6195 Dialog dialog (_("Close Region Gaps"));
6198 table.set_spacings (12);
6199 table.set_border_width (12);
6200 Label* l = manage (left_aligned_label (_("Crossfade length")));
6201 table.attach (*l, 0, 1, 0, 1);
6203 SpinButton spin_crossfade (1, 0);
6204 spin_crossfade.set_range (0, 15);
6205 spin_crossfade.set_increments (1, 1);
6206 spin_crossfade.set_value (5);
6207 table.attach (spin_crossfade, 1, 2, 0, 1);
6209 table.attach (*manage (new Label (_("ms"))), 2, 3, 0, 1);
6211 l = manage (left_aligned_label (_("Pull-back length")));
6212 table.attach (*l, 0, 1, 1, 2);
6214 SpinButton spin_pullback (1, 0);
6215 spin_pullback.set_range (0, 100);
6216 spin_pullback.set_increments (1, 1);
6217 spin_pullback.set_value(30);
6218 table.attach (spin_pullback, 1, 2, 1, 2);
6220 table.attach (*manage (new Label (_("ms"))), 2, 3, 1, 2);
6222 dialog.get_vbox()->pack_start (table);
6223 dialog.add_button (Stock::CANCEL, RESPONSE_CANCEL);
6224 dialog.add_button (_("Ok"), RESPONSE_ACCEPT);
6227 if (dialog.run () == RESPONSE_CANCEL) {
6231 framepos_t crossfade_len = spin_crossfade.get_value();
6232 framepos_t pull_back_frames = spin_pullback.get_value();
6234 crossfade_len = lrintf (crossfade_len * _session->frame_rate()/1000);
6235 pull_back_frames = lrintf (pull_back_frames * _session->frame_rate()/1000);
6237 /* Iterate over the region list and make adjacent regions overlap by crossfade_len_ms */
6239 _session->begin_reversible_command (_("close region gaps"));
6242 boost::shared_ptr<Region> last_region;
6244 rs.sort_by_position_and_track();
6246 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6248 boost::shared_ptr<Playlist> pl = (*r)->region()->playlist();
6250 if (!pl->frozen()) {
6251 /* we haven't seen this playlist before */
6253 /* remember used playlists so we can thaw them later */
6254 used_playlists.push_back(pl);
6258 framepos_t position = (*r)->region()->position();
6260 if (idx == 0 || position < last_region->position()){
6261 last_region = (*r)->region();
6266 (*r)->region()->trim_front( (position - pull_back_frames));
6267 last_region->trim_end( (position - pull_back_frames + crossfade_len));
6269 last_region = (*r)->region();
6274 while (used_playlists.size() > 0) {
6275 list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
6277 used_playlists.pop_front();
6280 _session->commit_reversible_command ();
6284 Editor::tab_to_transient (bool forward)
6286 AnalysisFeatureList positions;
6288 RegionSelection rs = get_regions_from_selection_and_entered ();
6294 framepos_t pos = _session->audible_frame ();
6296 if (!selection->tracks.empty()) {
6298 /* don't waste time searching for transients in duplicate playlists.
6301 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
6303 for (TrackViewList::iterator t = ts.begin(); t != ts.end(); ++t) {
6305 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*t);
6308 boost::shared_ptr<Track> tr = rtv->track();
6310 boost::shared_ptr<Playlist> pl = tr->playlist ();
6312 framepos_t result = pl->find_next_transient (pos, forward ? 1 : -1);
6315 positions.push_back (result);
6328 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6329 (*r)->region()->get_transients (positions);
6333 TransientDetector::cleanup_transients (positions, _session->frame_rate(), 3.0);
6336 AnalysisFeatureList::iterator x;
6338 for (x = positions.begin(); x != positions.end(); ++x) {
6344 if (x != positions.end ()) {
6345 _session->request_locate (*x);
6349 AnalysisFeatureList::reverse_iterator x;
6351 for (x = positions.rbegin(); x != positions.rend(); ++x) {
6357 if (x != positions.rend ()) {
6358 _session->request_locate (*x);
6364 Editor::playhead_forward_to_grid ()
6370 framepos_t pos = playhead_cursor->current_frame ();
6371 if (pos < max_framepos - 1) {
6373 snap_to_internal (pos, 1, false);
6374 _session->request_locate (pos);
6380 Editor::playhead_backward_to_grid ()
6386 framepos_t pos = playhead_cursor->current_frame ();
6389 snap_to_internal (pos, -1, false);
6390 _session->request_locate (pos);
6395 Editor::set_track_height (Height h)
6397 TrackSelection& ts (selection->tracks);
6399 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
6400 (*x)->set_height_enum (h);
6405 Editor::toggle_tracks_active ()
6407 TrackSelection& ts (selection->tracks);
6409 bool target = false;
6415 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
6416 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*x);
6420 target = !rtv->_route->active();
6423 rtv->_route->set_active (target, this);
6429 Editor::remove_tracks ()
6431 TrackSelection& ts (selection->tracks);
6437 vector<string> choices;
6441 const char* trackstr;
6443 vector<boost::shared_ptr<Route> > routes;
6444 bool special_bus = false;
6446 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
6447 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*x);
6449 if (rtv->is_track()) {
6455 routes.push_back (rtv->_route);
6457 if (rtv->route()->is_master() || rtv->route()->is_monitor()) {
6462 if (special_bus && !Config->get_allow_special_bus_removal()) {
6463 MessageDialog msg (_("That would be bad news ...."),
6467 msg.set_secondary_text (string_compose (_(
6468 "Removing the master or monitor bus is such a bad idea\n\
6469 that %1 is not going to allow it.\n\
6471 If you really want to do this sort of thing\n\
6472 edit your ardour.rc file to set the\n\
6473 \"allow-special-bus-removal\" option to be \"yes\""), PROGRAM_NAME));
6480 if (ntracks + nbusses == 0) {
6485 trackstr = _("tracks");
6487 trackstr = _("track");
6491 busstr = _("busses");
6498 prompt = string_compose (_("Do you really want to remove %1 %2 and %3 %4?\n"
6499 "(You may also lose the playlists associated with the %2)\n\n"
6500 "This action cannot be undone, and the session file will be overwritten!"),
6501 ntracks, trackstr, nbusses, busstr);
6503 prompt = string_compose (_("Do you really want to remove %1 %2?\n"
6504 "(You may also lose the playlists associated with the %2)\n\n"
6505 "This action cannot be undone, and the session file will be overwritten!"),
6508 } else if (nbusses) {
6509 prompt = string_compose (_("Do you really want to remove %1 %2?\n\n"
6510 "This action cannot be undon, and the session file will be overwritten"),
6514 choices.push_back (_("No, do nothing."));
6515 if (ntracks + nbusses > 1) {
6516 choices.push_back (_("Yes, remove them."));
6518 choices.push_back (_("Yes, remove it."));
6523 title = string_compose (_("Remove %1"), trackstr);
6525 title = string_compose (_("Remove %1"), busstr);
6528 Choice prompter (title, prompt, choices);
6530 if (prompter.run () != 1) {
6534 for (vector<boost::shared_ptr<Route> >::iterator x = routes.begin(); x != routes.end(); ++x) {
6535 _session->remove_route (*x);
6540 Editor::do_insert_time ()
6542 if (selection->tracks.empty()) {
6546 InsertTimeDialog d (*this);
6547 int response = d.run ();
6549 if (response != RESPONSE_OK) {
6553 if (d.distance() == 0) {
6557 InsertTimeOption opt = d.intersected_region_action ();
6560 get_preferred_edit_position(),
6566 d.move_glued_markers(),
6567 d.move_locked_markers(),
6573 Editor::insert_time (
6574 framepos_t pos, framecnt_t frames, InsertTimeOption opt,
6575 bool all_playlists, bool ignore_music_glue, bool markers_too, bool glued_markers_too, bool locked_markers_too, bool tempo_too
6578 bool commit = false;
6580 if (Config->get_edit_mode() == Lock) {
6584 begin_reversible_command (_("insert time"));
6586 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
6588 for (TrackViewList::iterator x = ts.begin(); x != ts.end(); ++x) {
6592 /* don't operate on any playlist more than once, which could
6593 * happen if "all playlists" is enabled, but there is more
6594 * than 1 track using playlists "from" a given track.
6597 set<boost::shared_ptr<Playlist> > pl;
6599 if (all_playlists) {
6600 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*x);
6602 vector<boost::shared_ptr<Playlist> > all = _session->playlists->playlists_for_track (rtav->track ());
6603 for (vector<boost::shared_ptr<Playlist> >::iterator p = all.begin(); p != all.end(); ++p) {
6608 if ((*x)->playlist ()) {
6609 pl.insert ((*x)->playlist ());
6613 for (set<boost::shared_ptr<Playlist> >::iterator i = pl.begin(); i != pl.end(); ++i) {
6615 (*i)->clear_changes ();
6616 (*i)->clear_owned_changes ();
6618 if (opt == SplitIntersected) {
6622 (*i)->shift (pos, frames, (opt == MoveIntersected), ignore_music_glue);
6624 vector<Command*> cmds;
6626 _session->add_commands (cmds);
6628 _session->add_command (new StatefulDiffCommand (*i));
6633 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*x);
6635 rtav->route ()->shift (pos, frames);
6643 XMLNode& before (_session->locations()->get_state());
6644 Locations::LocationList copy (_session->locations()->list());
6646 for (Locations::LocationList::iterator i = copy.begin(); i != copy.end(); ++i) {
6648 Locations::LocationList::const_iterator tmp;
6650 bool const was_locked = (*i)->locked ();
6651 if (locked_markers_too) {
6655 if ((*i)->position_lock_style() == AudioTime || glued_markers_too) {
6657 if ((*i)->start() >= pos) {
6658 (*i)->set_start ((*i)->start() + frames);
6659 if (!(*i)->is_mark()) {
6660 (*i)->set_end ((*i)->end() + frames);
6673 XMLNode& after (_session->locations()->get_state());
6674 _session->add_command (new MementoCommand<Locations>(*_session->locations(), &before, &after));
6679 _session->tempo_map().insert_time (pos, frames);
6683 commit_reversible_command ();
6688 Editor::fit_selected_tracks ()
6690 if (!selection->tracks.empty()) {
6691 fit_tracks (selection->tracks);
6695 /* no selected tracks - use tracks with selected regions */
6697 if (!selection->regions.empty()) {
6698 for (RegionSelection::iterator r = selection->regions.begin(); r != selection->regions.end(); ++r) {
6699 tvl.push_back (&(*r)->get_time_axis_view ());
6705 } else if (internal_editing()) {
6706 /* no selected tracks, or regions, but in internal edit mode, so follow the mouse and use
6709 if (entered_track) {
6710 tvl.push_back (entered_track);
6718 Editor::fit_tracks (TrackViewList & tracks)
6720 if (tracks.empty()) {
6724 uint32_t child_heights = 0;
6725 int visible_tracks = 0;
6727 for (TrackSelection::iterator t = tracks.begin(); t != tracks.end(); ++t) {
6729 if (!(*t)->marked_for_display()) {
6733 child_heights += (*t)->effective_height() - (*t)->current_height();
6737 uint32_t h = (uint32_t) floor ((_visible_canvas_height - child_heights) / visible_tracks);
6738 double first_y_pos = DBL_MAX;
6740 if (h < TimeAxisView::preset_height (HeightSmall)) {
6741 MessageDialog msg (*this, _("There are too many tracks to fit in the current window"));
6742 /* too small to be displayed */
6746 undo_visual_stack.push_back (current_visual_state (true));
6747 no_save_visual = true;
6749 /* build a list of all tracks, including children */
6752 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
6754 TimeAxisView::Children c = (*i)->get_child_list ();
6755 for (TimeAxisView::Children::iterator j = c.begin(); j != c.end(); ++j) {
6756 all.push_back (j->get());
6760 /* operate on all tracks, hide unselected ones that are in the middle of selected ones */
6762 bool prev_was_selected = false;
6763 bool is_selected = tracks.contains (all.front());
6764 bool next_is_selected;
6766 for (TrackViewList::iterator t = all.begin(); t != all.end(); ++t) {
6768 TrackViewList::iterator next;
6773 if (next != all.end()) {
6774 next_is_selected = tracks.contains (*next);
6776 next_is_selected = false;
6779 if ((*t)->marked_for_display ()) {
6781 (*t)->set_height (h);
6782 first_y_pos = std::min ((*t)->y_position (), first_y_pos);
6784 if (prev_was_selected && next_is_selected) {
6785 hide_track_in_display (*t);
6790 prev_was_selected = is_selected;
6791 is_selected = next_is_selected;
6795 set the controls_layout height now, because waiting for its size
6796 request signal handler will cause the vertical adjustment setting to fail
6799 controls_layout.property_height () = _full_canvas_height;
6800 vertical_adjustment.set_value (first_y_pos);
6802 redo_visual_stack.push_back (current_visual_state (true));
6806 Editor::save_visual_state (uint32_t n)
6808 while (visual_states.size() <= n) {
6809 visual_states.push_back (0);
6812 if (visual_states[n] != 0) {
6813 delete visual_states[n];
6816 visual_states[n] = current_visual_state (true);
6821 Editor::goto_visual_state (uint32_t n)
6823 if (visual_states.size() <= n) {
6827 if (visual_states[n] == 0) {
6831 use_visual_state (*visual_states[n]);
6835 Editor::start_visual_state_op (uint32_t n)
6837 save_visual_state (n);
6839 PopUp* pup = new PopUp (WIN_POS_MOUSE, 1000, true);
6841 snprintf (buf, sizeof (buf), _("Saved view %u"), n+1);
6842 pup->set_text (buf);
6847 Editor::cancel_visual_state_op (uint32_t n)
6849 goto_visual_state (n);
6853 Editor::toggle_region_mute ()
6855 if (_ignore_region_action) {
6859 RegionSelection rs = get_regions_from_selection_and_entered ();
6865 if (rs.size() > 1) {
6866 begin_reversible_command (_("mute regions"));
6868 begin_reversible_command (_("mute region"));
6871 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
6873 (*i)->region()->playlist()->clear_changes ();
6874 (*i)->region()->set_muted (!(*i)->region()->muted ());
6875 _session->add_command (new StatefulDiffCommand ((*i)->region()->playlist()));
6879 commit_reversible_command ();
6883 Editor::combine_regions ()
6885 /* foreach track with selected regions, take all selected regions
6886 and join them into a new region containing the subregions (as a
6890 typedef set<RouteTimeAxisView*> RTVS;
6893 if (selection->regions.empty()) {
6897 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
6898 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(&(*i)->get_time_axis_view());
6901 tracks.insert (rtv);
6905 begin_reversible_command (_("combine regions"));
6907 vector<RegionView*> new_selection;
6909 for (RTVS::iterator i = tracks.begin(); i != tracks.end(); ++i) {
6912 if ((rv = (*i)->combine_regions ()) != 0) {
6913 new_selection.push_back (rv);
6917 selection->clear_regions ();
6918 for (vector<RegionView*>::iterator i = new_selection.begin(); i != new_selection.end(); ++i) {
6919 selection->add (*i);
6922 commit_reversible_command ();
6926 Editor::uncombine_regions ()
6928 typedef set<RouteTimeAxisView*> RTVS;
6931 if (selection->regions.empty()) {
6935 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
6936 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(&(*i)->get_time_axis_view());
6939 tracks.insert (rtv);
6943 begin_reversible_command (_("uncombine regions"));
6945 for (RTVS::iterator i = tracks.begin(); i != tracks.end(); ++i) {
6946 (*i)->uncombine_regions ();
6949 commit_reversible_command ();
6953 Editor::toggle_midi_input_active (bool flip_others)
6956 boost::shared_ptr<RouteList> rl (new RouteList);
6958 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
6959 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
6965 boost::shared_ptr<MidiTrack> mt = rtav->midi_track();
6968 rl->push_back (rtav->route());
6969 onoff = !mt->input_active();
6973 _session->set_exclusive_input_active (rl, onoff, flip_others);