2 Copyright (C) 2000-2004 Paul Davis
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 /* Note: public Editor methods are documented in public_editor.h */
30 #include "pbd/error.h"
31 #include "pbd/basename.h"
32 #include "pbd/pthread_utils.h"
33 #include "pbd/memento_command.h"
34 #include "pbd/unwind.h"
35 #include "pbd/whitespace.h"
36 #include "pbd/stateful_diff_command.h"
38 #include <gtkmm2ext/utils.h>
39 #include <gtkmm2ext/choice.h>
40 #include <gtkmm2ext/popup.h>
42 #include "ardour/audio_track.h"
43 #include "ardour/audioregion.h"
44 #include "ardour/dB.h"
45 #include "ardour/location.h"
46 #include "ardour/midi_region.h"
47 #include "ardour/operations.h"
48 #include "ardour/playlist_factory.h"
49 #include "ardour/quantize.h"
50 #include "ardour/region_factory.h"
51 #include "ardour/reverse.h"
52 #include "ardour/session.h"
53 #include "ardour/session_playlists.h"
54 #include "ardour/strip_silence.h"
55 #include "ardour/transient_detector.h"
57 #include "ardour_ui.h"
60 #include "time_axis_view.h"
61 #include "route_time_axis.h"
62 #include "audio_time_axis.h"
63 #include "automation_time_axis.h"
64 #include "control_point.h"
65 #include "streamview.h"
66 #include "audio_streamview.h"
67 #include "audio_region_view.h"
68 #include "midi_region_view.h"
69 #include "rgb_macros.h"
70 #include "selection_templates.h"
71 #include "selection.h"
73 #include "gtk-custom-hruler.h"
74 #include "gui_thread.h"
77 #include "editor_drag.h"
78 #include "strip_silence_dialog.h"
79 #include "editor_routes.h"
80 #include "editor_regions.h"
81 #include "quantize_dialog.h"
82 #include "interthread_progress_window.h"
83 #include "insert_time_dialog.h"
84 #include "normalize_dialog.h"
85 #include "editor_cursors.h"
86 #include "mouse_cursors.h"
87 #include "patch_change_dialog.h"
88 #include "transpose_dialog.h"
93 using namespace ARDOUR;
96 using namespace Gtkmm2ext;
97 using namespace Editing;
98 using Gtkmm2ext::Keyboard;
100 /***********************************************************************
102 ***********************************************************************/
105 Editor::undo (uint32_t n)
107 if (_drags->active ()) {
117 Editor::redo (uint32_t n)
119 if (_drags->active ()) {
129 Editor::split_regions_at (framepos_t where, RegionSelection& regions)
133 list <boost::shared_ptr<Playlist > > used_playlists;
135 if (regions.empty()) {
139 begin_reversible_command (_("split"));
141 // if splitting a single region, and snap-to is using
142 // region boundaries, don't pay attention to them
144 if (regions.size() == 1) {
145 switch (_snap_type) {
146 case SnapToRegionStart:
147 case SnapToRegionSync:
148 case SnapToRegionEnd:
157 EditorFreeze(); /* Emit Signal */
160 for (RegionSelection::iterator a = regions.begin(); a != regions.end(); ) {
162 RegionSelection::iterator tmp;
164 /* XXX this test needs to be more complicated, to make sure we really
165 have something to split.
168 if (!(*a)->region()->covers (where)) {
176 boost::shared_ptr<Playlist> pl = (*a)->region()->playlist();
184 /* we haven't seen this playlist before */
186 /* remember used playlists so we can thaw them later */
187 used_playlists.push_back(pl);
192 pl->clear_changes ();
193 pl->split_region ((*a)->region(), where);
194 _session->add_command (new StatefulDiffCommand (pl));
200 while (used_playlists.size() > 0) {
201 list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
203 used_playlists.pop_front();
206 commit_reversible_command ();
209 EditorThaw(); /* Emit Signal */
213 /** Move one extreme of the current range selection. If more than one range is selected,
214 * the start of the earliest range or the end of the latest range is moved.
216 * @param move_end true to move the end of the current range selection, false to move
218 * @param next true to move the extreme to the next region boundary, false to move to
222 Editor::move_range_selection_start_or_end_to_region_boundary (bool move_end, bool next)
224 if (selection->time.start() == selection->time.end_frame()) {
228 framepos_t start = selection->time.start ();
229 framepos_t end = selection->time.end_frame ();
231 /* the position of the thing we may move */
232 framepos_t pos = move_end ? end : start;
233 int dir = next ? 1 : -1;
235 /* so we don't find the current region again */
236 if (dir > 0 || pos > 0) {
240 framepos_t const target = get_region_boundary (pos, dir, true, false);
255 begin_reversible_command (_("alter selection"));
256 selection->set_preserving_all_ranges (start, end);
257 commit_reversible_command ();
261 Editor::nudge_forward_release (GdkEventButton* ev)
263 if (ev->state & Keyboard::PrimaryModifier) {
264 nudge_forward (false, true);
266 nudge_forward (false, false);
272 Editor::nudge_backward_release (GdkEventButton* ev)
274 if (ev->state & Keyboard::PrimaryModifier) {
275 nudge_backward (false, true);
277 nudge_backward (false, false);
284 Editor::nudge_forward (bool next, bool force_playhead)
287 framepos_t next_distance;
293 RegionSelection rs = get_regions_from_selection_and_entered ();
295 if (!force_playhead && !rs.empty()) {
297 begin_reversible_command (_("nudge regions forward"));
299 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
300 boost::shared_ptr<Region> r ((*i)->region());
302 distance = get_nudge_distance (r->position(), next_distance);
305 distance = next_distance;
309 r->set_position (r->position() + distance);
310 _session->add_command (new StatefulDiffCommand (r));
313 commit_reversible_command ();
316 } else if (!force_playhead && !selection->markers.empty()) {
320 begin_reversible_command (_("nudge location forward"));
322 for (MarkerSelection::iterator i = selection->markers.begin(); i != selection->markers.end(); ++i) {
324 Location* loc = find_location_from_marker ((*i), is_start);
328 XMLNode& before (loc->get_state());
331 distance = get_nudge_distance (loc->start(), next_distance);
333 distance = next_distance;
335 if (max_framepos - distance > loc->start() + loc->length()) {
336 loc->set_start (loc->start() + distance);
338 loc->set_start (max_framepos - loc->length());
341 distance = get_nudge_distance (loc->end(), next_distance);
343 distance = next_distance;
345 if (max_framepos - distance > loc->end()) {
346 loc->set_end (loc->end() + distance);
348 loc->set_end (max_framepos);
351 XMLNode& after (loc->get_state());
352 _session->add_command (new MementoCommand<Location>(*loc, &before, &after));
356 commit_reversible_command ();
359 distance = get_nudge_distance (playhead_cursor->current_frame, next_distance);
360 _session->request_locate (playhead_cursor->current_frame + distance);
365 Editor::nudge_backward (bool next, bool force_playhead)
368 framepos_t next_distance;
374 RegionSelection rs = get_regions_from_selection_and_entered ();
376 if (!force_playhead && !rs.empty()) {
378 begin_reversible_command (_("nudge regions backward"));
380 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
381 boost::shared_ptr<Region> r ((*i)->region());
383 distance = get_nudge_distance (r->position(), next_distance);
386 distance = next_distance;
391 if (r->position() > distance) {
392 r->set_position (r->position() - distance);
396 _session->add_command (new StatefulDiffCommand (r));
399 commit_reversible_command ();
401 } else if (!force_playhead && !selection->markers.empty()) {
405 begin_reversible_command (_("nudge location forward"));
407 for (MarkerSelection::iterator i = selection->markers.begin(); i != selection->markers.end(); ++i) {
409 Location* loc = find_location_from_marker ((*i), is_start);
413 XMLNode& before (loc->get_state());
416 distance = get_nudge_distance (loc->start(), next_distance);
418 distance = next_distance;
420 if (distance < loc->start()) {
421 loc->set_start (loc->start() - distance);
426 distance = get_nudge_distance (loc->end(), next_distance);
429 distance = next_distance;
432 if (distance < loc->end() - loc->length()) {
433 loc->set_end (loc->end() - distance);
435 loc->set_end (loc->length());
439 XMLNode& after (loc->get_state());
440 _session->add_command (new MementoCommand<Location>(*loc, &before, &after));
444 commit_reversible_command ();
448 distance = get_nudge_distance (playhead_cursor->current_frame, next_distance);
450 if (playhead_cursor->current_frame > distance) {
451 _session->request_locate (playhead_cursor->current_frame - distance);
453 _session->goto_start();
459 Editor::nudge_forward_capture_offset ()
461 RegionSelection rs = get_regions_from_selection_and_entered ();
463 if (!_session || rs.empty()) {
467 begin_reversible_command (_("nudge forward"));
469 framepos_t const distance = _session->worst_output_latency();
471 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
472 boost::shared_ptr<Region> r ((*i)->region());
475 r->set_position (r->position() + distance);
476 _session->add_command(new StatefulDiffCommand (r));
479 commit_reversible_command ();
483 Editor::nudge_backward_capture_offset ()
485 RegionSelection rs = get_regions_from_selection_and_entered ();
487 if (!_session || rs.empty()) {
491 begin_reversible_command (_("nudge backward"));
493 framepos_t const distance = _session->worst_output_latency();
495 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
496 boost::shared_ptr<Region> r ((*i)->region());
500 if (r->position() > distance) {
501 r->set_position (r->position() - distance);
505 _session->add_command(new StatefulDiffCommand (r));
508 commit_reversible_command ();
514 Editor::move_to_start ()
516 _session->goto_start ();
520 Editor::move_to_end ()
523 _session->request_locate (_session->current_end_frame());
527 Editor::build_region_boundary_cache ()
530 vector<RegionPoint> interesting_points;
531 boost::shared_ptr<Region> r;
532 TrackViewList tracks;
535 region_boundary_cache.clear ();
541 switch (_snap_type) {
542 case SnapToRegionStart:
543 interesting_points.push_back (Start);
545 case SnapToRegionEnd:
546 interesting_points.push_back (End);
548 case SnapToRegionSync:
549 interesting_points.push_back (SyncPoint);
551 case SnapToRegionBoundary:
552 interesting_points.push_back (Start);
553 interesting_points.push_back (End);
556 fatal << string_compose (_("build_region_boundary_cache called with snap_type = %1"), _snap_type) << endmsg;
561 TimeAxisView *ontrack = 0;
564 if (!selection->tracks.empty()) {
565 tlist = selection->tracks.filter_to_unique_playlists ();
567 tlist = track_views.filter_to_unique_playlists ();
570 while (pos < _session->current_end_frame() && !at_end) {
573 framepos_t lpos = max_framepos;
575 for (vector<RegionPoint>::iterator p = interesting_points.begin(); p != interesting_points.end(); ++p) {
577 if ((r = find_next_region (pos, *p, 1, tlist, &ontrack)) == 0) {
578 if (*p == interesting_points.back()) {
581 /* move to next point type */
587 rpos = r->first_frame();
591 rpos = r->last_frame();
595 rpos = r->sync_position ();
603 RouteTimeAxisView *rtav;
605 if (ontrack != 0 && (rtav = dynamic_cast<RouteTimeAxisView*>(ontrack)) != 0 ) {
606 if (rtav->track() != 0) {
607 speed = rtav->track()->speed();
611 rpos = track_frame_to_session_frame (rpos, speed);
617 /* prevent duplicates, but we don't use set<> because we want to be able
621 vector<framepos_t>::iterator ri;
623 for (ri = region_boundary_cache.begin(); ri != region_boundary_cache.end(); ++ri) {
629 if (ri == region_boundary_cache.end()) {
630 region_boundary_cache.push_back (rpos);
637 /* finally sort to be sure that the order is correct */
639 sort (region_boundary_cache.begin(), region_boundary_cache.end());
642 boost::shared_ptr<Region>
643 Editor::find_next_region (framepos_t frame, RegionPoint point, int32_t dir, TrackViewList& tracks, TimeAxisView **ontrack)
645 TrackViewList::iterator i;
646 framepos_t closest = max_framepos;
647 boost::shared_ptr<Region> ret;
651 framepos_t track_frame;
652 RouteTimeAxisView *rtav;
654 for (i = tracks.begin(); i != tracks.end(); ++i) {
657 boost::shared_ptr<Region> r;
660 if ( (rtav = dynamic_cast<RouteTimeAxisView*>(*i)) != 0 ) {
661 if (rtav->track()!=0)
662 track_speed = rtav->track()->speed();
665 track_frame = session_frame_to_track_frame(frame, track_speed);
667 if ((r = (*i)->find_next_region (track_frame, point, dir)) == 0) {
673 rpos = r->first_frame ();
677 rpos = r->last_frame ();
681 rpos = r->sync_position ();
685 // rpos is a "track frame", converting it to "_session frame"
686 rpos = track_frame_to_session_frame(rpos, track_speed);
689 distance = rpos - frame;
691 distance = frame - rpos;
694 if (distance < closest) {
706 Editor::find_next_region_boundary (framepos_t pos, int32_t dir, const TrackViewList& tracks)
708 framecnt_t distance = max_framepos;
709 framepos_t current_nearest = -1;
711 for (TrackViewList::const_iterator i = tracks.begin(); i != tracks.end(); ++i) {
712 framepos_t contender;
715 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*i);
721 if ((contender = rtv->find_next_region_boundary (pos, dir)) < 0) {
725 d = ::llabs (pos - contender);
728 current_nearest = contender;
733 return current_nearest;
737 Editor::get_region_boundary (framepos_t pos, int32_t dir, bool with_selection, bool only_onscreen)
742 if (with_selection && Config->get_region_boundaries_from_selected_tracks()) {
744 if (!selection->tracks.empty()) {
746 target = find_next_region_boundary (pos, dir, selection->tracks);
750 if (only_onscreen || Config->get_region_boundaries_from_onscreen_tracks()) {
751 get_onscreen_tracks (tvl);
752 target = find_next_region_boundary (pos, dir, tvl);
754 target = find_next_region_boundary (pos, dir, track_views);
760 if (only_onscreen || Config->get_region_boundaries_from_onscreen_tracks()) {
761 get_onscreen_tracks (tvl);
762 target = find_next_region_boundary (pos, dir, tvl);
764 target = find_next_region_boundary (pos, dir, track_views);
772 Editor::cursor_to_region_boundary (bool with_selection, int32_t dir)
774 framepos_t pos = playhead_cursor->current_frame;
781 // so we don't find the current region again..
782 if (dir > 0 || pos > 0) {
786 if ((target = get_region_boundary (pos, dir, with_selection, false)) < 0) {
790 _session->request_locate (target);
794 Editor::cursor_to_next_region_boundary (bool with_selection)
796 cursor_to_region_boundary (with_selection, 1);
800 Editor::cursor_to_previous_region_boundary (bool with_selection)
802 cursor_to_region_boundary (with_selection, -1);
806 Editor::cursor_to_region_point (EditorCursor* cursor, RegionPoint point, int32_t dir)
808 boost::shared_ptr<Region> r;
809 framepos_t pos = cursor->current_frame;
815 TimeAxisView *ontrack = 0;
817 // so we don't find the current region again..
821 if (!selection->tracks.empty()) {
823 r = find_next_region (pos, point, dir, selection->tracks, &ontrack);
825 } else if (clicked_axisview) {
828 t.push_back (clicked_axisview);
830 r = find_next_region (pos, point, dir, t, &ontrack);
834 r = find_next_region (pos, point, dir, track_views, &ontrack);
843 pos = r->first_frame ();
847 pos = r->last_frame ();
851 pos = r->sync_position ();
856 RouteTimeAxisView *rtav;
858 if ( ontrack != 0 && (rtav = dynamic_cast<RouteTimeAxisView*>(ontrack)) != 0 ) {
859 if (rtav->track() != 0) {
860 speed = rtav->track()->speed();
864 pos = track_frame_to_session_frame(pos, speed);
866 if (cursor == playhead_cursor) {
867 _session->request_locate (pos);
869 cursor->set_position (pos);
874 Editor::cursor_to_next_region_point (EditorCursor* cursor, RegionPoint point)
876 cursor_to_region_point (cursor, point, 1);
880 Editor::cursor_to_previous_region_point (EditorCursor* cursor, RegionPoint point)
882 cursor_to_region_point (cursor, point, -1);
886 Editor::cursor_to_selection_start (EditorCursor *cursor)
890 switch (mouse_mode) {
892 if (!selection->regions.empty()) {
893 pos = selection->regions.start();
898 if (!selection->time.empty()) {
899 pos = selection->time.start ();
907 if (cursor == playhead_cursor) {
908 _session->request_locate (pos);
910 cursor->set_position (pos);
915 Editor::cursor_to_selection_end (EditorCursor *cursor)
919 switch (mouse_mode) {
921 if (!selection->regions.empty()) {
922 pos = selection->regions.end_frame();
927 if (!selection->time.empty()) {
928 pos = selection->time.end_frame ();
936 if (cursor == playhead_cursor) {
937 _session->request_locate (pos);
939 cursor->set_position (pos);
944 Editor::selected_marker_to_region_boundary (bool with_selection, int32_t dir)
954 if (selection->markers.empty()) {
958 if (!mouse_frame (mouse, ignored)) {
962 add_location_mark (mouse);
965 if ((loc = find_location_from_marker (selection->markers.front(), ignored)) == 0) {
969 framepos_t pos = loc->start();
971 // so we don't find the current region again..
972 if (dir > 0 || pos > 0) {
976 if ((target = get_region_boundary (pos, dir, with_selection, false)) < 0) {
980 loc->move_to (target);
984 Editor::selected_marker_to_next_region_boundary (bool with_selection)
986 selected_marker_to_region_boundary (with_selection, 1);
990 Editor::selected_marker_to_previous_region_boundary (bool with_selection)
992 selected_marker_to_region_boundary (with_selection, -1);
996 Editor::selected_marker_to_region_point (RegionPoint point, int32_t dir)
998 boost::shared_ptr<Region> r;
1003 if (!_session || selection->markers.empty()) {
1007 if ((loc = find_location_from_marker (selection->markers.front(), ignored)) == 0) {
1011 TimeAxisView *ontrack = 0;
1015 // so we don't find the current region again..
1019 if (!selection->tracks.empty()) {
1021 r = find_next_region (pos, point, dir, selection->tracks, &ontrack);
1025 r = find_next_region (pos, point, dir, track_views, &ontrack);
1034 pos = r->first_frame ();
1038 pos = r->last_frame ();
1042 pos = r->adjust_to_sync (r->first_frame());
1047 RouteTimeAxisView *rtav;
1049 if (ontrack != 0 && (rtav = dynamic_cast<RouteTimeAxisView*>(ontrack)) != 0) {
1050 if (rtav->track() != 0) {
1051 speed = rtav->track()->speed();
1055 pos = track_frame_to_session_frame(pos, speed);
1061 Editor::selected_marker_to_next_region_point (RegionPoint point)
1063 selected_marker_to_region_point (point, 1);
1067 Editor::selected_marker_to_previous_region_point (RegionPoint point)
1069 selected_marker_to_region_point (point, -1);
1073 Editor::selected_marker_to_selection_start ()
1079 if (!_session || selection->markers.empty()) {
1083 if ((loc = find_location_from_marker (selection->markers.front(), ignored)) == 0) {
1087 switch (mouse_mode) {
1089 if (!selection->regions.empty()) {
1090 pos = selection->regions.start();
1095 if (!selection->time.empty()) {
1096 pos = selection->time.start ();
1108 Editor::selected_marker_to_selection_end ()
1114 if (!_session || selection->markers.empty()) {
1118 if ((loc = find_location_from_marker (selection->markers.front(), ignored)) == 0) {
1122 switch (mouse_mode) {
1124 if (!selection->regions.empty()) {
1125 pos = selection->regions.end_frame();
1130 if (!selection->time.empty()) {
1131 pos = selection->time.end_frame ();
1143 Editor::scroll_playhead (bool forward)
1145 framepos_t pos = playhead_cursor->current_frame;
1146 framecnt_t delta = (framecnt_t) floor (current_page_frames() / 0.8);
1149 if (pos == max_framepos) {
1153 if (pos < max_framepos - delta) {
1172 _session->request_locate (pos);
1176 Editor::cursor_align (bool playhead_to_edit)
1182 if (playhead_to_edit) {
1184 if (selection->markers.empty()) {
1188 _session->request_locate (selection->markers.front()->position(), _session->transport_rolling());
1191 /* move selected markers to playhead */
1193 for (MarkerSelection::iterator i = selection->markers.begin(); i != selection->markers.end(); ++i) {
1196 Location* loc = find_location_from_marker (*i, ignored);
1198 if (loc->is_mark()) {
1199 loc->set_start (playhead_cursor->current_frame);
1201 loc->set (playhead_cursor->current_frame,
1202 playhead_cursor->current_frame + loc->length());
1209 Editor::scroll_backward (float pages)
1211 framepos_t const one_page = (framepos_t) rint (_canvas_width * frames_per_unit);
1212 framepos_t const cnt = (framepos_t) floor (pages * one_page);
1215 if (leftmost_frame < cnt) {
1218 frame = leftmost_frame - cnt;
1221 reset_x_origin (frame);
1225 Editor::scroll_forward (float pages)
1227 framepos_t const one_page = (framepos_t) rint (_canvas_width * frames_per_unit);
1228 framepos_t const cnt = (framepos_t) floor (pages * one_page);
1231 if (max_framepos - cnt < leftmost_frame) {
1232 frame = max_framepos - cnt;
1234 frame = leftmost_frame + cnt;
1237 reset_x_origin (frame);
1241 Editor::scroll_tracks_down ()
1243 double vert_value = vertical_adjustment.get_value() + vertical_adjustment.get_page_size();
1244 if (vert_value > vertical_adjustment.get_upper() - _canvas_height) {
1245 vert_value = vertical_adjustment.get_upper() - _canvas_height;
1248 vertical_adjustment.set_value (vert_value);
1252 Editor::scroll_tracks_up ()
1254 vertical_adjustment.set_value (vertical_adjustment.get_value() - vertical_adjustment.get_page_size());
1258 Editor::scroll_tracks_down_line ()
1260 double vert_value = vertical_adjustment.get_value() + 60;
1262 if (vert_value > vertical_adjustment.get_upper() - _canvas_height) {
1263 vert_value = vertical_adjustment.get_upper() - _canvas_height;
1266 vertical_adjustment.set_value (vert_value);
1270 Editor::scroll_tracks_up_line ()
1272 reset_y_origin (vertical_adjustment.get_value() - 60);
1278 Editor::tav_zoom_step (bool coarser)
1280 _routes->suspend_redisplay ();
1284 if (selection->tracks.empty()) {
1287 ts = &selection->tracks;
1290 for (TrackViewList::iterator i = ts->begin(); i != ts->end(); ++i) {
1291 TimeAxisView *tv = (static_cast<TimeAxisView*>(*i));
1292 tv->step_height (coarser);
1295 _routes->resume_redisplay ();
1299 Editor::tav_zoom_smooth (bool coarser, bool force_all)
1301 _routes->suspend_redisplay ();
1305 if (selection->tracks.empty() || force_all) {
1308 ts = &selection->tracks;
1311 for (TrackViewList::iterator i = ts->begin(); i != ts->end(); ++i) {
1312 TimeAxisView *tv = (static_cast<TimeAxisView*>(*i));
1313 uint32_t h = tv->current_height ();
1318 if (h >= TimeAxisView::preset_height (HeightSmall)) {
1323 tv->set_height (h + 5);
1327 _routes->resume_redisplay ();
1331 Editor::clamp_frames_per_unit (double& fpu) const
1333 bool clamped = false;
1340 if (max_framepos / fpu < 800) {
1341 fpu = max_framepos / 800.0;
1349 Editor::temporal_zoom_step (bool coarser)
1351 ENSURE_GUI_THREAD (*this, &Editor::temporal_zoom_step, coarser)
1353 double nfpu = frames_per_unit;
1356 nfpu = min (9e6, nfpu * 1.61803399);
1358 nfpu = max (1.0, nfpu / 1.61803399);
1361 temporal_zoom (nfpu);
1365 Editor::temporal_zoom (double fpu)
1371 framepos_t current_page = current_page_frames();
1372 framepos_t current_leftmost = leftmost_frame;
1373 framepos_t current_rightmost;
1374 framepos_t current_center;
1375 framepos_t new_page_size;
1376 framepos_t half_page_size;
1377 framepos_t leftmost_after_zoom = 0;
1379 bool in_track_canvas;
1383 clamp_frames_per_unit (fpu);
1384 if (fpu == frames_per_unit) {
1390 // Imposing an arbitrary limit to zoom out as too much zoom out produces
1391 // segfaults for lack of memory. If somebody decides this is not high enough I
1392 // believe it can be raisen to higher values but some limit must be in place.
1397 new_page_size = (framepos_t) floor (_canvas_width * nfpu);
1398 half_page_size = new_page_size / 2;
1400 switch (zoom_focus) {
1402 leftmost_after_zoom = current_leftmost;
1405 case ZoomFocusRight:
1406 current_rightmost = leftmost_frame + current_page;
1407 if (current_rightmost < new_page_size) {
1408 leftmost_after_zoom = 0;
1410 leftmost_after_zoom = current_rightmost - new_page_size;
1414 case ZoomFocusCenter:
1415 current_center = current_leftmost + (current_page/2);
1416 if (current_center < half_page_size) {
1417 leftmost_after_zoom = 0;
1419 leftmost_after_zoom = current_center - half_page_size;
1423 case ZoomFocusPlayhead:
1424 /* centre playhead */
1425 l = playhead_cursor->current_frame - (new_page_size * 0.5);
1428 leftmost_after_zoom = 0;
1429 } else if (l > max_framepos) {
1430 leftmost_after_zoom = max_framepos - new_page_size;
1432 leftmost_after_zoom = (framepos_t) l;
1436 case ZoomFocusMouse:
1437 /* try to keep the mouse over the same point in the display */
1439 if (!mouse_frame (where, in_track_canvas)) {
1440 /* use playhead instead */
1441 where = playhead_cursor->current_frame;
1443 if (where < half_page_size) {
1444 leftmost_after_zoom = 0;
1446 leftmost_after_zoom = where - half_page_size;
1451 l = - ((new_page_size * ((where - current_leftmost)/(double)current_page)) - where);
1454 leftmost_after_zoom = 0;
1455 } else if (l > max_framepos) {
1456 leftmost_after_zoom = max_framepos - new_page_size;
1458 leftmost_after_zoom = (framepos_t) l;
1465 /* try to keep the edit point in the same place */
1466 where = get_preferred_edit_position ();
1470 double l = - ((new_page_size * ((where - current_leftmost)/(double)current_page)) - where);
1473 leftmost_after_zoom = 0;
1474 } else if (l > max_framepos) {
1475 leftmost_after_zoom = max_framepos - new_page_size;
1477 leftmost_after_zoom = (framepos_t) l;
1481 /* edit point not defined */
1488 // leftmost_after_zoom = min (leftmost_after_zoom, _session->current_end_frame());
1490 reposition_and_zoom (leftmost_after_zoom, nfpu);
1494 Editor::temporal_zoom_region (bool both_axes)
1496 framepos_t start = max_framepos;
1498 set<TimeAxisView*> tracks;
1500 RegionSelection rs = get_regions_from_selection_and_entered ();
1506 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
1508 if ((*i)->region()->position() < start) {
1509 start = (*i)->region()->position();
1512 if ((*i)->region()->last_frame() + 1 > end) {
1513 end = (*i)->region()->last_frame() + 1;
1516 tracks.insert (&((*i)->get_time_axis_view()));
1519 /* now comes an "interesting" hack ... make sure we leave a little space
1520 at each end of the editor so that the zoom doesn't fit the region
1521 precisely to the screen.
1524 GdkScreen* screen = gdk_screen_get_default ();
1525 gint pixwidth = gdk_screen_get_width (screen);
1526 gint mmwidth = gdk_screen_get_width_mm (screen);
1527 double pix_per_mm = (double) pixwidth/ (double) mmwidth;
1528 double one_centimeter_in_pixels = pix_per_mm * 10.0;
1530 if ((start == 0 && end == 0) || end < start) {
1534 framepos_t range = end - start;
1535 double new_fpu = (double)range / (double)_canvas_width;
1536 framepos_t extra_samples = (framepos_t) floor (one_centimeter_in_pixels * new_fpu);
1538 if (start > extra_samples) {
1539 start -= extra_samples;
1544 if (max_framepos - extra_samples > end) {
1545 end += extra_samples;
1550 /* if we're zooming on both axes we need to save track heights etc.
1553 undo_visual_stack.push_back (current_visual_state (both_axes));
1555 PBD::Unwinder<bool> nsv (no_save_visual, true);
1557 temporal_zoom_by_frame (start, end);
1560 uint32_t per_track_height = (uint32_t) floor ((_canvas_height - canvas_timebars_vsize - 10.0) / tracks.size());
1562 /* set visible track heights appropriately */
1564 for (set<TimeAxisView*>::iterator t = tracks.begin(); t != tracks.end(); ++t) {
1565 (*t)->set_height (per_track_height);
1568 /* hide irrelevant tracks */
1570 _routes->suspend_redisplay ();
1572 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1573 if (find (tracks.begin(), tracks.end(), (*i)) == tracks.end()) {
1574 hide_track_in_display (*i);
1578 _routes->resume_redisplay ();
1580 vertical_adjustment.set_value (0.0);
1583 redo_visual_stack.push_back (current_visual_state (both_axes));
1587 Editor::zoom_to_region (bool both_axes)
1589 temporal_zoom_region (both_axes);
1593 Editor::temporal_zoom_selection ()
1595 if (!selection) return;
1597 if (selection->time.empty()) {
1601 framepos_t start = selection->time[clicked_selection].start;
1602 framepos_t end = selection->time[clicked_selection].end;
1604 temporal_zoom_by_frame (start, end);
1608 Editor::temporal_zoom_session ()
1610 ENSURE_GUI_THREAD (*this, &Editor::temporal_zoom_session)
1613 framecnt_t const l = _session->current_end_frame() - _session->current_start_frame();
1614 double s = _session->current_start_frame() - l * 0.01;
1618 framecnt_t const e = _session->current_end_frame() + l * 0.01;
1619 temporal_zoom_by_frame (framecnt_t (s), e);
1624 Editor::temporal_zoom_by_frame (framepos_t start, framepos_t end)
1626 if (!_session) return;
1628 if ((start == 0 && end == 0) || end < start) {
1632 framepos_t range = end - start;
1634 double new_fpu = (double)range / (double)_canvas_width;
1636 framepos_t new_page = (framepos_t) floor (_canvas_width * new_fpu);
1637 framepos_t middle = (framepos_t) floor( (double)start + ((double)range / 2.0f ));
1638 framepos_t new_leftmost = (framepos_t) floor( (double)middle - ((double)new_page/2.0f));
1640 if (new_leftmost > middle) {
1644 if (new_leftmost < 0) {
1648 reposition_and_zoom (new_leftmost, new_fpu);
1652 Editor::temporal_zoom_to_frame (bool coarser, framepos_t frame)
1657 double range_before = frame - leftmost_frame;
1660 new_fpu = frames_per_unit;
1663 new_fpu *= 1.61803399;
1664 range_before *= 1.61803399;
1666 new_fpu = max(1.0,(new_fpu/1.61803399));
1667 range_before /= 1.61803399;
1670 if (new_fpu == frames_per_unit) {
1674 framepos_t new_leftmost = frame - (framepos_t)range_before;
1676 if (new_leftmost > frame) {
1680 if (new_leftmost < 0) {
1684 reposition_and_zoom (new_leftmost, new_fpu);
1689 Editor::choose_new_marker_name(string &name) {
1691 if (!Config->get_name_new_markers()) {
1692 /* don't prompt user for a new name */
1696 ArdourPrompter dialog (true);
1698 dialog.set_prompt (_("New Name:"));
1700 dialog.set_title (_("New Location Marker"));
1702 dialog.set_name ("MarkNameWindow");
1703 dialog.set_size_request (250, -1);
1704 dialog.set_position (Gtk::WIN_POS_MOUSE);
1706 dialog.add_button (Stock::OK, RESPONSE_ACCEPT);
1707 dialog.set_initial_text (name);
1711 switch (dialog.run ()) {
1712 case RESPONSE_ACCEPT:
1718 dialog.get_result(name);
1725 Editor::add_location_from_selection ()
1729 if (selection->time.empty()) {
1733 if (_session == 0 || clicked_axisview == 0) {
1737 framepos_t start = selection->time[clicked_selection].start;
1738 framepos_t end = selection->time[clicked_selection].end;
1740 _session->locations()->next_available_name(rangename,"selection");
1741 Location *location = new Location (*_session, start, end, rangename, Location::IsRangeMarker);
1743 _session->begin_reversible_command (_("add marker"));
1744 XMLNode &before = _session->locations()->get_state();
1745 _session->locations()->add (location, true);
1746 XMLNode &after = _session->locations()->get_state();
1747 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
1748 _session->commit_reversible_command ();
1752 Editor::add_location_mark (framepos_t where)
1756 select_new_marker = true;
1758 _session->locations()->next_available_name(markername,"mark");
1759 if (!choose_new_marker_name(markername)) {
1762 Location *location = new Location (*_session, where, where, markername, Location::IsMark);
1763 _session->begin_reversible_command (_("add marker"));
1764 XMLNode &before = _session->locations()->get_state();
1765 _session->locations()->add (location, true);
1766 XMLNode &after = _session->locations()->get_state();
1767 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
1768 _session->commit_reversible_command ();
1772 Editor::add_location_from_playhead_cursor ()
1774 add_location_mark (_session->audible_frame());
1777 /** Add a range marker around each selected region */
1779 Editor::add_locations_from_region ()
1781 RegionSelection rs = get_regions_from_selection_and_entered ();
1787 _session->begin_reversible_command (selection->regions.size () > 1 ? _("add markers") : _("add marker"));
1788 XMLNode &before = _session->locations()->get_state();
1790 for (RegionSelection::iterator i = rs.begin (); i != rs.end (); ++i) {
1792 boost::shared_ptr<Region> region = (*i)->region ();
1794 Location *location = new Location (*_session, region->position(), region->last_frame(), region->name(), Location::IsRangeMarker);
1796 _session->locations()->add (location, true);
1799 XMLNode &after = _session->locations()->get_state();
1800 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
1801 _session->commit_reversible_command ();
1804 /** Add a single range marker around all selected regions */
1806 Editor::add_location_from_region ()
1808 RegionSelection rs = get_regions_from_selection_and_entered ();
1814 _session->begin_reversible_command (_("add marker"));
1815 XMLNode &before = _session->locations()->get_state();
1819 if (rs.size() > 1) {
1820 _session->locations()->next_available_name(markername, "regions");
1822 RegionView* rv = *(rs.begin());
1823 boost::shared_ptr<Region> region = rv->region();
1824 markername = region->name();
1827 if (!choose_new_marker_name(markername)) {
1831 // single range spanning all selected
1832 Location *location = new Location (*_session, selection->regions.start(), selection->regions.end_frame(), markername, Location::IsRangeMarker);
1833 _session->locations()->add (location, true);
1835 XMLNode &after = _session->locations()->get_state();
1836 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
1837 _session->commit_reversible_command ();
1843 Editor::jump_forward_to_mark ()
1849 Location *location = _session->locations()->first_location_after (playhead_cursor->current_frame);
1852 _session->request_locate (location->start(), _session->transport_rolling());
1854 _session->request_locate (_session->current_end_frame());
1859 Editor::jump_backward_to_mark ()
1865 Location *location = _session->locations()->first_location_before (playhead_cursor->current_frame);
1868 _session->request_locate (location->start(), _session->transport_rolling());
1870 _session->goto_start ();
1877 framepos_t const pos = _session->audible_frame ();
1880 _session->locations()->next_available_name (markername, "mark");
1882 if (!choose_new_marker_name (markername)) {
1886 _session->locations()->add (new Location (*_session, pos, 0, markername, Location::IsMark), true);
1890 Editor::clear_markers ()
1893 _session->begin_reversible_command (_("clear markers"));
1894 XMLNode &before = _session->locations()->get_state();
1895 _session->locations()->clear_markers ();
1896 XMLNode &after = _session->locations()->get_state();
1897 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
1898 _session->commit_reversible_command ();
1903 Editor::clear_ranges ()
1906 _session->begin_reversible_command (_("clear ranges"));
1907 XMLNode &before = _session->locations()->get_state();
1909 Location * looploc = _session->locations()->auto_loop_location();
1910 Location * punchloc = _session->locations()->auto_punch_location();
1911 Location * sessionloc = _session->locations()->session_range_location();
1913 _session->locations()->clear_ranges ();
1915 if (looploc) _session->locations()->add (looploc);
1916 if (punchloc) _session->locations()->add (punchloc);
1917 if (sessionloc) _session->locations()->add (sessionloc);
1919 XMLNode &after = _session->locations()->get_state();
1920 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
1921 _session->commit_reversible_command ();
1926 Editor::clear_locations ()
1928 _session->begin_reversible_command (_("clear locations"));
1929 XMLNode &before = _session->locations()->get_state();
1930 _session->locations()->clear ();
1931 XMLNode &after = _session->locations()->get_state();
1932 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
1933 _session->commit_reversible_command ();
1934 _session->locations()->clear ();
1938 Editor::unhide_markers ()
1940 for (LocationMarkerMap::iterator i = location_markers.begin(); i != location_markers.end(); ++i) {
1941 Location *l = (*i).first;
1942 if (l->is_hidden() && l->is_mark()) {
1943 l->set_hidden(false, this);
1949 Editor::unhide_ranges ()
1951 for (LocationMarkerMap::iterator i = location_markers.begin(); i != location_markers.end(); ++i) {
1952 Location *l = (*i).first;
1953 if (l->is_hidden() && l->is_range_marker()) {
1954 l->set_hidden(false, this);
1959 /* INSERT/REPLACE */
1962 Editor::insert_region_list_drag (boost::shared_ptr<Region> region, int x, int y)
1967 RouteTimeAxisView *rtv = 0;
1968 boost::shared_ptr<Playlist> playlist;
1970 track_canvas->window_to_world (x, y, wx, wy);
1973 event.type = GDK_BUTTON_RELEASE;
1974 event.button.x = wx;
1975 event.button.y = wy;
1977 where = event_frame (&event, &cx, &cy);
1979 if (where < leftmost_frame || where > leftmost_frame + current_page_frames()) {
1980 /* clearly outside canvas area */
1984 std::pair<TimeAxisView*, int> tv = trackview_by_y_position (cy);
1985 if (tv.first == 0) {
1989 if ((rtv = dynamic_cast<RouteTimeAxisView*> (tv.first)) == 0) {
1993 if ((playlist = rtv->playlist()) == 0) {
1999 begin_reversible_command (_("insert dragged region"));
2000 playlist->clear_changes ();
2001 playlist->add_region (RegionFactory::create (region, true), where, 1.0);
2002 _session->add_command(new StatefulDiffCommand (playlist));
2003 commit_reversible_command ();
2007 Editor::insert_route_list_drag (boost::shared_ptr<Route> route, int x, int y)
2011 RouteTimeAxisView *dest_rtv = 0;
2012 RouteTimeAxisView *source_rtv = 0;
2014 track_canvas->window_to_world (x, y, wx, wy);
2015 wx += horizontal_position ();
2016 wy += vertical_adjustment.get_value();
2019 event.type = GDK_BUTTON_RELEASE;
2020 event.button.x = wx;
2021 event.button.y = wy;
2023 event_frame (&event, &cx, &cy);
2025 std::pair<TimeAxisView*, int> const tv = trackview_by_y_position (cy);
2026 if (tv.first == 0) {
2030 if ((dest_rtv = dynamic_cast<RouteTimeAxisView*> (tv.first)) == 0) {
2034 /* use this drag source to add underlay to a track. But we really don't care
2035 about the Route, only the view of the route, so find it first */
2036 for(TrackViewList::iterator it = track_views.begin(); it != track_views.end(); ++it) {
2037 if((source_rtv = dynamic_cast<RouteTimeAxisView*>(*it)) == 0) {
2041 if(source_rtv->route() == route && source_rtv != dest_rtv) {
2042 dest_rtv->add_underlay(source_rtv->view());
2049 Editor::insert_region_list_selection (float times)
2051 RouteTimeAxisView *tv = 0;
2052 boost::shared_ptr<Playlist> playlist;
2054 if (clicked_routeview != 0) {
2055 tv = clicked_routeview;
2056 } else if (!selection->tracks.empty()) {
2057 if ((tv = dynamic_cast<RouteTimeAxisView*>(selection->tracks.front())) == 0) {
2060 } else if (entered_track != 0) {
2061 if ((tv = dynamic_cast<RouteTimeAxisView*>(entered_track)) == 0) {
2068 if ((playlist = tv->playlist()) == 0) {
2072 boost::shared_ptr<Region> region = _regions->get_single_selection ();
2077 begin_reversible_command (_("insert region"));
2078 playlist->clear_changes ();
2079 playlist->add_region ((RegionFactory::create (region, true)), get_preferred_edit_position(), times);
2080 _session->add_command(new StatefulDiffCommand (playlist));
2081 commit_reversible_command ();
2084 /* BUILT-IN EFFECTS */
2087 Editor::reverse_selection ()
2092 /* GAIN ENVELOPE EDITING */
2095 Editor::edit_envelope ()
2102 Editor::transition_to_rolling (bool fwd)
2108 if (_session->config.get_external_sync()) {
2109 switch (Config->get_sync_source()) {
2113 /* transport controlled by the master */
2118 if (_session->is_auditioning()) {
2119 _session->cancel_audition ();
2123 _session->request_transport_speed (fwd ? 1.0f : -1.0f);
2127 Editor::play_from_start ()
2129 _session->request_locate (_session->current_start_frame(), true);
2133 Editor::play_from_edit_point ()
2135 _session->request_locate (get_preferred_edit_position(), true);
2139 Editor::play_from_edit_point_and_return ()
2141 framepos_t start_frame;
2142 framepos_t return_frame;
2144 start_frame = get_preferred_edit_position (true);
2146 if (_session->transport_rolling()) {
2147 _session->request_locate (start_frame, false);
2151 /* don't reset the return frame if its already set */
2153 if ((return_frame = _session->requested_return_frame()) < 0) {
2154 return_frame = _session->audible_frame();
2157 if (start_frame >= 0) {
2158 _session->request_roll_at_and_return (start_frame, return_frame);
2163 Editor::play_selection ()
2165 if (selection->time.empty()) {
2169 _session->request_play_range (&selection->time, true);
2173 Editor::get_preroll ()
2175 return 1.0 /*Config->get_edit_preroll_seconds()*/ * _session->frame_rate();
2180 Editor::maybe_locate_with_edit_preroll ( framepos_t location )
2182 if ( _session->transport_rolling() || !Config->get_always_play_range() )
2185 location -= get_preroll();
2187 //don't try to locate before the beginning of time
2191 //if follow_playhead is on, keep the playhead on the screen
2192 if ( _follow_playhead )
2193 if ( location < leftmost_frame )
2194 location = leftmost_frame;
2196 _session->request_locate( location );
2200 Editor::play_with_preroll ()
2202 if (selection->time.empty()) {
2205 framepos_t preroll = get_preroll();
2207 framepos_t start = 0;
2208 if (selection->time[clicked_selection].start > preroll)
2209 start = selection->time[clicked_selection].start - preroll;
2211 framepos_t end = selection->time[clicked_selection].end + preroll;
2213 AudioRange ar (start, end, 0);
2214 list<AudioRange> lar;
2217 _session->request_play_range (&lar, true);
2222 Editor::play_location (Location& location)
2224 if (location.start() <= location.end()) {
2228 _session->request_bounded_roll (location.start(), location.end());
2232 Editor::loop_location (Location& location)
2234 if (location.start() <= location.end()) {
2240 if ((tll = transport_loop_location()) != 0) {
2241 tll->set (location.start(), location.end());
2243 // enable looping, reposition and start rolling
2244 _session->request_play_loop (true);
2245 _session->request_locate (tll->start(), true);
2250 Editor::do_layer_operation (LayerOperation op)
2252 if (selection->regions.empty ()) {
2256 bool const multiple = selection->regions.size() > 1;
2260 begin_reversible_command (_("raise regions"));
2262 begin_reversible_command (_("raise region"));
2268 begin_reversible_command (_("raise regions to top"));
2270 begin_reversible_command (_("raise region to top"));
2276 begin_reversible_command (_("lower regions"));
2278 begin_reversible_command (_("lower region"));
2284 begin_reversible_command (_("lower regions to bottom"));
2286 begin_reversible_command (_("lower region"));
2291 set<boost::shared_ptr<Playlist> > playlists = selection->regions.playlists ();
2292 for (set<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
2293 (*i)->clear_owned_changes ();
2296 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
2297 boost::shared_ptr<Region> r = (*i)->region ();
2309 r->lower_to_bottom ();
2313 for (set<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
2314 vector<Command*> cmds;
2316 _session->add_commands (cmds);
2319 commit_reversible_command ();
2323 Editor::raise_region ()
2325 do_layer_operation (Raise);
2329 Editor::raise_region_to_top ()
2331 do_layer_operation (RaiseToTop);
2335 Editor::lower_region ()
2337 do_layer_operation (Lower);
2341 Editor::lower_region_to_bottom ()
2343 do_layer_operation (LowerToBottom);
2346 /** Show the region editor for the selected regions */
2348 Editor::show_region_properties ()
2350 selection->foreach_regionview (&RegionView::show_region_editor);
2353 /** Show the midi list editor for the selected MIDI regions */
2355 Editor::show_midi_list_editor ()
2357 selection->foreach_midi_regionview (&MidiRegionView::show_list_editor);
2361 Editor::rename_region ()
2363 RegionSelection rs = get_regions_from_selection_and_entered ();
2369 ArdourDialog d (*this, _("Rename Region"), true, false);
2371 Label label (_("New name:"));
2374 hbox.set_spacing (6);
2375 hbox.pack_start (label, false, false);
2376 hbox.pack_start (entry, true, true);
2378 d.get_vbox()->set_border_width (12);
2379 d.get_vbox()->pack_start (hbox, false, false);
2381 d.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
2382 d.add_button(Gtk::Stock::OK, Gtk::RESPONSE_OK);
2384 d.set_size_request (300, -1);
2385 d.set_position (Gtk::WIN_POS_MOUSE);
2387 entry.set_text (rs.front()->region()->name());
2388 entry.select_region (0, -1);
2390 entry.signal_activate().connect (sigc::bind (sigc::mem_fun (d, &Dialog::response), RESPONSE_OK));
2396 int const ret = d.run();
2400 if (ret != RESPONSE_OK) {
2404 std::string str = entry.get_text();
2405 strip_whitespace_edges (str);
2407 rs.front()->region()->set_name (str);
2408 _regions->redisplay ();
2413 Editor::audition_playlist_region_via_route (boost::shared_ptr<Region> region, Route& route)
2415 if (_session->is_auditioning()) {
2416 _session->cancel_audition ();
2419 // note: some potential for creativity here, because region doesn't
2420 // have to belong to the playlist that Route is handling
2422 // bool was_soloed = route.soloed();
2424 route.set_solo (true, this);
2426 _session->request_bounded_roll (region->position(), region->position() + region->length());
2428 /* XXX how to unset the solo state ? */
2431 /** Start an audition of the first selected region */
2433 Editor::play_edit_range ()
2435 framepos_t start, end;
2437 if (get_edit_op_range (start, end)) {
2438 _session->request_bounded_roll (start, end);
2443 Editor::play_selected_region ()
2445 framepos_t start = max_framepos;
2448 RegionSelection rs = get_regions_from_selection_and_entered ();
2454 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
2455 if ((*i)->region()->position() < start) {
2456 start = (*i)->region()->position();
2458 if ((*i)->region()->last_frame() + 1 > end) {
2459 end = (*i)->region()->last_frame() + 1;
2463 _session->request_bounded_roll (start, end);
2467 Editor::audition_playlist_region_standalone (boost::shared_ptr<Region> region)
2469 _session->audition_region (region);
2473 Editor::region_from_selection ()
2475 if (clicked_axisview == 0) {
2479 if (selection->time.empty()) {
2483 framepos_t start = selection->time[clicked_selection].start;
2484 framepos_t end = selection->time[clicked_selection].end;
2486 TrackViewList tracks = get_tracks_for_range_action ();
2488 framepos_t selection_cnt = end - start + 1;
2490 for (TrackSelection::iterator i = tracks.begin(); i != tracks.end(); ++i) {
2491 boost::shared_ptr<Region> current;
2492 boost::shared_ptr<Playlist> pl;
2493 framepos_t internal_start;
2496 if ((pl = (*i)->playlist()) == 0) {
2500 if ((current = pl->top_region_at (start)) == 0) {
2504 internal_start = start - current->position();
2505 RegionFactory::region_name (new_name, current->name(), true);
2509 plist.add (ARDOUR::Properties::start, current->start() + internal_start);
2510 plist.add (ARDOUR::Properties::length, selection_cnt);
2511 plist.add (ARDOUR::Properties::name, new_name);
2512 plist.add (ARDOUR::Properties::layer, 0);
2514 boost::shared_ptr<Region> region (RegionFactory::create (current, plist));
2519 Editor::create_region_from_selection (vector<boost::shared_ptr<Region> >& new_regions)
2521 if (selection->time.empty() || selection->tracks.empty()) {
2525 framepos_t start = selection->time[clicked_selection].start;
2526 framepos_t end = selection->time[clicked_selection].end;
2528 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
2529 sort_track_selection (ts);
2531 for (TrackSelection::iterator i = ts.begin(); i != ts.end(); ++i) {
2532 boost::shared_ptr<Region> current;
2533 boost::shared_ptr<Playlist> playlist;
2534 framepos_t internal_start;
2537 if ((playlist = (*i)->playlist()) == 0) {
2541 if ((current = playlist->top_region_at(start)) == 0) {
2545 internal_start = start - current->position();
2546 RegionFactory::region_name (new_name, current->name(), true);
2550 plist.add (ARDOUR::Properties::start, current->start() + internal_start);
2551 plist.add (ARDOUR::Properties::length, end - start + 1);
2552 plist.add (ARDOUR::Properties::name, new_name);
2554 new_regions.push_back (RegionFactory::create (current, plist));
2559 Editor::split_multichannel_region ()
2561 RegionSelection rs = get_regions_from_selection_and_entered ();
2567 vector< boost::shared_ptr<Region> > v;
2569 for (list<RegionView*>::iterator x = rs.begin(); x != rs.end(); ++x) {
2570 (*x)->region()->separate_by_channel (*_session, v);
2575 Editor::new_region_from_selection ()
2577 region_from_selection ();
2578 cancel_selection ();
2582 add_if_covered (RegionView* rv, const AudioRange* ar, RegionSelection* rs)
2584 switch (rv->region()->coverage (ar->start, ar->end - 1)) {
2585 case Evoral::OverlapNone:
2593 * - selected tracks, or if there are none...
2594 * - tracks containing selected regions, or if there are none...
2599 Editor::get_tracks_for_range_action () const
2603 if (selection->tracks.empty()) {
2605 /* use tracks with selected regions */
2607 RegionSelection rs = selection->regions;
2609 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
2610 TimeAxisView* tv = &(*i)->get_time_axis_view();
2612 if (!t.contains (tv)) {
2618 /* no regions and no tracks: use all tracks */
2624 t = selection->tracks;
2627 return t.filter_to_unique_playlists();
2631 Editor::separate_regions_between (const TimeSelection& ts)
2633 bool in_command = false;
2634 boost::shared_ptr<Playlist> playlist;
2635 RegionSelection new_selection;
2637 TrackViewList tmptracks = get_tracks_for_range_action ();
2638 sort_track_selection (tmptracks);
2640 for (TrackSelection::iterator i = tmptracks.begin(); i != tmptracks.end(); ++i) {
2642 RouteTimeAxisView* rtv;
2644 if ((rtv = dynamic_cast<RouteTimeAxisView*> ((*i))) != 0) {
2646 if (rtv->is_track()) {
2648 /* no edits to destructive tracks */
2650 if (rtv->track()->destructive()) {
2654 if ((playlist = rtv->playlist()) != 0) {
2656 playlist->clear_changes ();
2658 /* XXX need to consider musical time selections here at some point */
2660 double speed = rtv->track()->speed();
2663 for (list<AudioRange>::const_iterator t = ts.begin(); t != ts.end(); ++t) {
2665 sigc::connection c = rtv->view()->RegionViewAdded.connect (
2666 sigc::mem_fun(*this, &Editor::collect_new_region_view));
2668 latest_regionviews.clear ();
2670 playlist->partition ((framepos_t)((*t).start * speed),
2671 (framepos_t)((*t).end * speed), false);
2675 if (!latest_regionviews.empty()) {
2677 rtv->view()->foreach_regionview (sigc::bind (
2678 sigc::ptr_fun (add_if_covered),
2679 &(*t), &new_selection));
2682 begin_reversible_command (_("separate"));
2686 /* pick up changes to existing regions */
2688 vector<Command*> cmds;
2689 playlist->rdiff (cmds);
2690 _session->add_commands (cmds);
2692 /* pick up changes to the playlist itself (adds/removes)
2695 _session->add_command(new StatefulDiffCommand (playlist));
2704 selection->set (new_selection);
2705 set_mouse_mode (MouseObject);
2707 commit_reversible_command ();
2711 struct PlaylistState {
2712 boost::shared_ptr<Playlist> playlist;
2716 /** Take tracks from get_tracks_for_range_action and cut any regions
2717 * on those tracks so that the tracks are empty over the time
2721 Editor::separate_region_from_selection ()
2723 /* preferentially use *all* ranges in the time selection if we're in range mode
2724 to allow discontiguous operation, since get_edit_op_range() currently
2725 returns a single range.
2728 if (mouse_mode == MouseRange && !selection->time.empty()) {
2730 separate_regions_between (selection->time);
2737 if (get_edit_op_range (start, end)) {
2739 AudioRange ar (start, end, 1);
2743 separate_regions_between (ts);
2749 Editor::separate_region_from_punch ()
2751 Location* loc = _session->locations()->auto_punch_location();
2753 separate_regions_using_location (*loc);
2758 Editor::separate_region_from_loop ()
2760 Location* loc = _session->locations()->auto_loop_location();
2762 separate_regions_using_location (*loc);
2767 Editor::separate_regions_using_location (Location& loc)
2769 if (loc.is_mark()) {
2773 AudioRange ar (loc.start(), loc.end(), 1);
2778 separate_regions_between (ts);
2781 /** Separate regions under the selected region */
2783 Editor::separate_under_selected_regions ()
2785 vector<PlaylistState> playlists;
2789 rs = get_regions_from_selection_and_entered();
2791 if (!_session || rs.empty()) {
2795 begin_reversible_command (_("separate region under"));
2797 list<boost::shared_ptr<Region> > regions_to_remove;
2799 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
2800 // we can't just remove the region(s) in this loop because
2801 // this removes them from the RegionSelection, and they thus
2802 // disappear from underneath the iterator, and the ++i above
2803 // SEGVs in a puzzling fashion.
2805 // so, first iterate over the regions to be removed from rs and
2806 // add them to the regions_to_remove list, and then
2807 // iterate over the list to actually remove them.
2809 regions_to_remove.push_back ((*i)->region());
2812 for (list<boost::shared_ptr<Region> >::iterator rl = regions_to_remove.begin(); rl != regions_to_remove.end(); ++rl) {
2814 boost::shared_ptr<Playlist> playlist = (*rl)->playlist();
2817 // is this check necessary?
2821 vector<PlaylistState>::iterator i;
2823 //only take state if this is a new playlist.
2824 for (i = playlists.begin(); i != playlists.end(); ++i) {
2825 if ((*i).playlist == playlist) {
2830 if (i == playlists.end()) {
2832 PlaylistState before;
2833 before.playlist = playlist;
2834 before.before = &playlist->get_state();
2836 playlist->freeze ();
2837 playlists.push_back(before);
2840 //Partition on the region bounds
2841 playlist->partition ((*rl)->first_frame() - 1, (*rl)->last_frame() + 1, true);
2843 //Re-add region that was just removed due to the partition operation
2844 playlist->add_region( (*rl), (*rl)->first_frame() );
2847 vector<PlaylistState>::iterator pl;
2849 for (pl = playlists.begin(); pl != playlists.end(); ++pl) {
2850 (*pl).playlist->thaw ();
2851 _session->add_command(new MementoCommand<Playlist>(*(*pl).playlist, (*pl).before, &(*pl).playlist->get_state()));
2854 commit_reversible_command ();
2858 Editor::crop_region_to_selection ()
2860 if (!selection->time.empty()) {
2862 crop_region_to (selection->time.start(), selection->time.end_frame());
2869 if (get_edit_op_range (start, end)) {
2870 crop_region_to (start, end);
2877 Editor::crop_region_to (framepos_t start, framepos_t end)
2879 vector<boost::shared_ptr<Playlist> > playlists;
2880 boost::shared_ptr<Playlist> playlist;
2883 if (selection->tracks.empty()) {
2884 ts = track_views.filter_to_unique_playlists();
2886 ts = selection->tracks.filter_to_unique_playlists ();
2889 sort_track_selection (ts);
2891 for (TrackSelection::iterator i = ts.begin(); i != ts.end(); ++i) {
2893 RouteTimeAxisView* rtv;
2895 if ((rtv = dynamic_cast<RouteTimeAxisView*> ((*i))) != 0) {
2897 boost::shared_ptr<Track> t = rtv->track();
2899 if (t != 0 && ! t->destructive()) {
2901 if ((playlist = rtv->playlist()) != 0) {
2902 playlists.push_back (playlist);
2908 if (playlists.empty()) {
2912 framepos_t the_start;
2916 begin_reversible_command (_("trim to selection"));
2918 for (vector<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
2920 boost::shared_ptr<Region> region;
2924 if ((region = (*i)->top_region_at(the_start)) == 0) {
2928 /* now adjust lengths to that we do the right thing
2929 if the selection extends beyond the region
2932 the_start = max (the_start, (framepos_t) region->position());
2933 if (max_framepos - the_start < region->length()) {
2934 the_end = the_start + region->length() - 1;
2936 the_end = max_framepos;
2938 the_end = min (end, the_end);
2939 cnt = the_end - the_start + 1;
2941 region->clear_changes ();
2942 region->trim_to (the_start, cnt);
2943 _session->add_command (new StatefulDiffCommand (region));
2946 commit_reversible_command ();
2950 Editor::region_fill_track ()
2952 RegionSelection rs = get_regions_from_selection_and_entered ();
2954 if (!_session || rs.empty()) {
2958 framepos_t const end = _session->current_end_frame ();
2960 begin_reversible_command (Operations::region_fill);
2962 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
2964 boost::shared_ptr<Region> region ((*i)->region());
2966 boost::shared_ptr<Playlist> pl = region->playlist();
2968 if (end <= region->last_frame()) {
2972 double times = (double) (end - region->last_frame()) / (double) region->length();
2978 pl->clear_changes ();
2979 pl->add_region (RegionFactory::create (region, true), region->last_frame(), times);
2980 _session->add_command (new StatefulDiffCommand (pl));
2983 commit_reversible_command ();
2987 Editor::region_fill_selection ()
2989 if (clicked_routeview == 0 || !clicked_routeview->is_audio_track()) {
2993 if (selection->time.empty()) {
2997 boost::shared_ptr<Region> region = _regions->get_single_selection ();
3002 framepos_t start = selection->time[clicked_selection].start;
3003 framepos_t end = selection->time[clicked_selection].end;
3005 boost::shared_ptr<Playlist> playlist;
3007 if (selection->tracks.empty()) {
3011 framepos_t selection_length = end - start;
3012 float times = (float)selection_length / region->length();
3014 begin_reversible_command (Operations::fill_selection);
3016 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
3018 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
3020 if ((playlist = (*i)->playlist()) == 0) {
3024 playlist->clear_changes ();
3025 playlist->add_region (RegionFactory::create (region, true), start, times);
3026 _session->add_command (new StatefulDiffCommand (playlist));
3029 commit_reversible_command ();
3033 Editor::set_region_sync_position ()
3035 set_sync_point (get_preferred_edit_position (), get_regions_from_selection_and_edit_point ());
3039 Editor::set_sync_point (framepos_t where, const RegionSelection& rs)
3041 bool in_command = false;
3043 for (RegionSelection::const_iterator r = rs.begin(); r != rs.end(); ++r) {
3045 if (!(*r)->region()->covers (where)) {
3049 boost::shared_ptr<Region> region ((*r)->region());
3052 begin_reversible_command (_("set sync point"));
3056 region->clear_changes ();
3057 region->set_sync_position (where);
3058 _session->add_command(new StatefulDiffCommand (region));
3062 commit_reversible_command ();
3066 /** Remove the sync positions of the selection */
3068 Editor::remove_region_sync ()
3070 RegionSelection rs = get_regions_from_selection_and_entered ();
3076 begin_reversible_command (_("remove region sync"));
3078 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3080 (*i)->region()->clear_changes ();
3081 (*i)->region()->clear_sync_position ();
3082 _session->add_command(new StatefulDiffCommand ((*i)->region()));
3085 commit_reversible_command ();
3089 Editor::naturalize_region ()
3091 RegionSelection rs = get_regions_from_selection_and_entered ();
3097 if (rs.size() > 1) {
3098 begin_reversible_command (_("move regions to original position"));
3100 begin_reversible_command (_("move region to original position"));
3103 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3104 (*i)->region()->clear_changes ();
3105 (*i)->region()->move_to_natural_position ();
3106 _session->add_command (new StatefulDiffCommand ((*i)->region()));
3109 commit_reversible_command ();
3113 Editor::align_regions (RegionPoint what)
3115 RegionSelection const rs = get_regions_from_selection_and_edit_point ();
3121 begin_reversible_command (_("align selection"));
3123 framepos_t const position = get_preferred_edit_position ();
3125 for (RegionSelection::const_iterator i = rs.begin(); i != rs.end(); ++i) {
3126 align_region_internal ((*i)->region(), what, position);
3129 commit_reversible_command ();
3132 struct RegionSortByTime {
3133 bool operator() (const RegionView* a, const RegionView* b) {
3134 return a->region()->position() < b->region()->position();
3139 Editor::align_regions_relative (RegionPoint point)
3141 RegionSelection const rs = get_regions_from_selection_and_edit_point ();
3147 framepos_t const position = get_preferred_edit_position ();
3149 framepos_t distance = 0;
3153 list<RegionView*> sorted;
3154 rs.by_position (sorted);
3156 boost::shared_ptr<Region> r ((*sorted.begin())->region());
3161 if (position > r->position()) {
3162 distance = position - r->position();
3164 distance = r->position() - position;
3170 if (position > r->last_frame()) {
3171 distance = position - r->last_frame();
3172 pos = r->position() + distance;
3174 distance = r->last_frame() - position;
3175 pos = r->position() - distance;
3181 pos = r->adjust_to_sync (position);
3182 if (pos > r->position()) {
3183 distance = pos - r->position();
3185 distance = r->position() - pos;
3191 if (pos == r->position()) {
3195 begin_reversible_command (_("align selection (relative)"));
3197 /* move first one specially */
3199 r->clear_changes ();
3200 r->set_position (pos);
3201 _session->add_command(new StatefulDiffCommand (r));
3203 /* move rest by the same amount */
3207 for (list<RegionView*>::iterator i = sorted.begin(); i != sorted.end(); ++i) {
3209 boost::shared_ptr<Region> region ((*i)->region());
3211 region->clear_changes ();
3214 region->set_position (region->position() + distance);
3216 region->set_position (region->position() - distance);
3219 _session->add_command(new StatefulDiffCommand (region));
3223 commit_reversible_command ();
3227 Editor::align_region (boost::shared_ptr<Region> region, RegionPoint point, framepos_t position)
3229 begin_reversible_command (_("align region"));
3230 align_region_internal (region, point, position);
3231 commit_reversible_command ();
3235 Editor::align_region_internal (boost::shared_ptr<Region> region, RegionPoint point, framepos_t position)
3237 region->clear_changes ();
3241 region->set_position (region->adjust_to_sync (position));
3245 if (position > region->length()) {
3246 region->set_position (position - region->length());
3251 region->set_position (position);
3255 _session->add_command(new StatefulDiffCommand (region));
3259 Editor::trim_region_front ()
3265 Editor::trim_region_back ()
3267 trim_region (false);
3271 Editor::trim_region (bool front)
3273 framepos_t where = get_preferred_edit_position();
3274 RegionSelection rs = get_regions_from_selection_and_edit_point ();
3280 begin_reversible_command (front ? _("trim front") : _("trim back"));
3282 for (list<RegionView*>::const_iterator i = rs.by_layer().begin(); i != rs.by_layer().end(); ++i) {
3283 if (!(*i)->region()->locked()) {
3285 (*i)->region()->clear_changes ();
3288 (*i)->region()->trim_front (where);
3289 maybe_locate_with_edit_preroll ( where );
3291 (*i)->region()->trim_end (where);
3292 maybe_locate_with_edit_preroll ( where );
3295 _session->add_command (new StatefulDiffCommand ((*i)->region()));
3299 commit_reversible_command ();
3302 /** Trim the end of the selected regions to the position of the edit cursor */
3304 Editor::trim_region_to_loop ()
3306 Location* loc = _session->locations()->auto_loop_location();
3310 trim_region_to_location (*loc, _("trim to loop"));
3314 Editor::trim_region_to_punch ()
3316 Location* loc = _session->locations()->auto_punch_location();
3320 trim_region_to_location (*loc, _("trim to punch"));
3324 Editor::trim_region_to_location (const Location& loc, const char* str)
3326 RegionSelection rs = get_regions_from_selection_and_entered ();
3328 begin_reversible_command (str);
3330 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
3331 RegionView* rv = (*x);
3333 /* require region to span proposed trim */
3334 switch (rv->region()->coverage (loc.start(), loc.end())) {
3335 case Evoral::OverlapInternal:
3341 RouteTimeAxisView* tav = dynamic_cast<RouteTimeAxisView*> (&rv->get_time_axis_view());
3350 if (tav->track() != 0) {
3351 speed = tav->track()->speed();
3354 start = session_frame_to_track_frame (loc.start(), speed);
3355 end = session_frame_to_track_frame (loc.end(), speed);
3357 rv->region()->clear_changes ();
3358 rv->region()->trim_to (start, (end - start));
3359 _session->add_command(new StatefulDiffCommand (rv->region()));
3362 commit_reversible_command ();
3366 Editor::trim_region_to_previous_region_end ()
3368 return trim_to_region(false);
3372 Editor::trim_region_to_next_region_start ()
3374 return trim_to_region(true);
3378 Editor::trim_to_region(bool forward)
3380 RegionSelection rs = get_regions_from_selection_and_entered ();
3382 begin_reversible_command (_("trim to region"));
3384 boost::shared_ptr<Region> next_region;
3386 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
3388 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*x);
3394 AudioTimeAxisView* atav = dynamic_cast<AudioTimeAxisView*> (&arv->get_time_axis_view());
3402 if (atav->track() != 0) {
3403 speed = atav->track()->speed();
3407 boost::shared_ptr<Region> region = arv->region();
3408 boost::shared_ptr<Playlist> playlist (region->playlist());
3410 region->clear_changes ();
3414 next_region = playlist->find_next_region (region->first_frame(), Start, 1);
3420 region->trim_end((framepos_t) ( (next_region->first_frame() - 1) * speed));
3421 arv->region_changed (PropertyChange (ARDOUR::Properties::length));
3425 next_region = playlist->find_next_region (region->first_frame(), Start, 0);
3431 region->trim_front((framepos_t) ((next_region->last_frame() + 1) * speed));
3433 arv->region_changed (ARDOUR::bounds_change);
3436 _session->add_command(new StatefulDiffCommand (region));
3439 commit_reversible_command ();
3443 Editor::unfreeze_route ()
3445 if (clicked_routeview == 0 || !clicked_routeview->is_track()) {
3449 clicked_routeview->track()->unfreeze ();
3453 Editor::_freeze_thread (void* arg)
3455 return static_cast<Editor*>(arg)->freeze_thread ();
3459 Editor::freeze_thread ()
3461 /* create event pool because we may need to talk to the session */
3462 SessionEvent::create_per_thread_pool ("freeze events", 64);
3463 /* create per-thread buffers for process() tree to use */
3464 current_interthread_info->process_thread.get_buffers ();
3465 clicked_routeview->audio_track()->freeze_me (*current_interthread_info);
3466 current_interthread_info->done = true;
3467 current_interthread_info->process_thread.drop_buffers();
3472 Editor::freeze_route ()
3478 /* stop transport before we start. this is important */
3480 _session->request_transport_speed (0.0);
3482 /* wait for just a little while, because the above call is asynchronous */
3486 if (clicked_routeview == 0 || !clicked_routeview->is_audio_track()) {
3490 if (!clicked_routeview->track()->bounceable (clicked_routeview->track()->main_outs(), true)) {
3492 _("This track/bus cannot be frozen because the signal adds or loses channels before reaching the outputs.\n"
3493 "This is typically caused by plugins that generate stereo output from mono input or vice versa.")
3495 d.set_title (_("Cannot freeze"));
3500 if (clicked_routeview->track()->has_external_redirects()) {
3501 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"
3502 "Freezing will only process the signal as far as the first send/insert/return."),
3503 clicked_routeview->track()->name()), true, MESSAGE_INFO, BUTTONS_NONE, true);
3505 d.add_button (_("Freeze anyway"), Gtk::RESPONSE_OK);
3506 d.add_button (_("Don't freeze"), Gtk::RESPONSE_CANCEL);
3507 d.set_title (_("Freeze Limits"));
3509 int response = d.run ();
3512 case Gtk::RESPONSE_CANCEL:
3519 InterThreadInfo itt;
3520 current_interthread_info = &itt;
3522 InterthreadProgressWindow ipw (current_interthread_info, _("Freeze"), _("Cancel Freeze"));
3524 pthread_create_and_store (X_("freezer"), &itt.thread, _freeze_thread, this);
3526 set_canvas_cursor (_cursors->wait);
3528 while (!itt.done && !itt.cancel) {
3529 gtk_main_iteration ();
3532 current_interthread_info = 0;
3533 set_canvas_cursor (current_canvas_cursor);
3537 Editor::bounce_range_selection (bool replace, bool enable_processing)
3539 if (selection->time.empty()) {
3543 TrackSelection views = selection->tracks;
3545 for (TrackViewList::iterator i = views.begin(); i != views.end(); ++i) {
3547 if (enable_processing) {
3549 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*i);
3551 if (rtv && rtv->track() && replace && enable_processing && !rtv->track()->bounceable (rtv->track()->main_outs(), false)) {
3553 _("You can't perform this operation because the processing of the signal "
3554 "will cause one or more of the tracks will end up with a region with more channels than this track has inputs.\n\n"
3555 "You can do this without processing, which is a different operation.")
3557 d.set_title (_("Cannot bounce"));
3564 framepos_t start = selection->time[clicked_selection].start;
3565 framepos_t end = selection->time[clicked_selection].end;
3566 framepos_t cnt = end - start + 1;
3568 begin_reversible_command (_("bounce range"));
3570 for (TrackViewList::iterator i = views.begin(); i != views.end(); ++i) {
3572 RouteTimeAxisView* rtv;
3574 if ((rtv = dynamic_cast<RouteTimeAxisView*> (*i)) == 0) {
3578 boost::shared_ptr<Playlist> playlist;
3580 if ((playlist = rtv->playlist()) == 0) {
3584 InterThreadInfo itt;
3586 playlist->clear_changes ();
3587 playlist->clear_owned_changes ();
3589 boost::shared_ptr<Region> r;
3591 if (enable_processing) {
3592 r = rtv->track()->bounce_range (start, start+cnt, itt, rtv->track()->main_outs(), false);
3594 r = rtv->track()->bounce_range (start, start+cnt, itt, boost::shared_ptr<Processor>(), false);
3602 list<AudioRange> ranges;
3603 ranges.push_back (AudioRange (start, start+cnt, 0));
3604 playlist->cut (ranges); // discard result
3605 playlist->add_region (r, start);
3608 vector<Command*> cmds;
3609 playlist->rdiff (cmds);
3610 _session->add_commands (cmds);
3612 _session->add_command (new StatefulDiffCommand (playlist));
3615 commit_reversible_command ();
3618 /** Delete selected regions, automation points or a time range */
3625 /** Cut selected regions, automation points or a time range */
3632 /** Copy selected regions, automation points or a time range */
3640 /** @return true if a Cut, Copy or Clear is possible */
3642 Editor::can_cut_copy () const
3644 switch (effective_mouse_mode()) {
3647 if (!selection->regions.empty() || !selection->points.empty()) {
3653 if (!selection->time.empty()) {
3666 /** Cut, copy or clear selected regions, automation points or a time range.
3667 * @param op Operation (Cut, Copy or Clear)
3670 Editor::cut_copy (CutCopyOp op)
3672 /* only cancel selection if cut/copy is successful.*/
3678 opname = _("delete");
3687 opname = _("clear");
3691 /* if we're deleting something, and the mouse is still pressed,
3692 the thing we started a drag for will be gone when we release
3693 the mouse button(s). avoid this. see part 2 at the end of
3697 if (op == Delete || op == Cut || op == Clear) {
3698 if (_drags->active ()) {
3703 if ( op != Clear ) //"Delete" doesn't change copy/paste buf
3704 cut_buffer->clear ();
3706 if (entered_marker) {
3708 /* cut/delete op while pointing at a marker */
3711 Location* loc = find_location_from_marker (entered_marker, ignored);
3713 if (_session && loc) {
3714 Glib::signal_idle().connect (sigc::bind (sigc::mem_fun(*this, &Editor::really_remove_marker), loc));
3721 if (internal_editing()) {
3723 switch (effective_mouse_mode()) {
3736 /* we only want to cut regions if some are selected */
3738 if (!selection->regions.empty()) {
3739 rs = get_regions_from_selection ();
3742 switch (effective_mouse_mode()) {
3745 //find regions's gain line
3746 AudioRegionView *rview = dynamic_cast<AudioRegionView*>(clicked_regionview);
3747 AutomationTimeAxisView *tview = dynamic_cast<AutomationTimeAxisView*>(clicked_trackview);
3749 AudioRegionGainLine *line = rview->get_gain_line();
3752 //cut region gain points in the selection
3753 AutomationList& alist (line->the_list());
3754 XMLNode &before = alist.get_state();
3755 AutomationList* what_we_got = 0;
3756 if ((what_we_got = alist.cut (selection->time.front().start - rview->audio_region()->position(), selection->time.front().end - rview->audio_region()->position())) != 0) {
3757 session->add_command(new MementoCommand<AutomationList>(alist, &before, &alist.get_state()));
3762 rview->set_envelope_visible(true);
3763 rview->audio_region()->set_envelope_active(true);
3766 AutomationLine *line = *(tview->lines.begin());
3769 //cut auto points in the selection
3770 AutomationList& alist (line->the_list());
3771 XMLNode &before = alist.get_state();
3772 AutomationList* what_we_got = 0;
3773 if ((what_we_got = alist.cut (selection->time.front().start, selection->time.front().end)) != 0) {
3774 session->add_command(new MementoCommand<AutomationList>(alist, &before, &alist.get_state()));
3784 if (!rs.empty() || !selection->points.empty()) {
3785 begin_reversible_command (opname + _(" objects"));
3788 cut_copy_regions (op, rs);
3790 if (op == Cut || op == Delete) {
3791 selection->clear_regions ();
3795 if (!selection->points.empty()) {
3796 cut_copy_points (op);
3798 if (op == Cut || op == Delete) {
3799 selection->clear_points ();
3803 commit_reversible_command ();
3807 if (selection->time.empty()) {
3808 framepos_t start, end;
3809 if (!get_edit_op_range (start, end)) {
3812 selection->set (start, end);
3815 begin_reversible_command (opname + _(" range"));
3816 cut_copy_ranges (op);
3817 commit_reversible_command ();
3819 if (op == Cut || op == Delete) {
3820 selection->clear_time ();
3830 if (op == Delete || op == Cut || op == Clear) {
3835 struct AutomationRecord {
3836 AutomationRecord () : state (0) {}
3837 AutomationRecord (XMLNode* s) : state (s) {}
3839 XMLNode* state; ///< state before any operation
3840 boost::shared_ptr<Evoral::ControlList> copy; ///< copied events for the cut buffer
3843 /** Cut, copy or clear selected automation points.
3844 * @param op Operation (Cut, Copy or Clear)
3847 Editor::cut_copy_points (CutCopyOp op)
3849 if (selection->points.empty ()) {
3853 /* XXX: not ideal, as there may be more than one track involved in the point selection */
3854 _last_cut_copy_source_track = &selection->points.front()->line().trackview;
3856 /* Keep a record of the AutomationLists that we end up using in this operation */
3857 typedef std::map<boost::shared_ptr<AutomationList>, AutomationRecord> Lists;
3860 /* Go through all selected points, making an AutomationRecord for each distinct AutomationList */
3861 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
3862 boost::shared_ptr<AutomationList> al = (*i)->line().the_list();
3863 if (lists.find (al) == lists.end ()) {
3864 /* We haven't seen this list yet, so make a record for it. This includes
3865 taking a copy of its current state, in case this is needed for undo later.
3867 lists[al] = AutomationRecord (&al->get_state ());
3871 if (op == Cut || op == Copy) {
3872 /* This operation will involve putting things in the cut buffer, so create an empty
3873 ControlList for each of our source lists to put the cut buffer data in.
3875 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
3876 i->second.copy = i->first->create (i->first->parameter ());
3879 /* Add all selected points to the relevant copy ControlLists */
3880 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
3881 boost::shared_ptr<AutomationList> al = (*i)->line().the_list();
3882 AutomationList::const_iterator j = (*i)->model ();
3883 lists[al].copy->add ((*j)->when, (*j)->value);
3886 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
3887 /* Correct this copy list so that it starts at time 0 */
3888 double const start = i->second.copy->front()->when;
3889 for (AutomationList::iterator j = i->second.copy->begin(); j != i->second.copy->end(); ++j) {
3890 (*j)->when -= start;
3893 /* And add it to the cut buffer */
3894 cut_buffer->add (i->second.copy);
3898 if (op == Delete || op == Cut) {
3899 /* This operation needs to remove things from the main AutomationList, so do that now */
3901 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
3902 i->first->freeze ();
3905 /* Remove each selected point from its AutomationList */
3906 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
3907 boost::shared_ptr<AutomationList> al = (*i)->line().the_list();
3908 al->erase ((*i)->model ());
3911 /* Thaw the lists and add undo records for them */
3912 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
3913 boost::shared_ptr<AutomationList> al = i->first;
3915 _session->add_command (new MementoCommand<AutomationList> (*al.get(), i->second.state, &(al->get_state ())));
3920 /** Cut, copy or clear selected automation points.
3921 * @param op Operation (Cut, Copy or Clear)
3924 Editor::cut_copy_midi (CutCopyOp op)
3926 for (MidiRegionSelection::iterator i = selection->midi_regions.begin(); i != selection->midi_regions.end(); ++i) {
3927 MidiRegionView* mrv = *i;
3928 mrv->cut_copy_clear (op);
3934 struct lt_playlist {
3935 bool operator () (const PlaylistState& a, const PlaylistState& b) {
3936 return a.playlist < b.playlist;
3940 struct PlaylistMapping {
3942 boost::shared_ptr<Playlist> pl;
3944 PlaylistMapping (TimeAxisView* tvp) : tv (tvp) {}
3947 /** Remove `clicked_regionview' */
3949 Editor::remove_clicked_region ()
3951 if (clicked_routeview == 0 || clicked_regionview == 0) {
3955 boost::shared_ptr<Playlist> playlist = clicked_routeview->playlist();
3957 begin_reversible_command (_("remove region"));
3958 playlist->clear_changes ();
3959 playlist->clear_owned_changes ();
3960 playlist->remove_region (clicked_regionview->region());
3962 /* We might have removed regions, which alters other regions' layering_index,
3963 so we need to do a recursive diff here.
3965 vector<Command*> cmds;
3966 playlist->rdiff (cmds);
3967 _session->add_commands (cmds);
3969 _session->add_command(new StatefulDiffCommand (playlist));
3970 commit_reversible_command ();
3974 /** Remove the selected regions */
3976 Editor::remove_selected_regions ()
3978 RegionSelection rs = get_regions_from_selection_and_entered ();
3980 if (!_session || rs.empty()) {
3984 begin_reversible_command (_("remove region"));
3986 list<boost::shared_ptr<Region> > regions_to_remove;
3988 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3989 // we can't just remove the region(s) in this loop because
3990 // this removes them from the RegionSelection, and they thus
3991 // disappear from underneath the iterator, and the ++i above
3992 // SEGVs in a puzzling fashion.
3994 // so, first iterate over the regions to be removed from rs and
3995 // add them to the regions_to_remove list, and then
3996 // iterate over the list to actually remove them.
3998 regions_to_remove.push_back ((*i)->region());
4001 vector<boost::shared_ptr<Playlist> > playlists;
4003 for (list<boost::shared_ptr<Region> >::iterator rl = regions_to_remove.begin(); rl != regions_to_remove.end(); ++rl) {
4005 boost::shared_ptr<Playlist> playlist = (*rl)->playlist();
4008 // is this check necessary?
4012 /* get_regions_from_selection_and_entered() guarantees that
4013 the playlists involved are unique, so there is no need
4017 playlists.push_back (playlist);
4019 playlist->clear_changes ();
4020 playlist->clear_owned_changes ();
4021 playlist->freeze ();
4022 playlist->remove_region (*rl);
4025 vector<boost::shared_ptr<Playlist> >::iterator pl;
4027 for (pl = playlists.begin(); pl != playlists.end(); ++pl) {
4030 /* We might have removed regions, which alters other regions' layering_index,
4031 so we need to do a recursive diff here.
4033 vector<Command*> cmds;
4034 (*pl)->rdiff (cmds);
4035 _session->add_commands (cmds);
4037 _session->add_command(new StatefulDiffCommand (*pl));
4040 commit_reversible_command ();
4043 /** Cut, copy or clear selected regions.
4044 * @param op Operation (Cut, Copy or Clear)
4047 Editor::cut_copy_regions (CutCopyOp op, RegionSelection& rs)
4049 /* we can't use a std::map here because the ordering is important, and we can't trivially sort
4050 a map when we want ordered access to both elements. i think.
4053 vector<PlaylistMapping> pmap;
4055 framepos_t first_position = max_framepos;
4057 typedef set<boost::shared_ptr<Playlist> > FreezeList;
4058 FreezeList freezelist;
4060 /* get ordering correct before we cut/copy */
4062 rs.sort_by_position_and_track ();
4064 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
4066 first_position = min ((framepos_t) (*x)->region()->position(), first_position);
4068 if (op == Cut || op == Clear || op == Delete) {
4069 boost::shared_ptr<Playlist> pl = (*x)->region()->playlist();
4072 FreezeList::iterator fl;
4074 // only take state if this is a new playlist.
4075 for (fl = freezelist.begin(); fl != freezelist.end(); ++fl) {
4081 if (fl == freezelist.end()) {
4082 pl->clear_changes();
4083 pl->clear_owned_changes ();
4085 freezelist.insert (pl);
4090 TimeAxisView* tv = &(*x)->get_time_axis_view();
4091 vector<PlaylistMapping>::iterator z;
4093 for (z = pmap.begin(); z != pmap.end(); ++z) {
4094 if ((*z).tv == tv) {
4099 if (z == pmap.end()) {
4100 pmap.push_back (PlaylistMapping (tv));
4104 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ) {
4106 boost::shared_ptr<Playlist> pl = (*x)->region()->playlist();
4109 /* region not yet associated with a playlist (e.g. unfinished
4116 TimeAxisView& tv = (*x)->get_time_axis_view();
4117 boost::shared_ptr<Playlist> npl;
4118 RegionSelection::iterator tmp;
4125 vector<PlaylistMapping>::iterator z;
4127 for (z = pmap.begin(); z != pmap.end(); ++z) {
4128 if ((*z).tv == &tv) {
4133 assert (z != pmap.end());
4136 npl = PlaylistFactory::create (pl->data_type(), *_session, "cutlist", true);
4144 boost::shared_ptr<Region> r = (*x)->region();
4145 boost::shared_ptr<Region> _xx;
4151 pl->remove_region (r);
4155 _xx = RegionFactory::create (r);
4156 npl->add_region (_xx, r->position() - first_position);
4157 pl->remove_region (r);
4161 /* copy region before adding, so we're not putting same object into two different playlists */
4162 npl->add_region (RegionFactory::create (r), r->position() - first_position);
4166 pl->remove_region (r);
4175 list<boost::shared_ptr<Playlist> > foo;
4177 /* the pmap is in the same order as the tracks in which selected regions occured */
4179 for (vector<PlaylistMapping>::iterator i = pmap.begin(); i != pmap.end(); ++i) {
4182 foo.push_back ((*i).pl);
4187 cut_buffer->set (foo);
4191 _last_cut_copy_source_track = 0;
4193 _last_cut_copy_source_track = pmap.front().tv;
4197 for (FreezeList::iterator pl = freezelist.begin(); pl != freezelist.end(); ++pl) {
4200 /* We might have removed regions, which alters other regions' layering_index,
4201 so we need to do a recursive diff here.
4203 vector<Command*> cmds;
4204 (*pl)->rdiff (cmds);
4205 _session->add_commands (cmds);
4207 _session->add_command (new StatefulDiffCommand (*pl));
4212 Editor::cut_copy_ranges (CutCopyOp op)
4214 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4216 /* Sort the track selection now, so that it if is used, the playlists
4217 selected by the calls below to cut_copy_clear are in the order that
4218 their tracks appear in the editor. This makes things like paste
4219 of ranges work properly.
4222 sort_track_selection (ts);
4225 if (!entered_track) {
4228 ts.push_back (entered_track);
4231 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4232 (*i)->cut_copy_clear (*selection, op);
4237 Editor::paste (float times, bool from_context)
4239 DEBUG_TRACE (DEBUG::CutNPaste, "paste to preferred edit pos\n");
4241 paste_internal (get_preferred_edit_position (false, from_context), times);
4245 Editor::mouse_paste ()
4250 if (!mouse_frame (where, ignored)) {
4255 paste_internal (where, 1);
4259 Editor::paste_internal (framepos_t position, float times)
4261 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("apparent paste position is %1\n", position));
4263 if (internal_editing()) {
4264 if (cut_buffer->midi_notes.empty()) {
4268 if (cut_buffer->empty()) {
4273 if (position == max_framepos) {
4274 position = get_preferred_edit_position();
4275 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("preferred edit position is %1\n", position));
4279 TrackViewList::iterator i;
4282 /* get everything in the correct order */
4284 if (_edit_point == Editing::EditAtMouse && entered_track) {
4285 /* With the mouse edit point, paste onto the track under the mouse */
4286 ts.push_back (entered_track);
4287 } else if (!selection->tracks.empty()) {
4288 /* Otherwise, if there are some selected tracks, paste to them */
4289 ts = selection->tracks.filter_to_unique_playlists ();
4290 sort_track_selection (ts);
4291 } else if (_last_cut_copy_source_track) {
4292 /* Otherwise paste to the track that the cut/copy came from;
4293 see discussion in mantis #3333.
4295 ts.push_back (_last_cut_copy_source_track);
4298 if (internal_editing ()) {
4300 /* undo/redo is handled by individual tracks/regions */
4302 for (nth = 0, i = ts.begin(); i != ts.end(); ++i, ++nth) {
4305 RegionSelection::iterator r;
4306 MidiNoteSelection::iterator cb;
4308 get_regions_at (rs, position, ts);
4310 for (cb = cut_buffer->midi_notes.begin(), r = rs.begin();
4311 cb != cut_buffer->midi_notes.end() && r != rs.end(); ++r) {
4312 MidiRegionView* mrv = dynamic_cast<MidiRegionView*> (*r);
4314 mrv->paste (position, times, **cb);
4322 /* we do redo (do you do voodoo?) */
4324 begin_reversible_command (Operations::paste);
4326 for (nth = 0, i = ts.begin(); i != ts.end(); ++i, ++nth) {
4327 (*i)->paste (position, times, *cut_buffer, nth);
4330 commit_reversible_command ();
4335 Editor::duplicate_some_regions (RegionSelection& regions, float times)
4337 boost::shared_ptr<Playlist> playlist;
4338 RegionSelection sel = regions; // clear (below) may clear the argument list if its the current region selection
4339 RegionSelection foo;
4341 framepos_t const start_frame = regions.start ();
4342 framepos_t const end_frame = regions.end_frame ();
4344 begin_reversible_command (Operations::duplicate_region);
4346 selection->clear_regions ();
4348 for (RegionSelection::iterator i = sel.begin(); i != sel.end(); ++i) {
4350 boost::shared_ptr<Region> r ((*i)->region());
4352 TimeAxisView& tv = (*i)->get_time_axis_view();
4353 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (&tv);
4354 latest_regionviews.clear ();
4355 sigc::connection c = rtv->view()->RegionViewAdded.connect (sigc::mem_fun(*this, &Editor::collect_new_region_view));
4357 playlist = (*i)->region()->playlist();
4358 playlist->clear_changes ();
4359 playlist->duplicate (r, end_frame + (r->first_frame() - start_frame), times);
4360 _session->add_command(new StatefulDiffCommand (playlist));
4364 foo.insert (foo.end(), latest_regionviews.begin(), latest_regionviews.end());
4367 commit_reversible_command ();
4370 selection->set (foo);
4375 Editor::duplicate_selection (float times)
4377 if (selection->time.empty() || selection->tracks.empty()) {
4381 boost::shared_ptr<Playlist> playlist;
4382 vector<boost::shared_ptr<Region> > new_regions;
4383 vector<boost::shared_ptr<Region> >::iterator ri;
4385 create_region_from_selection (new_regions);
4387 if (new_regions.empty()) {
4391 begin_reversible_command (_("duplicate selection"));
4393 ri = new_regions.begin();
4395 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4397 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4398 if ((playlist = (*i)->playlist()) == 0) {
4401 playlist->clear_changes ();
4402 playlist->duplicate (*ri, selection->time[clicked_selection].end, times);
4403 _session->add_command (new StatefulDiffCommand (playlist));
4406 if (ri == new_regions.end()) {
4411 commit_reversible_command ();
4414 /** Reset all selected points to the relevant default value */
4416 Editor::reset_point_selection ()
4418 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
4419 ARDOUR::AutomationList::iterator j = (*i)->model ();
4420 (*j)->value = (*i)->line().the_list()->default_value ();
4425 Editor::center_playhead ()
4427 float page = _canvas_width * frames_per_unit;
4428 center_screen_internal (playhead_cursor->current_frame, page);
4432 Editor::center_edit_point ()
4434 float page = _canvas_width * frames_per_unit;
4435 center_screen_internal (get_preferred_edit_position(), page);
4438 /** Caller must begin and commit a reversible command */
4440 Editor::clear_playlist (boost::shared_ptr<Playlist> playlist)
4442 playlist->clear_changes ();
4444 _session->add_command (new StatefulDiffCommand (playlist));
4448 Editor::nudge_track (bool use_edit, bool forwards)
4450 boost::shared_ptr<Playlist> playlist;
4451 framepos_t distance;
4452 framepos_t next_distance;
4456 start = get_preferred_edit_position();
4461 if ((distance = get_nudge_distance (start, next_distance)) == 0) {
4465 if (selection->tracks.empty()) {
4469 begin_reversible_command (_("nudge track"));
4471 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4473 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4475 if ((playlist = (*i)->playlist()) == 0) {
4479 playlist->clear_changes ();
4480 playlist->clear_owned_changes ();
4482 playlist->nudge_after (start, distance, forwards);
4484 vector<Command*> cmds;
4486 playlist->rdiff (cmds);
4487 _session->add_commands (cmds);
4489 _session->add_command (new StatefulDiffCommand (playlist));
4492 commit_reversible_command ();
4496 Editor::remove_last_capture ()
4498 vector<string> choices;
4505 if (Config->get_verify_remove_last_capture()) {
4506 prompt = _("Do you really want to destroy the last capture?"
4507 "\n(This is destructive and cannot be undone)");
4509 choices.push_back (_("No, do nothing."));
4510 choices.push_back (_("Yes, destroy it."));
4512 Gtkmm2ext::Choice prompter (_("Destroy last capture"), prompt, choices);
4514 if (prompter.run () == 1) {
4515 _session->remove_last_capture ();
4516 _regions->redisplay ();
4520 _session->remove_last_capture();
4521 _regions->redisplay ();
4526 Editor::normalize_region ()
4532 RegionSelection rs = get_regions_from_selection_and_entered ();
4538 NormalizeDialog dialog (rs.size() > 1);
4540 if (dialog.run () == RESPONSE_CANCEL) {
4544 set_canvas_cursor (_cursors->wait);
4547 /* XXX: should really only count audio regions here */
4548 int const regions = rs.size ();
4550 /* Make a list of the selected audio regions' maximum amplitudes, and also
4551 obtain the maximum amplitude of them all.
4553 list<double> max_amps;
4555 for (RegionSelection::const_iterator i = rs.begin(); i != rs.end(); ++i) {
4556 AudioRegionView const * arv = dynamic_cast<AudioRegionView const *> (*i);
4558 dialog.descend (1.0 / regions);
4559 double const a = arv->audio_region()->maximum_amplitude (&dialog);
4562 /* the user cancelled the operation */
4563 set_canvas_cursor (current_canvas_cursor);
4567 max_amps.push_back (a);
4568 max_amp = max (max_amp, a);
4573 begin_reversible_command (_("normalize"));
4575 list<double>::const_iterator a = max_amps.begin ();
4577 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
4578 AudioRegionView* const arv = dynamic_cast<AudioRegionView*> (*r);
4583 arv->region()->clear_changes ();
4585 double const amp = dialog.normalize_individually() ? *a : max_amp;
4587 arv->audio_region()->normalize (amp, dialog.target ());
4588 _session->add_command (new StatefulDiffCommand (arv->region()));
4593 commit_reversible_command ();
4594 set_canvas_cursor (current_canvas_cursor);
4599 Editor::reset_region_scale_amplitude ()
4605 RegionSelection rs = get_regions_from_selection_and_entered ();
4611 begin_reversible_command ("reset gain");
4613 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
4614 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
4617 arv->region()->clear_changes ();
4618 arv->audio_region()->set_scale_amplitude (1.0f);
4619 _session->add_command (new StatefulDiffCommand (arv->region()));
4622 commit_reversible_command ();
4626 Editor::adjust_region_gain (bool up)
4628 RegionSelection rs = get_regions_from_selection_and_entered ();
4630 if (!_session || rs.empty()) {
4634 begin_reversible_command ("adjust region gain");
4636 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
4637 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
4642 arv->region()->clear_changes ();
4644 double dB = accurate_coefficient_to_dB (arv->audio_region()->scale_amplitude ());
4652 arv->audio_region()->set_scale_amplitude (dB_to_coefficient (dB));
4653 _session->add_command (new StatefulDiffCommand (arv->region()));
4656 commit_reversible_command ();
4661 Editor::reverse_region ()
4667 Reverse rev (*_session);
4668 apply_filter (rev, _("reverse regions"));
4672 Editor::strip_region_silence ()
4678 RegionSelection rs = get_regions_from_selection_and_entered ();
4684 std::list<RegionView*> audio_only;
4686 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
4687 AudioRegionView* const arv = dynamic_cast<AudioRegionView*> (*i);
4689 audio_only.push_back (arv);
4693 StripSilenceDialog d (_session, audio_only);
4694 int const r = d.run ();
4698 if (r == Gtk::RESPONSE_OK) {
4699 ARDOUR::AudioIntervalMap silences;
4700 d.silences (silences);
4701 StripSilence s (*_session, silences, d.fade_length());
4702 apply_filter (s, _("strip silence"), &d);
4707 Editor::apply_midi_note_edit_op_to_region (MidiOperator& op, MidiRegionView& mrv)
4709 Evoral::Sequence<Evoral::MusicalTime>::Notes selected;
4710 mrv.selection_as_notelist (selected, true);
4712 vector<Evoral::Sequence<Evoral::MusicalTime>::Notes> v;
4713 v.push_back (selected);
4715 framepos_t pos_frames = mrv.midi_region()->position();
4716 double pos_beats = _session->tempo_map().framewalk_to_beats(0, pos_frames);
4718 return op (mrv.midi_region()->model(), pos_beats, v);
4722 Editor::apply_midi_note_edit_op (MidiOperator& op)
4726 RegionSelection rs = get_regions_from_selection_and_entered ();
4732 begin_reversible_command (op.name ());
4734 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
4735 RegionSelection::iterator tmp = r;
4738 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*r);
4741 cmd = apply_midi_note_edit_op_to_region (op, *mrv);
4744 _session->add_command (cmd);
4751 commit_reversible_command ();
4755 Editor::fork_region ()
4757 RegionSelection rs = get_regions_from_selection_and_entered ();
4763 begin_reversible_command (_("Fork Region(s)"));
4765 set_canvas_cursor (_cursors->wait);
4768 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
4769 RegionSelection::iterator tmp = r;
4772 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*>(*r);
4775 boost::shared_ptr<Playlist> playlist = mrv->region()->playlist();
4776 boost::shared_ptr<MidiRegion> newregion = mrv->midi_region()->clone ();
4778 playlist->clear_changes ();
4779 playlist->replace_region (mrv->region(), newregion, mrv->region()->position());
4780 _session->add_command(new StatefulDiffCommand (playlist));
4786 commit_reversible_command ();
4788 set_canvas_cursor (current_canvas_cursor);
4792 Editor::quantize_region ()
4794 int selected_midi_region_cnt = 0;
4800 RegionSelection rs = get_regions_from_selection_and_entered ();
4806 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
4807 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*r);
4809 selected_midi_region_cnt++;
4813 if (selected_midi_region_cnt == 0) {
4817 QuantizeDialog* qd = new QuantizeDialog (*this);
4820 const int r = qd->run ();
4823 if (r == Gtk::RESPONSE_OK) {
4824 Quantize quant (*_session, qd->snap_start(), qd->snap_end(),
4825 qd->start_grid_size(), qd->end_grid_size(),
4826 qd->strength(), qd->swing(), qd->threshold());
4828 apply_midi_note_edit_op (quant);
4833 Editor::insert_patch_change (bool from_context)
4835 RegionSelection rs = get_regions_from_selection_and_entered ();
4841 const framepos_t p = get_preferred_edit_position (false, from_context);
4843 /* XXX: bit of a hack; use the MIDNAM from the first selected region;
4844 there may be more than one, but the PatchChangeDialog can only offer
4845 one set of patch menus.
4847 MidiRegionView* first = dynamic_cast<MidiRegionView*> (rs.front ());
4849 Evoral::PatchChange<Evoral::MusicalTime> empty (0, 0, 0, 0);
4850 PatchChangeDialog d (0, _session, empty, first->instrument_info(), Gtk::Stock::ADD);
4852 if (d.run() == RESPONSE_CANCEL) {
4856 for (RegionSelection::iterator i = rs.begin (); i != rs.end(); ++i) {
4857 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*i);
4859 if (p >= mrv->region()->first_frame() && p <= mrv->region()->last_frame()) {
4860 mrv->add_patch_change (p - mrv->region()->position(), d.patch ());
4867 Editor::apply_filter (Filter& filter, string command, ProgressReporter* progress)
4869 RegionSelection rs = get_regions_from_selection_and_entered ();
4875 begin_reversible_command (command);
4877 set_canvas_cursor (_cursors->wait);
4881 int const N = rs.size ();
4883 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
4884 RegionSelection::iterator tmp = r;
4887 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
4889 boost::shared_ptr<Playlist> playlist = arv->region()->playlist();
4892 progress->descend (1.0 / N);
4895 if (arv->audio_region()->apply (filter, progress) == 0) {
4897 playlist->clear_changes ();
4898 playlist->clear_owned_changes ();
4900 if (filter.results.empty ()) {
4902 /* no regions returned; remove the old one */
4903 playlist->remove_region (arv->region ());
4907 std::vector<boost::shared_ptr<Region> >::iterator res = filter.results.begin ();
4909 /* first region replaces the old one */
4910 playlist->replace_region (arv->region(), *res, (*res)->position());
4914 while (res != filter.results.end()) {
4915 playlist->add_region (*res, (*res)->position());
4921 /* We might have removed regions, which alters other regions' layering_index,
4922 so we need to do a recursive diff here.
4924 vector<Command*> cmds;
4925 playlist->rdiff (cmds);
4926 _session->add_commands (cmds);
4928 _session->add_command(new StatefulDiffCommand (playlist));
4934 progress->ascend ();
4942 commit_reversible_command ();
4945 set_canvas_cursor (current_canvas_cursor);
4949 Editor::external_edit_region ()
4955 Editor::reset_region_gain_envelopes ()
4957 RegionSelection rs = get_regions_from_selection_and_entered ();
4959 if (!_session || rs.empty()) {
4963 _session->begin_reversible_command (_("reset region gain"));
4965 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
4966 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
4968 boost::shared_ptr<AutomationList> alist (arv->audio_region()->envelope());
4969 XMLNode& before (alist->get_state());
4971 arv->audio_region()->set_default_envelope ();
4972 _session->add_command (new MementoCommand<AutomationList>(*arv->audio_region()->envelope().get(), &before, &alist->get_state()));
4976 _session->commit_reversible_command ();
4980 Editor::set_region_gain_visibility (RegionView* rv)
4982 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (rv);
4984 arv->update_envelope_visibility();
4989 Editor::set_gain_envelope_visibility ()
4995 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4996 AudioTimeAxisView* v = dynamic_cast<AudioTimeAxisView*>(*i);
4998 v->audio_view()->foreach_regionview (sigc::mem_fun (this, &Editor::set_region_gain_visibility));
5004 Editor::toggle_gain_envelope_active ()
5006 if (_ignore_region_action) {
5010 RegionSelection rs = get_regions_from_selection_and_entered ();
5012 if (!_session || rs.empty()) {
5016 _session->begin_reversible_command (_("region gain envelope active"));
5018 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5019 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
5021 arv->region()->clear_changes ();
5022 arv->audio_region()->set_envelope_active (!arv->audio_region()->envelope_active());
5023 _session->add_command (new StatefulDiffCommand (arv->region()));
5027 _session->commit_reversible_command ();
5031 Editor::toggle_region_lock ()
5033 if (_ignore_region_action) {
5037 RegionSelection rs = get_regions_from_selection_and_entered ();
5039 if (!_session || rs.empty()) {
5043 _session->begin_reversible_command (_("toggle region lock"));
5045 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5046 (*i)->region()->clear_changes ();
5047 (*i)->region()->set_locked (!(*i)->region()->locked());
5048 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5051 _session->commit_reversible_command ();
5055 Editor::toggle_region_lock_style ()
5057 if (_ignore_region_action) {
5061 RegionSelection rs = get_regions_from_selection_and_entered ();
5063 if (!_session || rs.empty()) {
5067 _session->begin_reversible_command (_("region lock style"));
5069 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5070 (*i)->region()->clear_changes ();
5071 PositionLockStyle const ns = (*i)->region()->position_lock_style() == AudioTime ? MusicTime : AudioTime;
5072 (*i)->region()->set_position_lock_style (ns);
5073 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5076 _session->commit_reversible_command ();
5080 Editor::toggle_opaque_region ()
5082 if (_ignore_region_action) {
5086 RegionSelection rs = get_regions_from_selection_and_entered ();
5088 if (!_session || rs.empty()) {
5092 _session->begin_reversible_command (_("change region opacity"));
5094 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5095 (*i)->region()->clear_changes ();
5096 (*i)->region()->set_opaque (!(*i)->region()->opaque());
5097 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5100 _session->commit_reversible_command ();
5104 Editor::toggle_record_enable ()
5106 bool new_state = false;
5108 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5109 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5112 if (!rtav->is_track())
5116 new_state = !rtav->track()->record_enabled();
5120 rtav->track()->set_record_enabled (new_state, this);
5125 Editor::toggle_solo ()
5127 bool new_state = false;
5129 boost::shared_ptr<RouteList> rl (new RouteList);
5131 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5132 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5139 new_state = !rtav->route()->soloed ();
5143 rl->push_back (rtav->route());
5146 _session->set_solo (rl, new_state, Session::rt_cleanup, true);
5150 Editor::toggle_mute ()
5152 bool new_state = false;
5154 boost::shared_ptr<RouteList> rl (new RouteList);
5156 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5157 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5164 new_state = !rtav->route()->muted();
5168 rl->push_back (rtav->route());
5171 _session->set_mute (rl, new_state, Session::rt_cleanup, true);
5175 Editor::toggle_solo_isolate ()
5180 Editor::set_fade_length (bool in)
5182 RegionSelection rs = get_regions_from_selection_and_entered ();
5188 /* we need a region to measure the offset from the start */
5190 RegionView* rv = rs.front ();
5192 framepos_t pos = get_preferred_edit_position();
5196 if (pos > rv->region()->last_frame() || pos < rv->region()->first_frame()) {
5197 /* edit point is outside the relevant region */
5202 if (pos <= rv->region()->position()) {
5206 len = pos - rv->region()->position();
5207 cmd = _("set fade in length");
5209 if (pos >= rv->region()->last_frame()) {
5213 len = rv->region()->last_frame() - pos;
5214 cmd = _("set fade out length");
5217 begin_reversible_command (cmd);
5219 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5220 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5226 boost::shared_ptr<AutomationList> alist;
5228 alist = tmp->audio_region()->fade_in();
5230 alist = tmp->audio_region()->fade_out();
5233 XMLNode &before = alist->get_state();
5236 tmp->audio_region()->set_fade_in_length (len);
5237 tmp->audio_region()->set_fade_in_active (true);
5239 tmp->audio_region()->set_fade_out_length (len);
5240 tmp->audio_region()->set_fade_out_active (true);
5243 XMLNode &after = alist->get_state();
5244 _session->add_command(new MementoCommand<AutomationList>(*alist, &before, &after));
5247 commit_reversible_command ();
5251 Editor::set_fade_in_shape (FadeShape shape)
5253 RegionSelection rs = get_regions_from_selection_and_entered ();
5259 begin_reversible_command (_("set fade in shape"));
5261 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5262 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5268 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_in();
5269 XMLNode &before = alist->get_state();
5271 tmp->audio_region()->set_fade_in_shape (shape);
5273 XMLNode &after = alist->get_state();
5274 _session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
5277 commit_reversible_command ();
5282 Editor::set_fade_out_shape (FadeShape shape)
5284 RegionSelection rs = get_regions_from_selection_and_entered ();
5290 begin_reversible_command (_("set fade out shape"));
5292 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5293 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5299 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_out();
5300 XMLNode &before = alist->get_state();
5302 tmp->audio_region()->set_fade_out_shape (shape);
5304 XMLNode &after = alist->get_state();
5305 _session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
5308 commit_reversible_command ();
5312 Editor::set_fade_in_active (bool yn)
5314 RegionSelection rs = get_regions_from_selection_and_entered ();
5320 begin_reversible_command (_("set fade in active"));
5322 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5323 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5330 boost::shared_ptr<AudioRegion> ar (tmp->audio_region());
5332 ar->clear_changes ();
5333 ar->set_fade_in_active (yn);
5334 _session->add_command (new StatefulDiffCommand (ar));
5337 commit_reversible_command ();
5341 Editor::set_fade_out_active (bool yn)
5343 RegionSelection rs = get_regions_from_selection_and_entered ();
5349 begin_reversible_command (_("set fade out active"));
5351 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5352 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5358 boost::shared_ptr<AudioRegion> ar (tmp->audio_region());
5360 ar->clear_changes ();
5361 ar->set_fade_out_active (yn);
5362 _session->add_command(new StatefulDiffCommand (ar));
5365 commit_reversible_command ();
5369 Editor::toggle_region_fades (int dir)
5371 if (_ignore_region_action) {
5375 boost::shared_ptr<AudioRegion> ar;
5378 RegionSelection rs = get_regions_from_selection_and_entered ();
5384 RegionSelection::iterator i;
5385 for (i = rs.begin(); i != rs.end(); ++i) {
5386 if ((ar = boost::dynamic_pointer_cast<AudioRegion>((*i)->region())) != 0) {
5388 yn = ar->fade_out_active ();
5390 yn = ar->fade_in_active ();
5396 if (i == rs.end()) {
5400 /* XXX should this undo-able? */
5402 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5403 if ((ar = boost::dynamic_pointer_cast<AudioRegion>((*i)->region())) == 0) {
5406 if (dir == 1 || dir == 0) {
5407 ar->set_fade_in_active (!yn);
5410 if (dir == -1 || dir == 0) {
5411 ar->set_fade_out_active (!yn);
5417 /** Update region fade visibility after its configuration has been changed */
5419 Editor::update_region_fade_visibility ()
5421 bool _fade_visibility = _session->config.get_show_region_fades ();
5423 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5424 AudioTimeAxisView* v = dynamic_cast<AudioTimeAxisView*>(*i);
5426 if (_fade_visibility) {
5427 v->audio_view()->show_all_fades ();
5429 v->audio_view()->hide_all_fades ();
5436 Editor::set_edit_point ()
5441 if (!mouse_frame (where, ignored)) {
5447 if (selection->markers.empty()) {
5449 mouse_add_new_marker (where);
5454 Location* loc = find_location_from_marker (selection->markers.front(), ignored);
5457 loc->move_to (where);
5463 Editor::set_playhead_cursor ()
5465 if (entered_marker) {
5466 _session->request_locate (entered_marker->position(), _session->transport_rolling());
5471 if (!mouse_frame (where, ignored)) {
5478 _session->request_locate (where, _session->transport_rolling());
5482 if ( Config->get_always_play_range() )
5483 cancel_time_selection();
5487 Editor::split_region ()
5489 if ( !selection->time.empty()) {
5490 separate_regions_between (selection->time);
5494 RegionSelection rs = get_regions_from_selection_and_edit_point ();
5496 framepos_t where = get_preferred_edit_position ();
5502 split_regions_at (where, rs);
5505 struct EditorOrderRouteSorter {
5506 bool operator() (boost::shared_ptr<Route> a, boost::shared_ptr<Route> b) {
5507 return a->order_key (EditorSort) < b->order_key (EditorSort);
5512 Editor::select_next_route()
5514 if (selection->tracks.empty()) {
5515 selection->set (track_views.front());
5519 TimeAxisView* current = selection->tracks.front();
5523 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5524 if (*i == current) {
5526 if (i != track_views.end()) {
5529 current = (*(track_views.begin()));
5530 //selection->set (*(track_views.begin()));
5535 rui = dynamic_cast<RouteUI *>(current);
5536 } while ( current->hidden() || (rui != NULL && !rui->route()->active()));
5538 selection->set(current);
5540 ensure_track_visible(current);
5544 Editor::select_prev_route()
5546 if (selection->tracks.empty()) {
5547 selection->set (track_views.front());
5551 TimeAxisView* current = selection->tracks.front();
5555 for (TrackViewList::reverse_iterator i = track_views.rbegin(); i != track_views.rend(); ++i) {
5556 if (*i == current) {
5558 if (i != track_views.rend()) {
5561 current = *(track_views.rbegin());
5566 rui = dynamic_cast<RouteUI *>(current);
5567 } while ( current->hidden() || (rui != NULL && !rui->route()->active()));
5569 selection->set (current);
5571 ensure_track_visible(current);
5575 Editor::ensure_track_visible(TimeAxisView *track)
5577 if (track->hidden())
5580 double const current_view_min_y = vertical_adjustment.get_value();
5581 double const current_view_max_y = vertical_adjustment.get_value() + vertical_adjustment.get_page_size() - canvas_timebars_vsize;
5583 double const track_min_y = track->y_position ();
5584 double const track_max_y = track->y_position () + track->effective_height ();
5586 if (track_min_y >= current_view_min_y &&
5587 track_max_y <= current_view_max_y) {
5593 if (track_min_y < current_view_min_y) {
5594 // Track is above the current view
5595 new_value = track_min_y;
5597 // Track is below the current view
5598 new_value = track->y_position () + track->effective_height() + canvas_timebars_vsize - vertical_adjustment.get_page_size();
5601 vertical_adjustment.set_value(new_value);
5605 Editor::set_loop_from_selection (bool play)
5607 if (_session == 0 || selection->time.empty()) {
5611 framepos_t start = selection->time[clicked_selection].start;
5612 framepos_t end = selection->time[clicked_selection].end;
5614 set_loop_range (start, end, _("set loop range from selection"));
5617 _session->request_play_loop (true);
5618 _session->request_locate (start, true);
5623 Editor::set_loop_from_edit_range (bool play)
5625 if (_session == 0) {
5632 if (!get_edit_op_range (start, end)) {
5636 set_loop_range (start, end, _("set loop range from edit range"));
5639 _session->request_play_loop (true);
5640 _session->request_locate (start, true);
5645 Editor::set_loop_from_region (bool play)
5647 framepos_t start = max_framepos;
5650 RegionSelection rs = get_regions_from_selection_and_entered ();
5656 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5657 if ((*i)->region()->position() < start) {
5658 start = (*i)->region()->position();
5660 if ((*i)->region()->last_frame() + 1 > end) {
5661 end = (*i)->region()->last_frame() + 1;
5665 set_loop_range (start, end, _("set loop range from region"));
5668 _session->request_play_loop (true);
5669 _session->request_locate (start, true);
5674 Editor::set_punch_from_selection ()
5676 if (_session == 0 || selection->time.empty()) {
5680 framepos_t start = selection->time[clicked_selection].start;
5681 framepos_t end = selection->time[clicked_selection].end;
5683 set_punch_range (start, end, _("set punch range from selection"));
5687 Editor::set_punch_from_edit_range ()
5689 if (_session == 0) {
5696 if (!get_edit_op_range (start, end)) {
5700 set_punch_range (start, end, _("set punch range from edit range"));
5704 Editor::set_punch_from_region ()
5706 framepos_t start = max_framepos;
5709 RegionSelection rs = get_regions_from_selection_and_entered ();
5715 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5716 if ((*i)->region()->position() < start) {
5717 start = (*i)->region()->position();
5719 if ((*i)->region()->last_frame() + 1 > end) {
5720 end = (*i)->region()->last_frame() + 1;
5724 set_punch_range (start, end, _("set punch range from region"));
5728 Editor::pitch_shift_region ()
5730 RegionSelection rs = get_regions_from_selection_and_entered ();
5732 RegionSelection audio_rs;
5733 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5734 if (dynamic_cast<AudioRegionView*> (*i)) {
5735 audio_rs.push_back (*i);
5739 if (audio_rs.empty()) {
5743 pitch_shift (audio_rs, 1.2);
5747 Editor::transpose_region ()
5749 RegionSelection rs = get_regions_from_selection_and_entered ();
5751 list<MidiRegionView*> midi_region_views;
5752 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5753 MidiRegionView* mrv = dynamic_cast<MidiRegionView*> (*i);
5755 midi_region_views.push_back (mrv);
5760 int const r = d.run ();
5761 if (r != RESPONSE_ACCEPT) {
5765 for (list<MidiRegionView*>::iterator i = midi_region_views.begin(); i != midi_region_views.end(); ++i) {
5766 (*i)->midi_region()->transpose (d.semitones ());
5771 Editor::set_tempo_from_region ()
5773 RegionSelection rs = get_regions_from_selection_and_entered ();
5775 if (!_session || rs.empty()) {
5779 RegionView* rv = rs.front();
5781 define_one_bar (rv->region()->position(), rv->region()->last_frame() + 1);
5785 Editor::use_range_as_bar ()
5787 framepos_t start, end;
5788 if (get_edit_op_range (start, end)) {
5789 define_one_bar (start, end);
5794 Editor::define_one_bar (framepos_t start, framepos_t end)
5796 framepos_t length = end - start;
5798 const Meter& m (_session->tempo_map().meter_at (start));
5800 /* length = 1 bar */
5802 /* now we want frames per beat.
5803 we have frames per bar, and beats per bar, so ...
5806 /* XXXX METER MATH */
5808 double frames_per_beat = length / m.divisions_per_bar();
5810 /* beats per minute = */
5812 double beats_per_minute = (_session->frame_rate() * 60.0) / frames_per_beat;
5814 /* now decide whether to:
5816 (a) set global tempo
5817 (b) add a new tempo marker
5821 const TempoSection& t (_session->tempo_map().tempo_section_at (start));
5823 bool do_global = false;
5825 if ((_session->tempo_map().n_tempos() == 1) && (_session->tempo_map().n_meters() == 1)) {
5827 /* only 1 tempo & 1 meter: ask if the user wants to set the tempo
5828 at the start, or create a new marker
5831 vector<string> options;
5832 options.push_back (_("Cancel"));
5833 options.push_back (_("Add new marker"));
5834 options.push_back (_("Set global tempo"));
5837 _("Define one bar"),
5838 _("Do you want to set the global tempo or add a new tempo marker?"),
5842 c.set_default_response (2);
5858 /* more than 1 tempo and/or meter section already, go ahead do the "usual":
5859 if the marker is at the region starter, change it, otherwise add
5864 begin_reversible_command (_("set tempo from region"));
5865 XMLNode& before (_session->tempo_map().get_state());
5868 _session->tempo_map().change_initial_tempo (beats_per_minute, t.note_type());
5869 } else if (t.frame() == start) {
5870 _session->tempo_map().change_existing_tempo_at (start, beats_per_minute, t.note_type());
5872 _session->tempo_map().add_tempo (Tempo (beats_per_minute, t.note_type()), start);
5875 XMLNode& after (_session->tempo_map().get_state());
5877 _session->add_command (new MementoCommand<TempoMap>(_session->tempo_map(), &before, &after));
5878 commit_reversible_command ();
5882 Editor::split_region_at_transients ()
5884 AnalysisFeatureList positions;
5886 RegionSelection rs = get_regions_from_selection_and_entered ();
5888 if (!_session || rs.empty()) {
5892 _session->begin_reversible_command (_("split regions"));
5894 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ) {
5896 RegionSelection::iterator tmp;
5901 boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion> ((*i)->region());
5903 if (ar && (ar->get_transients (positions) == 0)) {
5904 split_region_at_points ((*i)->region(), positions, true);
5911 _session->commit_reversible_command ();
5916 Editor::split_region_at_points (boost::shared_ptr<Region> r, AnalysisFeatureList& positions, bool can_ferret, bool select_new)
5918 bool use_rhythmic_rodent = false;
5920 boost::shared_ptr<Playlist> pl = r->playlist();
5922 list<boost::shared_ptr<Region> > new_regions;
5928 if (positions.empty()) {
5933 if (positions.size() > 20 && can_ferret) {
5934 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);
5935 MessageDialog msg (msgstr,
5938 Gtk::BUTTONS_OK_CANCEL);
5941 msg.add_button (_("Call for the Ferret!"), RESPONSE_APPLY);
5942 msg.set_secondary_text (_("Press OK to continue with this split operation\nor ask the Ferret dialog to tune the analysis"));
5944 msg.set_secondary_text (_("Press OK to continue with this split operation"));
5947 msg.set_title (_("Excessive split?"));
5950 int response = msg.run();
5956 case RESPONSE_APPLY:
5957 use_rhythmic_rodent = true;
5964 if (use_rhythmic_rodent) {
5965 show_rhythm_ferret ();
5969 AnalysisFeatureList::const_iterator x;
5971 pl->clear_changes ();
5972 pl->clear_owned_changes ();
5974 x = positions.begin();
5976 if (x == positions.end()) {
5981 pl->remove_region (r);
5985 while (x != positions.end()) {
5987 /* deal with positons that are out of scope of present region bounds */
5988 if (*x <= 0 || *x > r->length()) {
5993 /* file start = original start + how far we from the initial position ?
5996 framepos_t file_start = r->start() + pos;
5998 /* length = next position - current position
6001 framepos_t len = (*x) - pos;
6003 /* XXX we do we really want to allow even single-sample regions?
6004 shouldn't we have some kind of lower limit on region size?
6013 if (RegionFactory::region_name (new_name, r->name())) {
6017 /* do NOT announce new regions 1 by one, just wait till they are all done */
6021 plist.add (ARDOUR::Properties::start, file_start);
6022 plist.add (ARDOUR::Properties::length, len);
6023 plist.add (ARDOUR::Properties::name, new_name);
6024 plist.add (ARDOUR::Properties::layer, 0);
6026 boost::shared_ptr<Region> nr = RegionFactory::create (r->sources(), plist, false);
6027 /* because we set annouce to false, manually add the new region to the
6030 RegionFactory::map_add (nr);
6032 pl->add_region (nr, r->position() + pos);
6035 new_regions.push_front(nr);
6044 RegionFactory::region_name (new_name, r->name());
6046 /* Add the final region */
6049 plist.add (ARDOUR::Properties::start, r->start() + pos);
6050 plist.add (ARDOUR::Properties::length, r->last_frame() - (r->position() + pos) + 1);
6051 plist.add (ARDOUR::Properties::name, new_name);
6052 plist.add (ARDOUR::Properties::layer, 0);
6054 boost::shared_ptr<Region> nr = RegionFactory::create (r->sources(), plist, false);
6055 /* because we set annouce to false, manually add the new region to the
6058 RegionFactory::map_add (nr);
6059 pl->add_region (nr, r->position() + pos);
6062 new_regions.push_front(nr);
6067 /* We might have removed regions, which alters other regions' layering_index,
6068 so we need to do a recursive diff here.
6070 vector<Command*> cmds;
6072 _session->add_commands (cmds);
6074 _session->add_command (new StatefulDiffCommand (pl));
6078 for (list<boost::shared_ptr<Region> >::iterator i = new_regions.begin(); i != new_regions.end(); ++i){
6079 set_selected_regionview_from_region_list ((*i), Selection::Add);
6085 Editor::place_transient()
6091 RegionSelection rs = get_regions_from_selection_and_edit_point ();
6097 framepos_t where = get_preferred_edit_position();
6099 _session->begin_reversible_command (_("place transient"));
6101 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6102 framepos_t position = (*r)->region()->position();
6103 (*r)->region()->add_transient(where - position);
6106 _session->commit_reversible_command ();
6110 Editor::remove_transient(ArdourCanvas::Item* item)
6116 ArdourCanvas::Line* _line = reinterpret_cast<ArdourCanvas::Line*> (item);
6119 AudioRegionView* _arv = reinterpret_cast<AudioRegionView*> (item->get_data ("regionview"));
6120 _arv->remove_transient (*(float*) _line->get_data ("position"));
6124 Editor::snap_regions_to_grid ()
6126 list <boost::shared_ptr<Playlist > > used_playlists;
6128 RegionSelection rs = get_regions_from_selection_and_entered ();
6130 if (!_session || rs.empty()) {
6134 _session->begin_reversible_command (_("snap regions to grid"));
6136 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6138 boost::shared_ptr<Playlist> pl = (*r)->region()->playlist();
6140 if (!pl->frozen()) {
6141 /* we haven't seen this playlist before */
6143 /* remember used playlists so we can thaw them later */
6144 used_playlists.push_back(pl);
6148 framepos_t start_frame = (*r)->region()->first_frame ();
6149 snap_to (start_frame);
6150 (*r)->region()->set_position (start_frame);
6153 while (used_playlists.size() > 0) {
6154 list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
6156 used_playlists.pop_front();
6159 _session->commit_reversible_command ();
6163 Editor::close_region_gaps ()
6165 list <boost::shared_ptr<Playlist > > used_playlists;
6167 RegionSelection rs = get_regions_from_selection_and_entered ();
6169 if (!_session || rs.empty()) {
6173 Dialog dialog (_("Close Region Gaps"));
6176 table.set_spacings (12);
6177 table.set_border_width (12);
6178 Label* l = manage (left_aligned_label (_("Crossfade length")));
6179 table.attach (*l, 0, 1, 0, 1);
6181 SpinButton spin_crossfade (1, 0);
6182 spin_crossfade.set_range (0, 15);
6183 spin_crossfade.set_increments (1, 1);
6184 spin_crossfade.set_value (5);
6185 table.attach (spin_crossfade, 1, 2, 0, 1);
6187 table.attach (*manage (new Label (_("ms"))), 2, 3, 0, 1);
6189 l = manage (left_aligned_label (_("Pull-back length")));
6190 table.attach (*l, 0, 1, 1, 2);
6192 SpinButton spin_pullback (1, 0);
6193 spin_pullback.set_range (0, 100);
6194 spin_pullback.set_increments (1, 1);
6195 spin_pullback.set_value(30);
6196 table.attach (spin_pullback, 1, 2, 1, 2);
6198 table.attach (*manage (new Label (_("ms"))), 2, 3, 1, 2);
6200 dialog.get_vbox()->pack_start (table);
6201 dialog.add_button (Stock::CANCEL, RESPONSE_CANCEL);
6202 dialog.add_button (_("Ok"), RESPONSE_ACCEPT);
6205 if (dialog.run () == RESPONSE_CANCEL) {
6209 framepos_t crossfade_len = spin_crossfade.get_value();
6210 framepos_t pull_back_frames = spin_pullback.get_value();
6212 crossfade_len = lrintf (crossfade_len * _session->frame_rate()/1000);
6213 pull_back_frames = lrintf (pull_back_frames * _session->frame_rate()/1000);
6215 /* Iterate over the region list and make adjacent regions overlap by crossfade_len_ms */
6217 _session->begin_reversible_command (_("close region gaps"));
6220 boost::shared_ptr<Region> last_region;
6222 rs.sort_by_position_and_track();
6224 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6226 boost::shared_ptr<Playlist> pl = (*r)->region()->playlist();
6228 if (!pl->frozen()) {
6229 /* we haven't seen this playlist before */
6231 /* remember used playlists so we can thaw them later */
6232 used_playlists.push_back(pl);
6236 framepos_t position = (*r)->region()->position();
6238 if (idx == 0 || position < last_region->position()){
6239 last_region = (*r)->region();
6244 (*r)->region()->trim_front( (position - pull_back_frames));
6245 last_region->trim_end( (position - pull_back_frames + crossfade_len));
6247 last_region = (*r)->region();
6252 while (used_playlists.size() > 0) {
6253 list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
6255 used_playlists.pop_front();
6258 _session->commit_reversible_command ();
6262 Editor::tab_to_transient (bool forward)
6264 AnalysisFeatureList positions;
6266 RegionSelection rs = get_regions_from_selection_and_entered ();
6272 framepos_t pos = _session->audible_frame ();
6274 if (!selection->tracks.empty()) {
6276 /* don't waste time searching for transients in duplicate playlists.
6279 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
6281 for (TrackViewList::iterator t = ts.begin(); t != ts.end(); ++t) {
6283 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*t);
6286 boost::shared_ptr<Track> tr = rtv->track();
6288 boost::shared_ptr<Playlist> pl = tr->playlist ();
6290 framepos_t result = pl->find_next_transient (pos, forward ? 1 : -1);
6293 positions.push_back (result);
6306 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6307 (*r)->region()->get_transients (positions);
6311 TransientDetector::cleanup_transients (positions, _session->frame_rate(), 3.0);
6314 AnalysisFeatureList::iterator x;
6316 for (x = positions.begin(); x != positions.end(); ++x) {
6322 if (x != positions.end ()) {
6323 _session->request_locate (*x);
6327 AnalysisFeatureList::reverse_iterator x;
6329 for (x = positions.rbegin(); x != positions.rend(); ++x) {
6335 if (x != positions.rend ()) {
6336 _session->request_locate (*x);
6342 Editor::playhead_forward_to_grid ()
6344 if (!_session) return;
6345 framepos_t pos = playhead_cursor->current_frame;
6346 if (pos < max_framepos - 1) {
6348 snap_to_internal (pos, 1, false);
6349 _session->request_locate (pos);
6355 Editor::playhead_backward_to_grid ()
6357 if (!_session) return;
6358 framepos_t pos = playhead_cursor->current_frame;
6361 snap_to_internal (pos, -1, false);
6362 _session->request_locate (pos);
6367 Editor::set_track_height (Height h)
6369 TrackSelection& ts (selection->tracks);
6371 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
6372 (*x)->set_height_enum (h);
6377 Editor::toggle_tracks_active ()
6379 TrackSelection& ts (selection->tracks);
6381 bool target = false;
6387 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
6388 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*x);
6392 target = !rtv->_route->active();
6395 rtv->_route->set_active (target, this);
6401 Editor::remove_tracks ()
6403 TrackSelection& ts (selection->tracks);
6409 vector<string> choices;
6413 const char* trackstr;
6415 vector<boost::shared_ptr<Route> > routes;
6416 bool special_bus = false;
6418 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
6419 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*x);
6421 if (rtv->is_track()) {
6427 routes.push_back (rtv->_route);
6429 if (rtv->route()->is_master() || rtv->route()->is_monitor()) {
6434 if (special_bus && !Config->get_allow_special_bus_removal()) {
6435 MessageDialog msg (_("That would be bad news ...."),
6439 msg.set_secondary_text (string_compose (_(
6440 "Removing the master or monitor bus is such a bad idea\n\
6441 that %1 is not going to allow it.\n\
6443 If you really want to do this sort of thing\n\
6444 edit your ardour.rc file to set the\n\
6445 \"allow-special-bus-removal\" option to be \"yes\""), PROGRAM_NAME));
6452 if (ntracks + nbusses == 0) {
6457 trackstr = _("tracks");
6459 trackstr = _("track");
6463 busstr = _("busses");
6470 prompt = string_compose (_("Do you really want to remove %1 %2 and %3 %4?\n"
6471 "(You may also lose the playlists associated with the %2)\n\n"
6472 "This action cannot be undone, and the session file will be overwritten!"),
6473 ntracks, trackstr, nbusses, busstr);
6475 prompt = string_compose (_("Do you really want to remove %1 %2?\n"
6476 "(You may also lose the playlists associated with the %2)\n\n"
6477 "This action cannot be undone, and the session file will be overwritten!"),
6480 } else if (nbusses) {
6481 prompt = string_compose (_("Do you really want to remove %1 %2?\n\n"
6482 "This action cannot be undon, and the session file will be overwritten"),
6486 choices.push_back (_("No, do nothing."));
6487 if (ntracks + nbusses > 1) {
6488 choices.push_back (_("Yes, remove them."));
6490 choices.push_back (_("Yes, remove it."));
6495 title = string_compose (_("Remove %1"), trackstr);
6497 title = string_compose (_("Remove %1"), busstr);
6500 Choice prompter (title, prompt, choices);
6502 if (prompter.run () != 1) {
6506 for (vector<boost::shared_ptr<Route> >::iterator x = routes.begin(); x != routes.end(); ++x) {
6507 _session->remove_route (*x);
6512 Editor::do_insert_time ()
6514 if (selection->tracks.empty()) {
6518 InsertTimeDialog d (*this);
6519 int response = d.run ();
6521 if (response != RESPONSE_OK) {
6525 if (d.distance() == 0) {
6529 InsertTimeOption opt = d.intersected_region_action ();
6532 get_preferred_edit_position(),
6538 d.move_glued_markers(),
6539 d.move_locked_markers(),
6545 Editor::insert_time (
6546 framepos_t pos, framecnt_t frames, InsertTimeOption opt,
6547 bool all_playlists, bool ignore_music_glue, bool markers_too, bool glued_markers_too, bool locked_markers_too, bool tempo_too
6550 bool commit = false;
6552 if (Config->get_edit_mode() == Lock) {
6556 begin_reversible_command (_("insert time"));
6558 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
6560 for (TrackViewList::iterator x = ts.begin(); x != ts.end(); ++x) {
6564 /* don't operate on any playlist more than once, which could
6565 * happen if "all playlists" is enabled, but there is more
6566 * than 1 track using playlists "from" a given track.
6569 set<boost::shared_ptr<Playlist> > pl;
6571 if (all_playlists) {
6572 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*x);
6574 vector<boost::shared_ptr<Playlist> > all = _session->playlists->playlists_for_track (rtav->track ());
6575 for (vector<boost::shared_ptr<Playlist> >::iterator p = all.begin(); p != all.end(); ++p) {
6580 if ((*x)->playlist ()) {
6581 pl.insert ((*x)->playlist ());
6585 for (set<boost::shared_ptr<Playlist> >::iterator i = pl.begin(); i != pl.end(); ++i) {
6587 (*i)->clear_changes ();
6588 (*i)->clear_owned_changes ();
6590 if (opt == SplitIntersected) {
6594 (*i)->shift (pos, frames, (opt == MoveIntersected), ignore_music_glue);
6596 vector<Command*> cmds;
6598 _session->add_commands (cmds);
6600 _session->add_command (new StatefulDiffCommand (*i));
6605 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*x);
6607 rtav->route ()->shift (pos, frames);
6615 XMLNode& before (_session->locations()->get_state());
6616 Locations::LocationList copy (_session->locations()->list());
6618 for (Locations::LocationList::iterator i = copy.begin(); i != copy.end(); ++i) {
6620 Locations::LocationList::const_iterator tmp;
6622 bool const was_locked = (*i)->locked ();
6623 if (locked_markers_too) {
6627 if ((*i)->position_lock_style() == AudioTime || glued_markers_too) {
6629 if ((*i)->start() >= pos) {
6630 (*i)->set_start ((*i)->start() + frames);
6631 if (!(*i)->is_mark()) {
6632 (*i)->set_end ((*i)->end() + frames);
6645 XMLNode& after (_session->locations()->get_state());
6646 _session->add_command (new MementoCommand<Locations>(*_session->locations(), &before, &after));
6651 _session->tempo_map().insert_time (pos, frames);
6655 commit_reversible_command ();
6660 Editor::fit_selected_tracks ()
6662 if (!selection->tracks.empty()) {
6663 fit_tracks (selection->tracks);
6667 /* no selected tracks - use tracks with selected regions */
6669 if (!selection->regions.empty()) {
6670 for (RegionSelection::iterator r = selection->regions.begin(); r != selection->regions.end(); ++r) {
6671 tvl.push_back (&(*r)->get_time_axis_view ());
6677 } else if (internal_editing()) {
6678 /* no selected tracks, or regions, but in internal edit mode, so follow the mouse and use
6681 if (entered_track) {
6682 tvl.push_back (entered_track);
6690 Editor::fit_tracks (TrackViewList & tracks)
6692 if (tracks.empty()) {
6696 uint32_t child_heights = 0;
6697 int visible_tracks = 0;
6699 for (TrackSelection::iterator t = tracks.begin(); t != tracks.end(); ++t) {
6701 if (!(*t)->marked_for_display()) {
6705 child_heights += (*t)->effective_height() - (*t)->current_height();
6709 uint32_t h = (uint32_t) floor ((_canvas_height - child_heights - canvas_timebars_vsize) / visible_tracks);
6710 double first_y_pos = DBL_MAX;
6712 if (h < TimeAxisView::preset_height (HeightSmall)) {
6713 MessageDialog msg (*this, _("There are too many tracks to fit in the current window"));
6714 /* too small to be displayed */
6718 undo_visual_stack.push_back (current_visual_state (true));
6719 no_save_visual = true;
6721 /* build a list of all tracks, including children */
6724 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
6726 TimeAxisView::Children c = (*i)->get_child_list ();
6727 for (TimeAxisView::Children::iterator j = c.begin(); j != c.end(); ++j) {
6728 all.push_back (j->get());
6732 /* operate on all tracks, hide unselected ones that are in the middle of selected ones */
6734 bool prev_was_selected = false;
6735 bool is_selected = tracks.contains (all.front());
6736 bool next_is_selected;
6738 for (TrackViewList::iterator t = all.begin(); t != all.end(); ++t) {
6740 TrackViewList::iterator next;
6745 if (next != all.end()) {
6746 next_is_selected = tracks.contains (*next);
6748 next_is_selected = false;
6751 if ((*t)->marked_for_display ()) {
6753 (*t)->set_height (h);
6754 first_y_pos = std::min ((*t)->y_position (), first_y_pos);
6756 if (prev_was_selected && next_is_selected) {
6757 hide_track_in_display (*t);
6762 prev_was_selected = is_selected;
6763 is_selected = next_is_selected;
6767 set the controls_layout height now, because waiting for its size
6768 request signal handler will cause the vertical adjustment setting to fail
6771 controls_layout.property_height () = full_canvas_height - canvas_timebars_vsize;
6772 vertical_adjustment.set_value (first_y_pos);
6774 redo_visual_stack.push_back (current_visual_state (true));
6778 Editor::save_visual_state (uint32_t n)
6780 while (visual_states.size() <= n) {
6781 visual_states.push_back (0);
6784 if (visual_states[n] != 0) {
6785 delete visual_states[n];
6788 visual_states[n] = current_visual_state (true);
6793 Editor::goto_visual_state (uint32_t n)
6795 if (visual_states.size() <= n) {
6799 if (visual_states[n] == 0) {
6803 use_visual_state (*visual_states[n]);
6807 Editor::start_visual_state_op (uint32_t n)
6809 save_visual_state (n);
6811 PopUp* pup = new PopUp (WIN_POS_MOUSE, 1000, true);
6813 snprintf (buf, sizeof (buf), _("Saved view %u"), n+1);
6814 pup->set_text (buf);
6819 Editor::cancel_visual_state_op (uint32_t n)
6821 goto_visual_state (n);
6825 Editor::toggle_region_mute ()
6827 if (_ignore_region_action) {
6831 RegionSelection rs = get_regions_from_selection_and_entered ();
6837 if (rs.size() > 1) {
6838 begin_reversible_command (_("mute regions"));
6840 begin_reversible_command (_("mute region"));
6843 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
6845 (*i)->region()->playlist()->clear_changes ();
6846 (*i)->region()->set_muted (!(*i)->region()->muted ());
6847 _session->add_command (new StatefulDiffCommand ((*i)->region()->playlist()));
6851 commit_reversible_command ();
6855 Editor::combine_regions ()
6857 /* foreach track with selected regions, take all selected regions
6858 and join them into a new region containing the subregions (as a
6862 typedef set<RouteTimeAxisView*> RTVS;
6865 if (selection->regions.empty()) {
6869 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
6870 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(&(*i)->get_time_axis_view());
6873 tracks.insert (rtv);
6877 begin_reversible_command (_("combine regions"));
6879 vector<RegionView*> new_selection;
6881 for (RTVS::iterator i = tracks.begin(); i != tracks.end(); ++i) {
6884 if ((rv = (*i)->combine_regions ()) != 0) {
6885 new_selection.push_back (rv);
6889 selection->clear_regions ();
6890 for (vector<RegionView*>::iterator i = new_selection.begin(); i != new_selection.end(); ++i) {
6891 selection->add (*i);
6894 commit_reversible_command ();
6898 Editor::uncombine_regions ()
6900 typedef set<RouteTimeAxisView*> RTVS;
6903 if (selection->regions.empty()) {
6907 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
6908 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(&(*i)->get_time_axis_view());
6911 tracks.insert (rtv);
6915 begin_reversible_command (_("uncombine regions"));
6917 for (RTVS::iterator i = tracks.begin(); i != tracks.end(); ++i) {
6918 (*i)->uncombine_regions ();
6921 commit_reversible_command ();
6925 Editor::toggle_midi_input_active (bool flip_others)
6928 boost::shared_ptr<RouteList> rl (new RouteList);
6930 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
6931 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
6937 boost::shared_ptr<MidiTrack> mt = rtav->midi_track();
6940 rl->push_back (rtav->route());
6941 onoff = !mt->input_active();
6945 _session->set_exclusive_input_active (rl, onoff, flip_others);