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 */
31 #include "pbd/error.h"
32 #include "pbd/basename.h"
33 #include "pbd/pthread_utils.h"
34 #include "pbd/memento_command.h"
35 #include "pbd/unwind.h"
36 #include "pbd/whitespace.h"
37 #include "pbd/stateful_diff_command.h"
39 #include <gtkmm2ext/utils.h>
40 #include <gtkmm2ext/choice.h>
41 #include <gtkmm2ext/popup.h>
43 #include "ardour/audio_track.h"
44 #include "ardour/audioregion.h"
45 #include "ardour/dB.h"
46 #include "ardour/location.h"
47 #include "ardour/midi_region.h"
48 #include "ardour/midi_track.h"
49 #include "ardour/operations.h"
50 #include "ardour/playlist_factory.h"
51 #include "ardour/profile.h"
52 #include "ardour/quantize.h"
53 #include "ardour/legatize.h"
54 #include "ardour/region_factory.h"
55 #include "ardour/reverse.h"
56 #include "ardour/session.h"
57 #include "ardour/session_playlists.h"
58 #include "ardour/strip_silence.h"
59 #include "ardour/transient_detector.h"
61 #include "canvas/canvas.h"
64 #include "ardour_ui.h"
65 #include "audio_region_view.h"
66 #include "audio_streamview.h"
67 #include "audio_time_axis.h"
68 #include "automation_region_view.h"
69 #include "automation_time_axis.h"
70 #include "control_point.h"
74 #include "editor_cursors.h"
75 #include "editor_drag.h"
76 #include "editor_regions.h"
77 #include "editor_routes.h"
78 #include "gui_thread.h"
79 #include "insert_time_dialog.h"
80 #include "interthread_progress_window.h"
81 #include "item_counts.h"
83 #include "midi_region_view.h"
84 #include "mixer_strip.h"
85 #include "mouse_cursors.h"
86 #include "normalize_dialog.h"
88 #include "paste_context.h"
89 #include "patch_change_dialog.h"
90 #include "quantize_dialog.h"
91 #include "region_gain_line.h"
92 #include "rgb_macros.h"
93 #include "route_time_axis.h"
94 #include "selection.h"
95 #include "selection_templates.h"
96 #include "streamview.h"
97 #include "strip_silence_dialog.h"
98 #include "time_axis_view.h"
99 #include "transpose_dialog.h"
100 #include "transform_dialog.h"
105 using namespace ARDOUR;
108 using namespace Gtkmm2ext;
109 using namespace Editing;
110 using Gtkmm2ext::Keyboard;
112 /***********************************************************************
114 ***********************************************************************/
117 Editor::undo (uint32_t n)
119 if (_drags->active ()) {
129 Editor::redo (uint32_t n)
131 if (_drags->active ()) {
141 Editor::split_regions_at (framepos_t where, RegionSelection& regions)
145 RegionSelection pre_selected_regions = selection->regions;
146 bool working_on_selection = !pre_selected_regions.empty();
148 list<boost::shared_ptr<Playlist> > used_playlists;
149 list<RouteTimeAxisView*> used_trackviews;
151 if (regions.empty()) {
155 begin_reversible_command (_("split"));
157 // if splitting a single region, and snap-to is using
158 // region boundaries, don't pay attention to them
160 if (regions.size() == 1) {
161 switch (_snap_type) {
162 case SnapToRegionStart:
163 case SnapToRegionSync:
164 case SnapToRegionEnd:
173 EditorFreeze(); /* Emit Signal */
176 for (RegionSelection::iterator a = regions.begin(); a != regions.end(); ) {
178 RegionSelection::iterator tmp;
180 /* XXX this test needs to be more complicated, to make sure we really
181 have something to split.
184 if (!(*a)->region()->covers (where)) {
192 boost::shared_ptr<Playlist> pl = (*a)->region()->playlist();
200 /* we haven't seen this playlist before */
202 /* remember used playlists so we can thaw them later */
203 used_playlists.push_back(pl);
205 TimeAxisView& tv = (*a)->get_time_axis_view();
206 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (&tv);
208 used_trackviews.push_back (rtv);
215 pl->clear_changes ();
216 pl->split_region ((*a)->region(), where);
217 _session->add_command (new StatefulDiffCommand (pl));
223 latest_regionviews.clear ();
225 vector<sigc::connection> region_added_connections;
227 for (list<RouteTimeAxisView*>::iterator i = used_trackviews.begin(); i != used_trackviews.end(); ++i) {
228 region_added_connections.push_back ((*i)->view()->RegionViewAdded.connect (sigc::mem_fun(*this, &Editor::collect_new_region_view)));
231 while (used_playlists.size() > 0) {
232 list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
234 used_playlists.pop_front();
237 for (vector<sigc::connection>::iterator c = region_added_connections.begin(); c != region_added_connections.end(); ++c) {
242 EditorThaw(); /* Emit Signal */
245 if (working_on_selection) {
246 // IFF we were working on selected regions, try to reinstate the other region selections that existed before the freeze/thaw.
248 _ignore_follow_edits = true; // a split will change the region selection in mysterious ways; it's not practical or wanted to follow this edit
249 RegionSelectionAfterSplit rsas = Config->get_region_selection_after_split();
250 /* There are three classes of regions that we might want selected after
251 splitting selected regions:
252 - regions selected before the split operation, and unaffected by it
253 - newly-created regions before the split
254 - newly-created regions after the split
257 if (rsas & Existing) {
258 // region selections that existed before the split.
259 selection->add ( pre_selected_regions );
262 for (RegionSelection::iterator ri = latest_regionviews.begin(); ri != latest_regionviews.end(); ri++) {
263 if ((*ri)->region()->position() < where) {
264 // new regions created before the split
265 if (rsas & NewlyCreatedLeft) {
266 selection->add (*ri);
269 // new regions created after the split
270 if (rsas & NewlyCreatedRight) {
271 selection->add (*ri);
275 _ignore_follow_edits = false;
277 _ignore_follow_edits = true;
278 if( working_on_selection ) {
279 selection->add (latest_regionviews); //these are the new regions created after the split
281 _ignore_follow_edits = false;
284 commit_reversible_command ();
287 /** Move one extreme of the current range selection. If more than one range is selected,
288 * the start of the earliest range or the end of the latest range is moved.
290 * @param move_end true to move the end of the current range selection, false to move
292 * @param next true to move the extreme to the next region boundary, false to move to
296 Editor::move_range_selection_start_or_end_to_region_boundary (bool move_end, bool next)
298 if (selection->time.start() == selection->time.end_frame()) {
302 framepos_t start = selection->time.start ();
303 framepos_t end = selection->time.end_frame ();
305 /* the position of the thing we may move */
306 framepos_t pos = move_end ? end : start;
307 int dir = next ? 1 : -1;
309 /* so we don't find the current region again */
310 if (dir > 0 || pos > 0) {
314 framepos_t const target = get_region_boundary (pos, dir, true, false);
329 begin_reversible_command (_("alter selection"));
330 selection->set_preserving_all_ranges (start, end);
331 commit_reversible_command ();
335 Editor::nudge_forward_release (GdkEventButton* ev)
337 if (ev->state & Keyboard::PrimaryModifier) {
338 nudge_forward (false, true);
340 nudge_forward (false, false);
346 Editor::nudge_backward_release (GdkEventButton* ev)
348 if (ev->state & Keyboard::PrimaryModifier) {
349 nudge_backward (false, true);
351 nudge_backward (false, false);
358 Editor::nudge_forward (bool next, bool force_playhead)
361 framepos_t next_distance;
367 RegionSelection rs = get_regions_from_selection_and_entered ();
369 if (!force_playhead && !rs.empty()) {
371 begin_reversible_command (_("nudge regions forward"));
373 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
374 boost::shared_ptr<Region> r ((*i)->region());
376 distance = get_nudge_distance (r->position(), next_distance);
379 distance = next_distance;
383 r->set_position (r->position() + distance);
384 _session->add_command (new StatefulDiffCommand (r));
387 commit_reversible_command ();
390 } else if (!force_playhead && !selection->markers.empty()) {
394 begin_reversible_command (_("nudge location forward"));
396 for (MarkerSelection::iterator i = selection->markers.begin(); i != selection->markers.end(); ++i) {
398 Location* loc = find_location_from_marker ((*i), is_start);
402 XMLNode& before (loc->get_state());
405 distance = get_nudge_distance (loc->start(), next_distance);
407 distance = next_distance;
409 if (max_framepos - distance > loc->start() + loc->length()) {
410 loc->set_start (loc->start() + distance);
412 loc->set_start (max_framepos - loc->length());
415 distance = get_nudge_distance (loc->end(), next_distance);
417 distance = next_distance;
419 if (max_framepos - distance > loc->end()) {
420 loc->set_end (loc->end() + distance);
422 loc->set_end (max_framepos);
425 XMLNode& after (loc->get_state());
426 _session->add_command (new MementoCommand<Location>(*loc, &before, &after));
430 commit_reversible_command ();
433 distance = get_nudge_distance (playhead_cursor->current_frame (), next_distance);
434 _session->request_locate (playhead_cursor->current_frame () + distance);
439 Editor::nudge_backward (bool next, bool force_playhead)
442 framepos_t next_distance;
448 RegionSelection rs = get_regions_from_selection_and_entered ();
450 if (!force_playhead && !rs.empty()) {
452 begin_reversible_command (_("nudge regions backward"));
454 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
455 boost::shared_ptr<Region> r ((*i)->region());
457 distance = get_nudge_distance (r->position(), next_distance);
460 distance = next_distance;
465 if (r->position() > distance) {
466 r->set_position (r->position() - distance);
470 _session->add_command (new StatefulDiffCommand (r));
473 commit_reversible_command ();
475 } else if (!force_playhead && !selection->markers.empty()) {
479 begin_reversible_command (_("nudge location forward"));
481 for (MarkerSelection::iterator i = selection->markers.begin(); i != selection->markers.end(); ++i) {
483 Location* loc = find_location_from_marker ((*i), is_start);
487 XMLNode& before (loc->get_state());
490 distance = get_nudge_distance (loc->start(), next_distance);
492 distance = next_distance;
494 if (distance < loc->start()) {
495 loc->set_start (loc->start() - distance);
500 distance = get_nudge_distance (loc->end(), next_distance);
503 distance = next_distance;
506 if (distance < loc->end() - loc->length()) {
507 loc->set_end (loc->end() - distance);
509 loc->set_end (loc->length());
513 XMLNode& after (loc->get_state());
514 _session->add_command (new MementoCommand<Location>(*loc, &before, &after));
518 commit_reversible_command ();
522 distance = get_nudge_distance (playhead_cursor->current_frame (), next_distance);
524 if (playhead_cursor->current_frame () > distance) {
525 _session->request_locate (playhead_cursor->current_frame () - distance);
527 _session->goto_start();
533 Editor::nudge_forward_capture_offset ()
535 RegionSelection rs = get_regions_from_selection_and_entered ();
537 if (!_session || rs.empty()) {
541 begin_reversible_command (_("nudge forward"));
543 framepos_t const distance = _session->worst_output_latency();
545 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
546 boost::shared_ptr<Region> r ((*i)->region());
549 r->set_position (r->position() + distance);
550 _session->add_command(new StatefulDiffCommand (r));
553 commit_reversible_command ();
557 Editor::nudge_backward_capture_offset ()
559 RegionSelection rs = get_regions_from_selection_and_entered ();
561 if (!_session || rs.empty()) {
565 begin_reversible_command (_("nudge backward"));
567 framepos_t const distance = _session->worst_output_latency();
569 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
570 boost::shared_ptr<Region> r ((*i)->region());
574 if (r->position() > distance) {
575 r->set_position (r->position() - distance);
579 _session->add_command(new StatefulDiffCommand (r));
582 commit_reversible_command ();
585 struct RegionSelectionPositionSorter {
586 bool operator() (RegionView* a, RegionView* b) {
587 return a->region()->position() < b->region()->position();
592 Editor::sequence_regions ()
595 framepos_t r_end_prev;
603 RegionSelection rs = get_regions_from_selection_and_entered ();
604 rs.sort(RegionSelectionPositionSorter());
608 begin_reversible_command (_("sequence regions"));
609 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
610 boost::shared_ptr<Region> r ((*i)->region());
618 if(r->position_locked())
625 r->set_position(r_end_prev);
628 _session->add_command (new StatefulDiffCommand (r));
630 r_end=r->position() + r->length();
634 commit_reversible_command ();
642 Editor::move_to_start ()
644 _session->goto_start ();
648 Editor::move_to_end ()
651 _session->request_locate (_session->current_end_frame());
655 Editor::build_region_boundary_cache ()
658 vector<RegionPoint> interesting_points;
659 boost::shared_ptr<Region> r;
660 TrackViewList tracks;
663 region_boundary_cache.clear ();
669 switch (_snap_type) {
670 case SnapToRegionStart:
671 interesting_points.push_back (Start);
673 case SnapToRegionEnd:
674 interesting_points.push_back (End);
676 case SnapToRegionSync:
677 interesting_points.push_back (SyncPoint);
679 case SnapToRegionBoundary:
680 interesting_points.push_back (Start);
681 interesting_points.push_back (End);
684 fatal << string_compose (_("build_region_boundary_cache called with snap_type = %1"), _snap_type) << endmsg;
685 abort(); /*NOTREACHED*/
689 TimeAxisView *ontrack = 0;
692 if (!selection->tracks.empty()) {
693 tlist = selection->tracks.filter_to_unique_playlists ();
695 tlist = track_views.filter_to_unique_playlists ();
698 while (pos < _session->current_end_frame() && !at_end) {
701 framepos_t lpos = max_framepos;
703 for (vector<RegionPoint>::iterator p = interesting_points.begin(); p != interesting_points.end(); ++p) {
705 if ((r = find_next_region (pos, *p, 1, tlist, &ontrack)) == 0) {
706 if (*p == interesting_points.back()) {
709 /* move to next point type */
715 rpos = r->first_frame();
719 rpos = r->last_frame();
723 rpos = r->sync_position ();
731 RouteTimeAxisView *rtav;
733 if (ontrack != 0 && (rtav = dynamic_cast<RouteTimeAxisView*>(ontrack)) != 0 ) {
734 if (rtav->track() != 0) {
735 speed = rtav->track()->speed();
739 rpos = track_frame_to_session_frame (rpos, speed);
745 /* prevent duplicates, but we don't use set<> because we want to be able
749 vector<framepos_t>::iterator ri;
751 for (ri = region_boundary_cache.begin(); ri != region_boundary_cache.end(); ++ri) {
757 if (ri == region_boundary_cache.end()) {
758 region_boundary_cache.push_back (rpos);
765 /* finally sort to be sure that the order is correct */
767 sort (region_boundary_cache.begin(), region_boundary_cache.end());
770 boost::shared_ptr<Region>
771 Editor::find_next_region (framepos_t frame, RegionPoint point, int32_t dir, TrackViewList& tracks, TimeAxisView **ontrack)
773 TrackViewList::iterator i;
774 framepos_t closest = max_framepos;
775 boost::shared_ptr<Region> ret;
779 framepos_t track_frame;
780 RouteTimeAxisView *rtav;
782 for (i = tracks.begin(); i != tracks.end(); ++i) {
785 boost::shared_ptr<Region> r;
788 if ( (rtav = dynamic_cast<RouteTimeAxisView*>(*i)) != 0 ) {
789 if (rtav->track()!=0)
790 track_speed = rtav->track()->speed();
793 track_frame = session_frame_to_track_frame(frame, track_speed);
795 if ((r = (*i)->find_next_region (track_frame, point, dir)) == 0) {
801 rpos = r->first_frame ();
805 rpos = r->last_frame ();
809 rpos = r->sync_position ();
813 // rpos is a "track frame", converting it to "_session frame"
814 rpos = track_frame_to_session_frame(rpos, track_speed);
817 distance = rpos - frame;
819 distance = frame - rpos;
822 if (distance < closest) {
834 Editor::find_next_region_boundary (framepos_t pos, int32_t dir, const TrackViewList& tracks)
836 framecnt_t distance = max_framepos;
837 framepos_t current_nearest = -1;
839 for (TrackViewList::const_iterator i = tracks.begin(); i != tracks.end(); ++i) {
840 framepos_t contender;
843 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*i);
849 if ((contender = rtv->find_next_region_boundary (pos, dir)) < 0) {
853 d = ::llabs (pos - contender);
856 current_nearest = contender;
861 return current_nearest;
865 Editor::get_region_boundary (framepos_t pos, int32_t dir, bool with_selection, bool only_onscreen)
870 if (with_selection && Config->get_region_boundaries_from_selected_tracks()) {
872 if (!selection->tracks.empty()) {
874 target = find_next_region_boundary (pos, dir, selection->tracks);
878 if (only_onscreen || Config->get_region_boundaries_from_onscreen_tracks()) {
879 get_onscreen_tracks (tvl);
880 target = find_next_region_boundary (pos, dir, tvl);
882 target = find_next_region_boundary (pos, dir, track_views);
888 if (only_onscreen || Config->get_region_boundaries_from_onscreen_tracks()) {
889 get_onscreen_tracks (tvl);
890 target = find_next_region_boundary (pos, dir, tvl);
892 target = find_next_region_boundary (pos, dir, track_views);
900 Editor::cursor_to_region_boundary (bool with_selection, int32_t dir)
902 framepos_t pos = playhead_cursor->current_frame ();
909 // so we don't find the current region again..
910 if (dir > 0 || pos > 0) {
914 if ((target = get_region_boundary (pos, dir, with_selection, false)) < 0) {
918 _session->request_locate (target);
922 Editor::cursor_to_next_region_boundary (bool with_selection)
924 cursor_to_region_boundary (with_selection, 1);
928 Editor::cursor_to_previous_region_boundary (bool with_selection)
930 cursor_to_region_boundary (with_selection, -1);
934 Editor::cursor_to_region_point (EditorCursor* cursor, RegionPoint point, int32_t dir)
936 boost::shared_ptr<Region> r;
937 framepos_t pos = cursor->current_frame ();
943 TimeAxisView *ontrack = 0;
945 // so we don't find the current region again..
949 if (!selection->tracks.empty()) {
951 r = find_next_region (pos, point, dir, selection->tracks, &ontrack);
953 } else if (clicked_axisview) {
956 t.push_back (clicked_axisview);
958 r = find_next_region (pos, point, dir, t, &ontrack);
962 r = find_next_region (pos, point, dir, track_views, &ontrack);
971 pos = r->first_frame ();
975 pos = r->last_frame ();
979 pos = r->sync_position ();
984 RouteTimeAxisView *rtav;
986 if ( ontrack != 0 && (rtav = dynamic_cast<RouteTimeAxisView*>(ontrack)) != 0 ) {
987 if (rtav->track() != 0) {
988 speed = rtav->track()->speed();
992 pos = track_frame_to_session_frame(pos, speed);
994 if (cursor == playhead_cursor) {
995 _session->request_locate (pos);
997 cursor->set_position (pos);
1002 Editor::cursor_to_next_region_point (EditorCursor* cursor, RegionPoint point)
1004 cursor_to_region_point (cursor, point, 1);
1008 Editor::cursor_to_previous_region_point (EditorCursor* cursor, RegionPoint point)
1010 cursor_to_region_point (cursor, point, -1);
1014 Editor::cursor_to_selection_start (EditorCursor *cursor)
1018 switch (mouse_mode) {
1020 if (!selection->regions.empty()) {
1021 pos = selection->regions.start();
1026 if (!selection->time.empty()) {
1027 pos = selection->time.start ();
1035 if (cursor == playhead_cursor) {
1036 _session->request_locate (pos);
1038 cursor->set_position (pos);
1043 Editor::cursor_to_selection_end (EditorCursor *cursor)
1047 switch (mouse_mode) {
1049 if (!selection->regions.empty()) {
1050 pos = selection->regions.end_frame();
1055 if (!selection->time.empty()) {
1056 pos = selection->time.end_frame ();
1064 if (cursor == playhead_cursor) {
1065 _session->request_locate (pos);
1067 cursor->set_position (pos);
1072 Editor::selected_marker_to_region_boundary (bool with_selection, int32_t dir)
1082 if (selection->markers.empty()) {
1086 if (!mouse_frame (mouse, ignored)) {
1090 add_location_mark (mouse);
1093 if ((loc = find_location_from_marker (selection->markers.front(), ignored)) == 0) {
1097 framepos_t pos = loc->start();
1099 // so we don't find the current region again..
1100 if (dir > 0 || pos > 0) {
1104 if ((target = get_region_boundary (pos, dir, with_selection, false)) < 0) {
1108 loc->move_to (target);
1112 Editor::selected_marker_to_next_region_boundary (bool with_selection)
1114 selected_marker_to_region_boundary (with_selection, 1);
1118 Editor::selected_marker_to_previous_region_boundary (bool with_selection)
1120 selected_marker_to_region_boundary (with_selection, -1);
1124 Editor::selected_marker_to_region_point (RegionPoint point, int32_t dir)
1126 boost::shared_ptr<Region> r;
1131 if (!_session || selection->markers.empty()) {
1135 if ((loc = find_location_from_marker (selection->markers.front(), ignored)) == 0) {
1139 TimeAxisView *ontrack = 0;
1143 // so we don't find the current region again..
1147 if (!selection->tracks.empty()) {
1149 r = find_next_region (pos, point, dir, selection->tracks, &ontrack);
1153 r = find_next_region (pos, point, dir, track_views, &ontrack);
1162 pos = r->first_frame ();
1166 pos = r->last_frame ();
1170 pos = r->adjust_to_sync (r->first_frame());
1175 RouteTimeAxisView *rtav;
1177 if (ontrack != 0 && (rtav = dynamic_cast<RouteTimeAxisView*>(ontrack)) != 0) {
1178 if (rtav->track() != 0) {
1179 speed = rtav->track()->speed();
1183 pos = track_frame_to_session_frame(pos, speed);
1189 Editor::selected_marker_to_next_region_point (RegionPoint point)
1191 selected_marker_to_region_point (point, 1);
1195 Editor::selected_marker_to_previous_region_point (RegionPoint point)
1197 selected_marker_to_region_point (point, -1);
1201 Editor::selected_marker_to_selection_start ()
1207 if (!_session || selection->markers.empty()) {
1211 if ((loc = find_location_from_marker (selection->markers.front(), ignored)) == 0) {
1215 switch (mouse_mode) {
1217 if (!selection->regions.empty()) {
1218 pos = selection->regions.start();
1223 if (!selection->time.empty()) {
1224 pos = selection->time.start ();
1236 Editor::selected_marker_to_selection_end ()
1242 if (!_session || selection->markers.empty()) {
1246 if ((loc = find_location_from_marker (selection->markers.front(), ignored)) == 0) {
1250 switch (mouse_mode) {
1252 if (!selection->regions.empty()) {
1253 pos = selection->regions.end_frame();
1258 if (!selection->time.empty()) {
1259 pos = selection->time.end_frame ();
1271 Editor::scroll_playhead (bool forward)
1273 framepos_t pos = playhead_cursor->current_frame ();
1274 framecnt_t delta = (framecnt_t) floor (current_page_samples() / 0.8);
1277 if (pos == max_framepos) {
1281 if (pos < max_framepos - delta) {
1300 _session->request_locate (pos);
1304 Editor::cursor_align (bool playhead_to_edit)
1310 if (playhead_to_edit) {
1312 if (selection->markers.empty()) {
1316 _session->request_locate (selection->markers.front()->position(), _session->transport_rolling());
1319 /* move selected markers to playhead */
1321 for (MarkerSelection::iterator i = selection->markers.begin(); i != selection->markers.end(); ++i) {
1324 Location* loc = find_location_from_marker (*i, ignored);
1326 if (loc->is_mark()) {
1327 loc->set_start (playhead_cursor->current_frame ());
1329 loc->set (playhead_cursor->current_frame (),
1330 playhead_cursor->current_frame () + loc->length());
1337 Editor::scroll_backward (float pages)
1339 framepos_t const one_page = (framepos_t) rint (_visible_canvas_width * samples_per_pixel);
1340 framepos_t const cnt = (framepos_t) floor (pages * one_page);
1343 if (leftmost_frame < cnt) {
1346 frame = leftmost_frame - cnt;
1349 reset_x_origin (frame);
1353 Editor::scroll_forward (float pages)
1355 framepos_t const one_page = (framepos_t) rint (_visible_canvas_width * samples_per_pixel);
1356 framepos_t const cnt = (framepos_t) floor (pages * one_page);
1359 if (max_framepos - cnt < leftmost_frame) {
1360 frame = max_framepos - cnt;
1362 frame = leftmost_frame + cnt;
1365 reset_x_origin (frame);
1369 Editor::scroll_tracks_down ()
1371 double vert_value = vertical_adjustment.get_value() + vertical_adjustment.get_page_size();
1372 if (vert_value > vertical_adjustment.get_upper() - _visible_canvas_height) {
1373 vert_value = vertical_adjustment.get_upper() - _visible_canvas_height;
1376 vertical_adjustment.set_value (vert_value);
1380 Editor::scroll_tracks_up ()
1382 vertical_adjustment.set_value (vertical_adjustment.get_value() - vertical_adjustment.get_page_size());
1386 Editor::scroll_tracks_down_line ()
1388 double vert_value = vertical_adjustment.get_value() + 60;
1390 if (vert_value > vertical_adjustment.get_upper() - _visible_canvas_height) {
1391 vert_value = vertical_adjustment.get_upper() - _visible_canvas_height;
1394 vertical_adjustment.set_value (vert_value);
1398 Editor::scroll_tracks_up_line ()
1400 reset_y_origin (vertical_adjustment.get_value() - 60);
1404 Editor::scroll_down_one_track ()
1406 TrackViewList::reverse_iterator next = track_views.rend();
1407 std::pair<TimeAxisView*,double> res;
1408 const double top_of_trackviews = vertical_adjustment.get_value();
1410 for (TrackViewList::reverse_iterator t = track_views.rbegin(); t != track_views.rend(); ++t) {
1411 if ((*t)->hidden()) {
1416 /* If this is the upper-most visible trackview, we want to display
1417 the one above it (next)
1420 res = (*t)->covers_y_position (top_of_trackviews);
1428 /* move to the track below the first one that covers the */
1430 if (next != track_views.rend()) {
1431 ensure_time_axis_view_is_visible (**next, true);
1439 Editor::scroll_up_one_track ()
1441 TrackViewList::iterator prev = track_views.end();
1442 std::pair<TimeAxisView*,double> res;
1443 double top_of_trackviews = vertical_adjustment.get_value ();
1445 for (TrackViewList::iterator t = track_views.begin(); t != track_views.end(); ++t) {
1447 if ((*t)->hidden()) {
1451 /* find the trackview at the top of the trackview group */
1452 res = (*t)->covers_y_position (top_of_trackviews);
1461 if (prev != track_views.end()) {
1462 ensure_time_axis_view_is_visible (**prev, true);
1472 Editor::tav_zoom_step (bool coarser)
1474 DisplaySuspender ds;
1478 if (selection->tracks.empty()) {
1481 ts = &selection->tracks;
1484 for (TrackViewList::iterator i = ts->begin(); i != ts->end(); ++i) {
1485 TimeAxisView *tv = (static_cast<TimeAxisView*>(*i));
1486 tv->step_height (coarser);
1491 Editor::tav_zoom_smooth (bool coarser, bool force_all)
1493 DisplaySuspender ds;
1497 if (selection->tracks.empty() || force_all) {
1500 ts = &selection->tracks;
1503 for (TrackViewList::iterator i = ts->begin(); i != ts->end(); ++i) {
1504 TimeAxisView *tv = (static_cast<TimeAxisView*>(*i));
1505 uint32_t h = tv->current_height ();
1510 if (h >= TimeAxisView::preset_height (HeightSmall)) {
1515 tv->set_height (h + 5);
1522 Editor::temporal_zoom_step (bool coarser)
1524 ENSURE_GUI_THREAD (*this, &Editor::temporal_zoom_step, coarser)
1526 framecnt_t nspp = samples_per_pixel;
1534 temporal_zoom (nspp);
1538 Editor::temporal_zoom (framecnt_t fpp)
1544 framepos_t current_page = current_page_samples();
1545 framepos_t current_leftmost = leftmost_frame;
1546 framepos_t current_rightmost;
1547 framepos_t current_center;
1548 framepos_t new_page_size;
1549 framepos_t half_page_size;
1550 framepos_t leftmost_after_zoom = 0;
1552 bool in_track_canvas;
1556 if (fpp == samples_per_pixel) {
1560 // Imposing an arbitrary limit to zoom out as too much zoom out produces
1561 // segfaults for lack of memory. If somebody decides this is not high enough I
1562 // believe it can be raisen to higher values but some limit must be in place.
1564 // This constant represents 1 day @ 48kHz on a 1600 pixel wide display
1565 // all of which is used for the editor track displays. The whole day
1566 // would be 4147200000 samples, so 2592000 samples per pixel.
1568 nfpp = min (fpp, (framecnt_t) 2592000);
1569 nfpp = max ((framecnt_t) 1, nfpp);
1571 new_page_size = (framepos_t) floor (_visible_canvas_width * nfpp);
1572 half_page_size = new_page_size / 2;
1574 switch (zoom_focus) {
1576 leftmost_after_zoom = current_leftmost;
1579 case ZoomFocusRight:
1580 current_rightmost = leftmost_frame + current_page;
1581 if (current_rightmost < new_page_size) {
1582 leftmost_after_zoom = 0;
1584 leftmost_after_zoom = current_rightmost - new_page_size;
1588 case ZoomFocusCenter:
1589 current_center = current_leftmost + (current_page/2);
1590 if (current_center < half_page_size) {
1591 leftmost_after_zoom = 0;
1593 leftmost_after_zoom = current_center - half_page_size;
1597 case ZoomFocusPlayhead:
1598 /* centre playhead */
1599 l = playhead_cursor->current_frame () - (new_page_size * 0.5);
1602 leftmost_after_zoom = 0;
1603 } else if (l > max_framepos) {
1604 leftmost_after_zoom = max_framepos - new_page_size;
1606 leftmost_after_zoom = (framepos_t) l;
1610 case ZoomFocusMouse:
1611 /* try to keep the mouse over the same point in the display */
1613 if (!mouse_frame (where, in_track_canvas)) {
1614 /* use playhead instead */
1615 where = playhead_cursor->current_frame ();
1617 if (where < half_page_size) {
1618 leftmost_after_zoom = 0;
1620 leftmost_after_zoom = where - half_page_size;
1625 l = - ((new_page_size * ((where - current_leftmost)/(double)current_page)) - where);
1628 leftmost_after_zoom = 0;
1629 } else if (l > max_framepos) {
1630 leftmost_after_zoom = max_framepos - new_page_size;
1632 leftmost_after_zoom = (framepos_t) l;
1639 /* try to keep the edit point in the same place */
1640 where = get_preferred_edit_position ();
1644 double l = - ((new_page_size * ((where - current_leftmost)/(double)current_page)) - where);
1647 leftmost_after_zoom = 0;
1648 } else if (l > max_framepos) {
1649 leftmost_after_zoom = max_framepos - new_page_size;
1651 leftmost_after_zoom = (framepos_t) l;
1655 /* edit point not defined */
1662 // leftmost_after_zoom = min (leftmost_after_zoom, _session->current_end_frame());
1664 reposition_and_zoom (leftmost_after_zoom, nfpp);
1668 Editor::calc_extra_zoom_edges(framepos_t &start, framepos_t &end)
1670 /* this func helps make sure we leave a little space
1671 at each end of the editor so that the zoom doesn't fit the region
1672 precisely to the screen.
1675 GdkScreen* screen = gdk_screen_get_default ();
1676 const gint pixwidth = gdk_screen_get_width (screen);
1677 const gint mmwidth = gdk_screen_get_width_mm (screen);
1678 const double pix_per_mm = (double) pixwidth/ (double) mmwidth;
1679 const double one_centimeter_in_pixels = pix_per_mm * 10.0;
1681 const framepos_t range = end - start;
1682 const framecnt_t new_fpp = (framecnt_t) ceil ((double) range / (double) _visible_canvas_width);
1683 const framepos_t extra_samples = (framepos_t) floor (one_centimeter_in_pixels * new_fpp);
1685 if (start > extra_samples) {
1686 start -= extra_samples;
1691 if (max_framepos - extra_samples > end) {
1692 end += extra_samples;
1699 Editor::temporal_zoom_region (bool both_axes)
1701 framepos_t start = max_framepos;
1703 set<TimeAxisView*> tracks;
1705 RegionSelection rs = get_regions_from_selection_and_entered ();
1711 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
1713 if ((*i)->region()->position() < start) {
1714 start = (*i)->region()->position();
1717 if ((*i)->region()->last_frame() + 1 > end) {
1718 end = (*i)->region()->last_frame() + 1;
1721 tracks.insert (&((*i)->get_time_axis_view()));
1724 if ((start == 0 && end == 0) || end < start) {
1728 calc_extra_zoom_edges (start, end);
1730 /* if we're zooming on both axes we need to save track heights etc.
1733 undo_visual_stack.push_back (current_visual_state (both_axes));
1735 PBD::Unwinder<bool> nsv (no_save_visual, true);
1737 temporal_zoom_by_frame (start, end);
1740 uint32_t per_track_height = (uint32_t) floor ((_visible_canvas_height - 10.0) / tracks.size());
1742 /* set visible track heights appropriately */
1744 for (set<TimeAxisView*>::iterator t = tracks.begin(); t != tracks.end(); ++t) {
1745 (*t)->set_height (per_track_height);
1748 /* hide irrelevant tracks */
1750 DisplaySuspender ds;
1752 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1753 if (find (tracks.begin(), tracks.end(), (*i)) == tracks.end()) {
1754 hide_track_in_display (*i);
1758 vertical_adjustment.set_value (0.0);
1761 redo_visual_stack.push_back (current_visual_state (both_axes));
1766 Editor::temporal_zoom_selection (bool both_axes)
1768 if (!selection) return;
1770 //ToDo: if notes are selected, zoom to that
1772 //ToDo: if control points are selected, zoom to that
1774 //if region(s) are selected, zoom to that
1775 if ( !selection->regions.empty() )
1776 temporal_zoom_region (both_axes);
1778 //if a range is selected, zoom to that
1779 if (!selection->time.empty()) {
1781 framepos_t start = selection->time.start();
1782 framepos_t end = selection->time.end_frame();
1784 calc_extra_zoom_edges(start, end);
1786 temporal_zoom_by_frame (start, end);
1789 fit_selected_tracks();
1796 Editor::temporal_zoom_session ()
1798 ENSURE_GUI_THREAD (*this, &Editor::temporal_zoom_session)
1801 framecnt_t start = _session->current_start_frame();
1802 framecnt_t end = _session->current_end_frame();
1804 if (_session->actively_recording () ) {
1805 framepos_t cur = playhead_cursor->current_frame ();
1807 /* recording beyond the end marker; zoom out
1808 * by 5 seconds more so that if 'follow
1809 * playhead' is active we don't immediately
1812 end = cur + _session->frame_rate() * 5;
1816 if ((start == 0 && end == 0) || end < start) {
1820 calc_extra_zoom_edges(start, end);
1822 temporal_zoom_by_frame (start, end);
1827 Editor::temporal_zoom_by_frame (framepos_t start, framepos_t end)
1829 if (!_session) return;
1831 if ((start == 0 && end == 0) || end < start) {
1835 framepos_t range = end - start;
1837 const framecnt_t new_fpp = (framecnt_t) ceil ((double) range / (double) _visible_canvas_width);
1839 framepos_t new_page = range;
1840 framepos_t middle = (framepos_t) floor ((double) start + ((double) range / 2.0f));
1841 framepos_t new_leftmost = (framepos_t) floor ((double) middle - ((double) new_page / 2.0f));
1843 if (new_leftmost > middle) {
1847 if (new_leftmost < 0) {
1851 reposition_and_zoom (new_leftmost, new_fpp);
1855 Editor::temporal_zoom_to_frame (bool coarser, framepos_t frame)
1861 framecnt_t range_before = frame - leftmost_frame;
1865 if (samples_per_pixel <= 1) {
1868 new_spp = samples_per_pixel + (samples_per_pixel/2);
1870 range_before += range_before/2;
1872 if (samples_per_pixel >= 1) {
1873 new_spp = samples_per_pixel - (samples_per_pixel/2);
1875 /* could bail out here since we cannot zoom any finer,
1876 but leave that to the equality test below
1878 new_spp = samples_per_pixel;
1881 range_before -= range_before/2;
1884 if (new_spp == samples_per_pixel) {
1888 /* zoom focus is automatically taken as @param frame when this
1892 framepos_t new_leftmost = frame - (framepos_t)range_before;
1894 if (new_leftmost > frame) {
1898 if (new_leftmost < 0) {
1902 reposition_and_zoom (new_leftmost, new_spp);
1907 Editor::choose_new_marker_name(string &name) {
1909 if (!ARDOUR_UI::config()->get_name_new_markers()) {
1910 /* don't prompt user for a new name */
1914 ArdourPrompter dialog (true);
1916 dialog.set_prompt (_("New Name:"));
1918 dialog.set_title (_("New Location Marker"));
1920 dialog.set_name ("MarkNameWindow");
1921 dialog.set_size_request (250, -1);
1922 dialog.set_position (Gtk::WIN_POS_MOUSE);
1924 dialog.add_button (Stock::OK, RESPONSE_ACCEPT);
1925 dialog.set_initial_text (name);
1929 switch (dialog.run ()) {
1930 case RESPONSE_ACCEPT:
1936 dialog.get_result(name);
1943 Editor::add_location_from_selection ()
1947 if (selection->time.empty()) {
1951 if (_session == 0 || clicked_axisview == 0) {
1955 framepos_t start = selection->time[clicked_selection].start;
1956 framepos_t end = selection->time[clicked_selection].end;
1958 _session->locations()->next_available_name(rangename,"selection");
1959 Location *location = new Location (*_session, start, end, rangename, Location::IsRangeMarker);
1961 begin_reversible_command (_("add marker"));
1963 XMLNode &before = _session->locations()->get_state();
1964 _session->locations()->add (location, true);
1965 XMLNode &after = _session->locations()->get_state();
1966 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
1968 commit_reversible_command ();
1972 Editor::add_location_mark (framepos_t where)
1976 select_new_marker = true;
1978 _session->locations()->next_available_name(markername,"mark");
1979 if (!choose_new_marker_name(markername)) {
1982 Location *location = new Location (*_session, where, where, markername, Location::IsMark);
1983 begin_reversible_command (_("add marker"));
1985 XMLNode &before = _session->locations()->get_state();
1986 _session->locations()->add (location, true);
1987 XMLNode &after = _session->locations()->get_state();
1988 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
1990 commit_reversible_command ();
1994 Editor::add_location_from_playhead_cursor ()
1996 add_location_mark (_session->audible_frame());
2000 Editor::remove_location_at_playhead_cursor ()
2005 begin_reversible_command (_("remove marker"));
2007 XMLNode &before = _session->locations()->get_state();
2008 bool removed = false;
2010 //find location(s) at this time
2011 Locations::LocationList locs;
2012 _session->locations()->find_all_between (_session->audible_frame(), _session->audible_frame()+1, locs, Location::Flags(0));
2013 for (Locations::LocationList::iterator i = locs.begin(); i != locs.end(); ++i) {
2014 if ((*i)->is_mark()) {
2015 _session->locations()->remove (*i);
2022 XMLNode &after = _session->locations()->get_state();
2023 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2025 commit_reversible_command ();
2030 /** Add a range marker around each selected region */
2032 Editor::add_locations_from_region ()
2034 RegionSelection rs = get_regions_from_selection_and_entered ();
2040 begin_reversible_command (selection->regions.size () > 1 ? _("add markers") : _("add marker"));
2042 XMLNode &before = _session->locations()->get_state();
2044 for (RegionSelection::iterator i = rs.begin (); i != rs.end (); ++i) {
2046 boost::shared_ptr<Region> region = (*i)->region ();
2048 Location *location = new Location (*_session, region->position(), region->last_frame(), region->name(), Location::IsRangeMarker);
2050 _session->locations()->add (location, true);
2053 XMLNode &after = _session->locations()->get_state();
2054 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2056 commit_reversible_command ();
2059 /** Add a single range marker around all selected regions */
2061 Editor::add_location_from_region ()
2063 RegionSelection rs = get_regions_from_selection_and_entered ();
2069 begin_reversible_command (_("add marker"));
2071 XMLNode &before = _session->locations()->get_state();
2075 if (rs.size() > 1) {
2076 _session->locations()->next_available_name(markername, "regions");
2078 RegionView* rv = *(rs.begin());
2079 boost::shared_ptr<Region> region = rv->region();
2080 markername = region->name();
2083 if (!choose_new_marker_name(markername)) {
2087 // single range spanning all selected
2088 Location *location = new Location (*_session, selection->regions.start(), selection->regions.end_frame(), markername, Location::IsRangeMarker);
2089 _session->locations()->add (location, true);
2091 XMLNode &after = _session->locations()->get_state();
2092 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2094 commit_reversible_command ();
2100 Editor::jump_forward_to_mark ()
2106 framepos_t pos = _session->locations()->first_mark_after (playhead_cursor->current_frame());
2112 _session->request_locate (pos, _session->transport_rolling());
2116 Editor::jump_backward_to_mark ()
2122 framepos_t pos = _session->locations()->first_mark_before (playhead_cursor->current_frame());
2128 _session->request_locate (pos, _session->transport_rolling());
2134 framepos_t const pos = _session->audible_frame ();
2137 _session->locations()->next_available_name (markername, "mark");
2139 if (!choose_new_marker_name (markername)) {
2143 _session->locations()->add (new Location (*_session, pos, 0, markername, Location::IsMark), true);
2147 Editor::clear_markers ()
2150 begin_reversible_command (_("clear markers"));
2152 XMLNode &before = _session->locations()->get_state();
2153 _session->locations()->clear_markers ();
2154 XMLNode &after = _session->locations()->get_state();
2155 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2157 commit_reversible_command ();
2162 Editor::clear_ranges ()
2165 begin_reversible_command (_("clear ranges"));
2167 XMLNode &before = _session->locations()->get_state();
2169 _session->locations()->clear_ranges ();
2171 XMLNode &after = _session->locations()->get_state();
2172 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2174 commit_reversible_command ();
2179 Editor::clear_locations ()
2181 begin_reversible_command (_("clear locations"));
2183 XMLNode &before = _session->locations()->get_state();
2184 _session->locations()->clear ();
2185 XMLNode &after = _session->locations()->get_state();
2186 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2188 commit_reversible_command ();
2192 Editor::unhide_markers ()
2194 for (LocationMarkerMap::iterator i = location_markers.begin(); i != location_markers.end(); ++i) {
2195 Location *l = (*i).first;
2196 if (l->is_hidden() && l->is_mark()) {
2197 l->set_hidden(false, this);
2203 Editor::unhide_ranges ()
2205 for (LocationMarkerMap::iterator i = location_markers.begin(); i != location_markers.end(); ++i) {
2206 Location *l = (*i).first;
2207 if (l->is_hidden() && l->is_range_marker()) {
2208 l->set_hidden(false, this);
2213 /* INSERT/REPLACE */
2216 Editor::insert_region_list_selection (float times)
2218 RouteTimeAxisView *tv = 0;
2219 boost::shared_ptr<Playlist> playlist;
2221 if (clicked_routeview != 0) {
2222 tv = clicked_routeview;
2223 } else if (!selection->tracks.empty()) {
2224 if ((tv = dynamic_cast<RouteTimeAxisView*>(selection->tracks.front())) == 0) {
2227 } else if (entered_track != 0) {
2228 if ((tv = dynamic_cast<RouteTimeAxisView*>(entered_track)) == 0) {
2235 if ((playlist = tv->playlist()) == 0) {
2239 boost::shared_ptr<Region> region = _regions->get_single_selection ();
2244 begin_reversible_command (_("insert region"));
2245 playlist->clear_changes ();
2246 playlist->add_region ((RegionFactory::create (region, true)), get_preferred_edit_position(), times);
2247 if (Config->get_edit_mode() == Ripple)
2248 playlist->ripple (get_preferred_edit_position(), region->length() * times, boost::shared_ptr<Region>());
2250 _session->add_command(new StatefulDiffCommand (playlist));
2251 commit_reversible_command ();
2254 /* BUILT-IN EFFECTS */
2257 Editor::reverse_selection ()
2262 /* GAIN ENVELOPE EDITING */
2265 Editor::edit_envelope ()
2272 Editor::transition_to_rolling (bool fwd)
2278 if (_session->config.get_external_sync()) {
2279 switch (Config->get_sync_source()) {
2283 /* transport controlled by the master */
2288 if (_session->is_auditioning()) {
2289 _session->cancel_audition ();
2293 _session->request_transport_speed (fwd ? 1.0f : -1.0f);
2297 Editor::play_from_start ()
2299 _session->request_locate (_session->current_start_frame(), true);
2303 Editor::play_from_edit_point ()
2305 _session->request_locate (get_preferred_edit_position(), true);
2309 Editor::play_from_edit_point_and_return ()
2311 framepos_t start_frame;
2312 framepos_t return_frame;
2314 start_frame = get_preferred_edit_position (true);
2316 if (_session->transport_rolling()) {
2317 _session->request_locate (start_frame, false);
2321 /* don't reset the return frame if its already set */
2323 if ((return_frame = _session->requested_return_frame()) < 0) {
2324 return_frame = _session->audible_frame();
2327 if (start_frame >= 0) {
2328 _session->request_roll_at_and_return (start_frame, return_frame);
2333 Editor::play_selection ()
2335 if (selection->time.empty()) {
2339 _session->request_play_range (&selection->time, true);
2343 Editor::get_preroll ()
2345 return 1.0 /*Config->get_edit_preroll_seconds()*/ * _session->frame_rate();
2350 Editor::maybe_locate_with_edit_preroll ( framepos_t location )
2352 if ( _session->transport_rolling() || !ARDOUR_UI::config()->get_follow_edits() || _ignore_follow_edits )
2355 location -= get_preroll();
2357 //don't try to locate before the beginning of time
2361 //if follow_playhead is on, keep the playhead on the screen
2362 if ( _follow_playhead )
2363 if ( location < leftmost_frame )
2364 location = leftmost_frame;
2366 _session->request_locate( location );
2370 Editor::play_with_preroll ()
2372 if (selection->time.empty()) {
2375 framepos_t preroll = get_preroll();
2377 framepos_t start = 0;
2378 if (selection->time[clicked_selection].start > preroll)
2379 start = selection->time[clicked_selection].start - preroll;
2381 framepos_t end = selection->time[clicked_selection].end + preroll;
2383 AudioRange ar (start, end, 0);
2384 list<AudioRange> lar;
2387 _session->request_play_range (&lar, true);
2392 Editor::play_location (Location& location)
2394 if (location.start() <= location.end()) {
2398 _session->request_bounded_roll (location.start(), location.end());
2402 Editor::loop_location (Location& location)
2404 if (location.start() <= location.end()) {
2410 if ((tll = transport_loop_location()) != 0) {
2411 tll->set (location.start(), location.end());
2413 // enable looping, reposition and start rolling
2414 _session->request_locate (tll->start(), true);
2415 _session->request_play_loop (true);
2420 Editor::do_layer_operation (LayerOperation op)
2422 if (selection->regions.empty ()) {
2426 bool const multiple = selection->regions.size() > 1;
2430 begin_reversible_command (_("raise regions"));
2432 begin_reversible_command (_("raise region"));
2438 begin_reversible_command (_("raise regions to top"));
2440 begin_reversible_command (_("raise region to top"));
2446 begin_reversible_command (_("lower regions"));
2448 begin_reversible_command (_("lower region"));
2454 begin_reversible_command (_("lower regions to bottom"));
2456 begin_reversible_command (_("lower region"));
2461 set<boost::shared_ptr<Playlist> > playlists = selection->regions.playlists ();
2462 for (set<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
2463 (*i)->clear_owned_changes ();
2466 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
2467 boost::shared_ptr<Region> r = (*i)->region ();
2479 r->lower_to_bottom ();
2483 for (set<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
2484 vector<Command*> cmds;
2486 _session->add_commands (cmds);
2489 commit_reversible_command ();
2493 Editor::raise_region ()
2495 do_layer_operation (Raise);
2499 Editor::raise_region_to_top ()
2501 do_layer_operation (RaiseToTop);
2505 Editor::lower_region ()
2507 do_layer_operation (Lower);
2511 Editor::lower_region_to_bottom ()
2513 do_layer_operation (LowerToBottom);
2516 /** Show the region editor for the selected regions */
2518 Editor::show_region_properties ()
2520 selection->foreach_regionview (&RegionView::show_region_editor);
2523 /** Show the midi list editor for the selected MIDI regions */
2525 Editor::show_midi_list_editor ()
2527 selection->foreach_midi_regionview (&MidiRegionView::show_list_editor);
2531 Editor::rename_region ()
2533 RegionSelection rs = get_regions_from_selection_and_entered ();
2539 ArdourDialog d (*this, _("Rename Region"), true, false);
2541 Label label (_("New name:"));
2544 hbox.set_spacing (6);
2545 hbox.pack_start (label, false, false);
2546 hbox.pack_start (entry, true, true);
2548 d.get_vbox()->set_border_width (12);
2549 d.get_vbox()->pack_start (hbox, false, false);
2551 d.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
2552 d.add_button(Gtk::Stock::OK, Gtk::RESPONSE_OK);
2554 d.set_size_request (300, -1);
2556 entry.set_text (rs.front()->region()->name());
2557 entry.select_region (0, -1);
2559 entry.signal_activate().connect (sigc::bind (sigc::mem_fun (d, &Dialog::response), RESPONSE_OK));
2565 int const ret = d.run();
2569 if (ret != RESPONSE_OK) {
2573 std::string str = entry.get_text();
2574 strip_whitespace_edges (str);
2576 rs.front()->region()->set_name (str);
2577 _regions->redisplay ();
2582 Editor::audition_playlist_region_via_route (boost::shared_ptr<Region> region, Route& route)
2584 if (_session->is_auditioning()) {
2585 _session->cancel_audition ();
2588 // note: some potential for creativity here, because region doesn't
2589 // have to belong to the playlist that Route is handling
2591 // bool was_soloed = route.soloed();
2593 route.set_solo (true, this);
2595 _session->request_bounded_roll (region->position(), region->position() + region->length());
2597 /* XXX how to unset the solo state ? */
2600 /** Start an audition of the first selected region */
2602 Editor::play_edit_range ()
2604 framepos_t start, end;
2606 if (get_edit_op_range (start, end)) {
2607 _session->request_bounded_roll (start, end);
2612 Editor::play_selected_region ()
2614 framepos_t start = max_framepos;
2617 RegionSelection rs = get_regions_from_selection_and_entered ();
2623 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
2624 if ((*i)->region()->position() < start) {
2625 start = (*i)->region()->position();
2627 if ((*i)->region()->last_frame() + 1 > end) {
2628 end = (*i)->region()->last_frame() + 1;
2632 _session->request_bounded_roll (start, end);
2636 Editor::audition_playlist_region_standalone (boost::shared_ptr<Region> region)
2638 _session->audition_region (region);
2642 Editor::region_from_selection ()
2644 if (clicked_axisview == 0) {
2648 if (selection->time.empty()) {
2652 framepos_t start = selection->time[clicked_selection].start;
2653 framepos_t end = selection->time[clicked_selection].end;
2655 TrackViewList tracks = get_tracks_for_range_action ();
2657 framepos_t selection_cnt = end - start + 1;
2659 for (TrackSelection::iterator i = tracks.begin(); i != tracks.end(); ++i) {
2660 boost::shared_ptr<Region> current;
2661 boost::shared_ptr<Playlist> pl;
2662 framepos_t internal_start;
2665 if ((pl = (*i)->playlist()) == 0) {
2669 if ((current = pl->top_region_at (start)) == 0) {
2673 internal_start = start - current->position();
2674 RegionFactory::region_name (new_name, current->name(), true);
2678 plist.add (ARDOUR::Properties::start, current->start() + internal_start);
2679 plist.add (ARDOUR::Properties::length, selection_cnt);
2680 plist.add (ARDOUR::Properties::name, new_name);
2681 plist.add (ARDOUR::Properties::layer, 0);
2683 boost::shared_ptr<Region> region (RegionFactory::create (current, plist));
2688 Editor::create_region_from_selection (vector<boost::shared_ptr<Region> >& new_regions)
2690 if (selection->time.empty() || selection->tracks.empty()) {
2694 framepos_t start, end;
2695 if (clicked_selection) {
2696 start = selection->time[clicked_selection].start;
2697 end = selection->time[clicked_selection].end;
2699 start = selection->time.start();
2700 end = selection->time.end_frame();
2703 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
2704 sort_track_selection (ts);
2706 for (TrackSelection::iterator i = ts.begin(); i != ts.end(); ++i) {
2707 boost::shared_ptr<Region> current;
2708 boost::shared_ptr<Playlist> playlist;
2709 framepos_t internal_start;
2712 if ((playlist = (*i)->playlist()) == 0) {
2716 if ((current = playlist->top_region_at(start)) == 0) {
2720 internal_start = start - current->position();
2721 RegionFactory::region_name (new_name, current->name(), true);
2725 plist.add (ARDOUR::Properties::start, current->start() + internal_start);
2726 plist.add (ARDOUR::Properties::length, end - start + 1);
2727 plist.add (ARDOUR::Properties::name, new_name);
2729 new_regions.push_back (RegionFactory::create (current, plist));
2734 Editor::split_multichannel_region ()
2736 RegionSelection rs = get_regions_from_selection_and_entered ();
2742 vector< boost::shared_ptr<Region> > v;
2744 for (list<RegionView*>::iterator x = rs.begin(); x != rs.end(); ++x) {
2745 (*x)->region()->separate_by_channel (*_session, v);
2750 Editor::new_region_from_selection ()
2752 region_from_selection ();
2753 cancel_selection ();
2757 add_if_covered (RegionView* rv, const AudioRange* ar, RegionSelection* rs)
2759 switch (rv->region()->coverage (ar->start, ar->end - 1)) {
2760 // n.b. -1 because AudioRange::end is one past the end, but coverage expects inclusive ranges
2761 case Evoral::OverlapNone:
2769 * - selected tracks, or if there are none...
2770 * - tracks containing selected regions, or if there are none...
2775 Editor::get_tracks_for_range_action () const
2779 if (selection->tracks.empty()) {
2781 /* use tracks with selected regions */
2783 RegionSelection rs = selection->regions;
2785 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
2786 TimeAxisView* tv = &(*i)->get_time_axis_view();
2788 if (!t.contains (tv)) {
2794 /* no regions and no tracks: use all tracks */
2800 t = selection->tracks;
2803 return t.filter_to_unique_playlists();
2807 Editor::separate_regions_between (const TimeSelection& ts)
2809 bool in_command = false;
2810 boost::shared_ptr<Playlist> playlist;
2811 RegionSelection new_selection;
2813 TrackViewList tmptracks = get_tracks_for_range_action ();
2814 sort_track_selection (tmptracks);
2816 for (TrackSelection::iterator i = tmptracks.begin(); i != tmptracks.end(); ++i) {
2818 RouteTimeAxisView* rtv;
2820 if ((rtv = dynamic_cast<RouteTimeAxisView*> ((*i))) != 0) {
2822 if (rtv->is_track()) {
2824 /* no edits to destructive tracks */
2826 if (rtv->track()->destructive()) {
2830 if ((playlist = rtv->playlist()) != 0) {
2832 playlist->clear_changes ();
2834 /* XXX need to consider musical time selections here at some point */
2836 double speed = rtv->track()->speed();
2839 for (list<AudioRange>::const_iterator t = ts.begin(); t != ts.end(); ++t) {
2841 sigc::connection c = rtv->view()->RegionViewAdded.connect (
2842 sigc::mem_fun(*this, &Editor::collect_new_region_view));
2844 latest_regionviews.clear ();
2846 playlist->partition ((framepos_t)((*t).start * speed),
2847 (framepos_t)((*t).end * speed), false);
2851 if (!latest_regionviews.empty()) {
2853 rtv->view()->foreach_regionview (sigc::bind (
2854 sigc::ptr_fun (add_if_covered),
2855 &(*t), &new_selection));
2858 begin_reversible_command (_("separate"));
2862 /* pick up changes to existing regions */
2864 vector<Command*> cmds;
2865 playlist->rdiff (cmds);
2866 _session->add_commands (cmds);
2868 /* pick up changes to the playlist itself (adds/removes)
2871 _session->add_command(new StatefulDiffCommand (playlist));
2880 // selection->set (new_selection);
2882 commit_reversible_command ();
2886 struct PlaylistState {
2887 boost::shared_ptr<Playlist> playlist;
2891 /** Take tracks from get_tracks_for_range_action and cut any regions
2892 * on those tracks so that the tracks are empty over the time
2896 Editor::separate_region_from_selection ()
2898 /* preferentially use *all* ranges in the time selection if we're in range mode
2899 to allow discontiguous operation, since get_edit_op_range() currently
2900 returns a single range.
2903 if (!selection->time.empty()) {
2905 separate_regions_between (selection->time);
2912 if (get_edit_op_range (start, end)) {
2914 AudioRange ar (start, end, 1);
2918 separate_regions_between (ts);
2924 Editor::separate_region_from_punch ()
2926 Location* loc = _session->locations()->auto_punch_location();
2928 separate_regions_using_location (*loc);
2933 Editor::separate_region_from_loop ()
2935 Location* loc = _session->locations()->auto_loop_location();
2937 separate_regions_using_location (*loc);
2942 Editor::separate_regions_using_location (Location& loc)
2944 if (loc.is_mark()) {
2948 AudioRange ar (loc.start(), loc.end(), 1);
2953 separate_regions_between (ts);
2956 /** Separate regions under the selected region */
2958 Editor::separate_under_selected_regions ()
2960 vector<PlaylistState> playlists;
2964 rs = get_regions_from_selection_and_entered();
2966 if (!_session || rs.empty()) {
2970 begin_reversible_command (_("separate region under"));
2972 list<boost::shared_ptr<Region> > regions_to_remove;
2974 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
2975 // we can't just remove the region(s) in this loop because
2976 // this removes them from the RegionSelection, and they thus
2977 // disappear from underneath the iterator, and the ++i above
2978 // SEGVs in a puzzling fashion.
2980 // so, first iterate over the regions to be removed from rs and
2981 // add them to the regions_to_remove list, and then
2982 // iterate over the list to actually remove them.
2984 regions_to_remove.push_back ((*i)->region());
2987 for (list<boost::shared_ptr<Region> >::iterator rl = regions_to_remove.begin(); rl != regions_to_remove.end(); ++rl) {
2989 boost::shared_ptr<Playlist> playlist = (*rl)->playlist();
2992 // is this check necessary?
2996 vector<PlaylistState>::iterator i;
2998 //only take state if this is a new playlist.
2999 for (i = playlists.begin(); i != playlists.end(); ++i) {
3000 if ((*i).playlist == playlist) {
3005 if (i == playlists.end()) {
3007 PlaylistState before;
3008 before.playlist = playlist;
3009 before.before = &playlist->get_state();
3011 playlist->freeze ();
3012 playlists.push_back(before);
3015 //Partition on the region bounds
3016 playlist->partition ((*rl)->first_frame() - 1, (*rl)->last_frame() + 1, true);
3018 //Re-add region that was just removed due to the partition operation
3019 playlist->add_region( (*rl), (*rl)->first_frame() );
3022 vector<PlaylistState>::iterator pl;
3024 for (pl = playlists.begin(); pl != playlists.end(); ++pl) {
3025 (*pl).playlist->thaw ();
3026 _session->add_command(new MementoCommand<Playlist>(*(*pl).playlist, (*pl).before, &(*pl).playlist->get_state()));
3029 commit_reversible_command ();
3033 Editor::crop_region_to_selection ()
3035 if (!selection->time.empty()) {
3037 crop_region_to (selection->time.start(), selection->time.end_frame());
3044 if (get_edit_op_range (start, end)) {
3045 crop_region_to (start, end);
3052 Editor::crop_region_to (framepos_t start, framepos_t end)
3054 vector<boost::shared_ptr<Playlist> > playlists;
3055 boost::shared_ptr<Playlist> playlist;
3058 if (selection->tracks.empty()) {
3059 ts = track_views.filter_to_unique_playlists();
3061 ts = selection->tracks.filter_to_unique_playlists ();
3064 sort_track_selection (ts);
3066 for (TrackSelection::iterator i = ts.begin(); i != ts.end(); ++i) {
3068 RouteTimeAxisView* rtv;
3070 if ((rtv = dynamic_cast<RouteTimeAxisView*> ((*i))) != 0) {
3072 boost::shared_ptr<Track> t = rtv->track();
3074 if (t != 0 && ! t->destructive()) {
3076 if ((playlist = rtv->playlist()) != 0) {
3077 playlists.push_back (playlist);
3083 if (playlists.empty()) {
3087 framepos_t the_start;
3091 begin_reversible_command (_("trim to selection"));
3093 for (vector<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
3095 boost::shared_ptr<Region> region;
3099 if ((region = (*i)->top_region_at(the_start)) == 0) {
3103 /* now adjust lengths to that we do the right thing
3104 if the selection extends beyond the region
3107 the_start = max (the_start, (framepos_t) region->position());
3108 if (max_framepos - the_start < region->length()) {
3109 the_end = the_start + region->length() - 1;
3111 the_end = max_framepos;
3113 the_end = min (end, the_end);
3114 cnt = the_end - the_start + 1;
3116 region->clear_changes ();
3117 region->trim_to (the_start, cnt);
3118 _session->add_command (new StatefulDiffCommand (region));
3121 commit_reversible_command ();
3125 Editor::region_fill_track ()
3127 RegionSelection rs = get_regions_from_selection_and_entered ();
3129 if (!_session || rs.empty()) {
3133 framepos_t const end = _session->current_end_frame ();
3135 begin_reversible_command (Operations::region_fill);
3137 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3139 boost::shared_ptr<Region> region ((*i)->region());
3141 boost::shared_ptr<Playlist> pl = region->playlist();
3143 if (end <= region->last_frame()) {
3147 double times = (double) (end - region->last_frame()) / (double) region->length();
3153 pl->clear_changes ();
3154 pl->add_region (RegionFactory::create (region, true), region->last_frame(), times);
3155 _session->add_command (new StatefulDiffCommand (pl));
3158 commit_reversible_command ();
3162 Editor::region_fill_selection ()
3164 if (clicked_routeview == 0 || !clicked_routeview->is_audio_track()) {
3168 if (selection->time.empty()) {
3172 boost::shared_ptr<Region> region = _regions->get_single_selection ();
3177 framepos_t start = selection->time[clicked_selection].start;
3178 framepos_t end = selection->time[clicked_selection].end;
3180 boost::shared_ptr<Playlist> playlist;
3182 if (selection->tracks.empty()) {
3186 framepos_t selection_length = end - start;
3187 float times = (float)selection_length / region->length();
3189 begin_reversible_command (Operations::fill_selection);
3191 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
3193 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
3195 if ((playlist = (*i)->playlist()) == 0) {
3199 playlist->clear_changes ();
3200 playlist->add_region (RegionFactory::create (region, true), start, times);
3201 _session->add_command (new StatefulDiffCommand (playlist));
3204 commit_reversible_command ();
3208 Editor::set_region_sync_position ()
3210 set_sync_point (get_preferred_edit_position (), get_regions_from_selection_and_edit_point ());
3214 Editor::set_sync_point (framepos_t where, const RegionSelection& rs)
3216 bool in_command = false;
3218 for (RegionSelection::const_iterator r = rs.begin(); r != rs.end(); ++r) {
3220 if (!(*r)->region()->covers (where)) {
3224 boost::shared_ptr<Region> region ((*r)->region());
3227 begin_reversible_command (_("set sync point"));
3231 region->clear_changes ();
3232 region->set_sync_position (where);
3233 _session->add_command(new StatefulDiffCommand (region));
3237 commit_reversible_command ();
3241 /** Remove the sync positions of the selection */
3243 Editor::remove_region_sync ()
3245 RegionSelection rs = get_regions_from_selection_and_entered ();
3251 begin_reversible_command (_("remove region sync"));
3253 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3255 (*i)->region()->clear_changes ();
3256 (*i)->region()->clear_sync_position ();
3257 _session->add_command(new StatefulDiffCommand ((*i)->region()));
3260 commit_reversible_command ();
3264 Editor::naturalize_region ()
3266 RegionSelection rs = get_regions_from_selection_and_entered ();
3272 if (rs.size() > 1) {
3273 begin_reversible_command (_("move regions to original position"));
3275 begin_reversible_command (_("move region to original position"));
3278 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3279 (*i)->region()->clear_changes ();
3280 (*i)->region()->move_to_natural_position ();
3281 _session->add_command (new StatefulDiffCommand ((*i)->region()));
3284 commit_reversible_command ();
3288 Editor::align_regions (RegionPoint what)
3290 RegionSelection const rs = get_regions_from_selection_and_edit_point ();
3296 begin_reversible_command (_("align selection"));
3298 framepos_t const position = get_preferred_edit_position ();
3300 for (RegionSelection::const_iterator i = rs.begin(); i != rs.end(); ++i) {
3301 align_region_internal ((*i)->region(), what, position);
3304 commit_reversible_command ();
3307 struct RegionSortByTime {
3308 bool operator() (const RegionView* a, const RegionView* b) {
3309 return a->region()->position() < b->region()->position();
3314 Editor::align_regions_relative (RegionPoint point)
3316 RegionSelection const rs = get_regions_from_selection_and_edit_point ();
3322 framepos_t const position = get_preferred_edit_position ();
3324 framepos_t distance = 0;
3328 list<RegionView*> sorted;
3329 rs.by_position (sorted);
3331 boost::shared_ptr<Region> r ((*sorted.begin())->region());
3336 if (position > r->position()) {
3337 distance = position - r->position();
3339 distance = r->position() - position;
3345 if (position > r->last_frame()) {
3346 distance = position - r->last_frame();
3347 pos = r->position() + distance;
3349 distance = r->last_frame() - position;
3350 pos = r->position() - distance;
3356 pos = r->adjust_to_sync (position);
3357 if (pos > r->position()) {
3358 distance = pos - r->position();
3360 distance = r->position() - pos;
3366 if (pos == r->position()) {
3370 begin_reversible_command (_("align selection (relative)"));
3372 /* move first one specially */
3374 r->clear_changes ();
3375 r->set_position (pos);
3376 _session->add_command(new StatefulDiffCommand (r));
3378 /* move rest by the same amount */
3382 for (list<RegionView*>::iterator i = sorted.begin(); i != sorted.end(); ++i) {
3384 boost::shared_ptr<Region> region ((*i)->region());
3386 region->clear_changes ();
3389 region->set_position (region->position() + distance);
3391 region->set_position (region->position() - distance);
3394 _session->add_command(new StatefulDiffCommand (region));
3398 commit_reversible_command ();
3402 Editor::align_region (boost::shared_ptr<Region> region, RegionPoint point, framepos_t position)
3404 begin_reversible_command (_("align region"));
3405 align_region_internal (region, point, position);
3406 commit_reversible_command ();
3410 Editor::align_region_internal (boost::shared_ptr<Region> region, RegionPoint point, framepos_t position)
3412 region->clear_changes ();
3416 region->set_position (region->adjust_to_sync (position));
3420 if (position > region->length()) {
3421 region->set_position (position - region->length());
3426 region->set_position (position);
3430 _session->add_command(new StatefulDiffCommand (region));
3434 Editor::trim_region_front ()
3440 Editor::trim_region_back ()
3442 trim_region (false);
3446 Editor::trim_region (bool front)
3448 framepos_t where = get_preferred_edit_position();
3449 RegionSelection rs = get_regions_from_selection_and_edit_point ();
3455 begin_reversible_command (front ? _("trim front") : _("trim back"));
3457 for (list<RegionView*>::const_iterator i = rs.by_layer().begin(); i != rs.by_layer().end(); ++i) {
3458 if (!(*i)->region()->locked()) {
3460 (*i)->region()->clear_changes ();
3463 (*i)->region()->trim_front (where);
3464 maybe_locate_with_edit_preroll ( where );
3466 (*i)->region()->trim_end (where);
3467 maybe_locate_with_edit_preroll ( where );
3470 _session->add_command (new StatefulDiffCommand ((*i)->region()));
3474 commit_reversible_command ();
3477 /** Trim the end of the selected regions to the position of the edit cursor */
3479 Editor::trim_region_to_loop ()
3481 Location* loc = _session->locations()->auto_loop_location();
3485 trim_region_to_location (*loc, _("trim to loop"));
3489 Editor::trim_region_to_punch ()
3491 Location* loc = _session->locations()->auto_punch_location();
3495 trim_region_to_location (*loc, _("trim to punch"));
3499 Editor::trim_region_to_location (const Location& loc, const char* str)
3501 RegionSelection rs = get_regions_from_selection_and_entered ();
3503 begin_reversible_command (str);
3505 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
3506 RegionView* rv = (*x);
3508 /* require region to span proposed trim */
3509 switch (rv->region()->coverage (loc.start(), loc.end())) {
3510 case Evoral::OverlapInternal:
3516 RouteTimeAxisView* tav = dynamic_cast<RouteTimeAxisView*> (&rv->get_time_axis_view());
3525 if (tav->track() != 0) {
3526 speed = tav->track()->speed();
3529 start = session_frame_to_track_frame (loc.start(), speed);
3530 end = session_frame_to_track_frame (loc.end(), speed);
3532 rv->region()->clear_changes ();
3533 rv->region()->trim_to (start, (end - start));
3534 _session->add_command(new StatefulDiffCommand (rv->region()));
3537 commit_reversible_command ();
3541 Editor::trim_region_to_previous_region_end ()
3543 return trim_to_region(false);
3547 Editor::trim_region_to_next_region_start ()
3549 return trim_to_region(true);
3553 Editor::trim_to_region(bool forward)
3555 RegionSelection rs = get_regions_from_selection_and_entered ();
3557 begin_reversible_command (_("trim to region"));
3559 boost::shared_ptr<Region> next_region;
3561 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
3563 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*x);
3569 AudioTimeAxisView* atav = dynamic_cast<AudioTimeAxisView*> (&arv->get_time_axis_view());
3577 if (atav->track() != 0) {
3578 speed = atav->track()->speed();
3582 boost::shared_ptr<Region> region = arv->region();
3583 boost::shared_ptr<Playlist> playlist (region->playlist());
3585 region->clear_changes ();
3589 next_region = playlist->find_next_region (region->first_frame(), Start, 1);
3595 region->trim_end((framepos_t) ( (next_region->first_frame() - 1) * speed));
3596 arv->region_changed (PropertyChange (ARDOUR::Properties::length));
3600 next_region = playlist->find_next_region (region->first_frame(), Start, 0);
3606 region->trim_front((framepos_t) ((next_region->last_frame() + 1) * speed));
3608 arv->region_changed (ARDOUR::bounds_change);
3611 _session->add_command(new StatefulDiffCommand (region));
3614 commit_reversible_command ();
3618 Editor::unfreeze_route ()
3620 if (clicked_routeview == 0 || !clicked_routeview->is_track()) {
3624 clicked_routeview->track()->unfreeze ();
3628 Editor::_freeze_thread (void* arg)
3630 return static_cast<Editor*>(arg)->freeze_thread ();
3634 Editor::freeze_thread ()
3636 /* create event pool because we may need to talk to the session */
3637 SessionEvent::create_per_thread_pool ("freeze events", 64);
3638 /* create per-thread buffers for process() tree to use */
3639 clicked_routeview->audio_track()->freeze_me (*current_interthread_info);
3640 current_interthread_info->done = true;
3645 Editor::freeze_route ()
3651 /* stop transport before we start. this is important */
3653 _session->request_transport_speed (0.0);
3655 /* wait for just a little while, because the above call is asynchronous */
3657 Glib::usleep (250000);
3659 if (clicked_routeview == 0 || !clicked_routeview->is_audio_track()) {
3663 if (!clicked_routeview->track()->bounceable (clicked_routeview->track()->main_outs(), true)) {
3665 _("This track/bus cannot be frozen because the signal adds or loses channels before reaching the outputs.\n"
3666 "This is typically caused by plugins that generate stereo output from mono input or vice versa.")
3668 d.set_title (_("Cannot freeze"));
3673 if (clicked_routeview->track()->has_external_redirects()) {
3674 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"
3675 "Freezing will only process the signal as far as the first send/insert/return."),
3676 clicked_routeview->track()->name()), true, MESSAGE_INFO, BUTTONS_NONE, true);
3678 d.add_button (_("Freeze anyway"), Gtk::RESPONSE_OK);
3679 d.add_button (_("Don't freeze"), Gtk::RESPONSE_CANCEL);
3680 d.set_title (_("Freeze Limits"));
3682 int response = d.run ();
3685 case Gtk::RESPONSE_CANCEL:
3692 InterThreadInfo itt;
3693 current_interthread_info = &itt;
3695 InterthreadProgressWindow ipw (current_interthread_info, _("Freeze"), _("Cancel Freeze"));
3697 pthread_create_and_store (X_("freezer"), &itt.thread, _freeze_thread, this);
3699 CursorContext::Handle cursor_ctx = CursorContext::create(*this, _cursors->wait);
3701 while (!itt.done && !itt.cancel) {
3702 gtk_main_iteration ();
3705 current_interthread_info = 0;
3709 Editor::bounce_range_selection (bool replace, bool enable_processing)
3711 if (selection->time.empty()) {
3715 TrackSelection views = selection->tracks;
3717 for (TrackViewList::iterator i = views.begin(); i != views.end(); ++i) {
3719 if (enable_processing) {
3721 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*i);
3723 if (rtv && rtv->track() && replace && enable_processing && !rtv->track()->bounceable (rtv->track()->main_outs(), false)) {
3725 _("You can't perform this operation because the processing of the signal "
3726 "will cause one or more of the tracks to end up with a region with more channels than this track has inputs.\n\n"
3727 "You can do this without processing, which is a different operation.")
3729 d.set_title (_("Cannot bounce"));
3736 framepos_t start = selection->time[clicked_selection].start;
3737 framepos_t end = selection->time[clicked_selection].end;
3738 framepos_t cnt = end - start + 1;
3740 begin_reversible_command (_("bounce range"));
3742 for (TrackViewList::iterator i = views.begin(); i != views.end(); ++i) {
3744 RouteTimeAxisView* rtv;
3746 if ((rtv = dynamic_cast<RouteTimeAxisView*> (*i)) == 0) {
3750 boost::shared_ptr<Playlist> playlist;
3752 if ((playlist = rtv->playlist()) == 0) {
3756 InterThreadInfo itt;
3758 playlist->clear_changes ();
3759 playlist->clear_owned_changes ();
3761 boost::shared_ptr<Region> r;
3763 if (enable_processing) {
3764 r = rtv->track()->bounce_range (start, start+cnt, itt, rtv->track()->main_outs(), false);
3766 r = rtv->track()->bounce_range (start, start+cnt, itt, boost::shared_ptr<Processor>(), false);
3774 list<AudioRange> ranges;
3775 ranges.push_back (AudioRange (start, start+cnt, 0));
3776 playlist->cut (ranges); // discard result
3777 playlist->add_region (r, start);
3780 vector<Command*> cmds;
3781 playlist->rdiff (cmds);
3782 _session->add_commands (cmds);
3784 _session->add_command (new StatefulDiffCommand (playlist));
3787 commit_reversible_command ();
3790 /** Delete selected regions, automation points or a time range */
3794 //special case: if the user is pointing in the editor/mixer strip, they may be trying to delete a plugin.
3795 //we need this because the editor-mixer strip is in the editor window, so it doesn't get the bindings from the mix window
3796 bool deleted = false;
3797 if ( current_mixer_strip && current_mixer_strip == MixerStrip::entered_mixer_strip() )
3798 deleted = current_mixer_strip->delete_processors ();
3804 /** Cut selected regions, automation points or a time range */
3811 /** Copy selected regions, automation points or a time range */
3819 /** @return true if a Cut, Copy or Clear is possible */
3821 Editor::can_cut_copy () const
3823 if (!selection->time.empty() || !selection->regions.empty() || !selection->points.empty())
3830 /** Cut, copy or clear selected regions, automation points or a time range.
3831 * @param op Operation (Delete, Cut, Copy or Clear)
3834 Editor::cut_copy (CutCopyOp op)
3836 /* only cancel selection if cut/copy is successful.*/
3842 opname = _("delete");
3851 opname = _("clear");
3855 /* if we're deleting something, and the mouse is still pressed,
3856 the thing we started a drag for will be gone when we release
3857 the mouse button(s). avoid this. see part 2 at the end of
3861 if (op == Delete || op == Cut || op == Clear) {
3862 if (_drags->active ()) {
3867 if ( op != Delete ) //"Delete" doesn't change copy/paste buf
3868 cut_buffer->clear ();
3870 if (entered_marker) {
3872 /* cut/delete op while pointing at a marker */
3875 Location* loc = find_location_from_marker (entered_marker, ignored);
3877 if (_session && loc) {
3878 Glib::signal_idle().connect (sigc::bind (sigc::mem_fun(*this, &Editor::really_remove_marker), loc));
3885 switch (mouse_mode) {
3888 begin_reversible_command (opname + ' ' + X_("MIDI"));
3890 commit_reversible_command ();
3896 bool did_edit = false;
3898 if (!selection->regions.empty() || !selection->points.empty()) {
3899 begin_reversible_command (opname + ' ' + _("objects"));
3902 if (!selection->regions.empty()) {
3903 cut_copy_regions (op, selection->regions);
3905 if (op == Cut || op == Delete) {
3906 selection->clear_regions ();
3910 if (!selection->points.empty()) {
3911 cut_copy_points (op);
3913 if (op == Cut || op == Delete) {
3914 selection->clear_points ();
3917 } else if (selection->time.empty()) {
3918 framepos_t start, end;
3919 /* no time selection, see if we can get an edit range
3922 if (get_edit_op_range (start, end)) {
3923 selection->set (start, end);
3925 } else if (!selection->time.empty()) {
3926 begin_reversible_command (opname + ' ' + _("range"));
3929 cut_copy_ranges (op);
3931 if (op == Cut || op == Delete) {
3932 selection->clear_time ();
3937 /* reset repeated paste state */
3940 commit_reversible_command ();
3943 if (op == Delete || op == Cut || op == Clear) {
3948 struct AutomationRecord {
3949 AutomationRecord () : state (0) , line(NULL) {}
3950 AutomationRecord (XMLNode* s, const AutomationLine* l) : state (s) , line (l) {}
3952 XMLNode* state; ///< state before any operation
3953 const AutomationLine* line; ///< line this came from
3954 boost::shared_ptr<Evoral::ControlList> copy; ///< copied events for the cut buffer
3957 /** Cut, copy or clear selected automation points.
3958 * @param op Operation (Cut, Copy or Clear)
3961 Editor::cut_copy_points (Editing::CutCopyOp op, Evoral::MusicalTime earliest, bool midi)
3963 if (selection->points.empty ()) {
3967 /* XXX: not ideal, as there may be more than one track involved in the point selection */
3968 _last_cut_copy_source_track = &selection->points.front()->line().trackview;
3970 /* Keep a record of the AutomationLists that we end up using in this operation */
3971 typedef std::map<boost::shared_ptr<AutomationList>, AutomationRecord> Lists;
3974 /* Go through all selected points, making an AutomationRecord for each distinct AutomationList */
3975 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
3976 const AutomationLine& line = (*i)->line();
3977 const boost::shared_ptr<AutomationList> al = line.the_list();
3978 if (lists.find (al) == lists.end ()) {
3979 /* We haven't seen this list yet, so make a record for it. This includes
3980 taking a copy of its current state, in case this is needed for undo later.
3982 lists[al] = AutomationRecord (&al->get_state (), &line);
3986 if (op == Cut || op == Copy) {
3987 /* This operation will involve putting things in the cut buffer, so create an empty
3988 ControlList for each of our source lists to put the cut buffer data in.
3990 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
3991 i->second.copy = i->first->create (i->first->parameter (), i->first->descriptor());
3994 /* Add all selected points to the relevant copy ControlLists */
3995 framepos_t start = std::numeric_limits<framepos_t>::max();
3996 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
3997 boost::shared_ptr<AutomationList> al = (*i)->line().the_list();
3998 AutomationList::const_iterator j = (*i)->model();
4000 lists[al].copy->fast_simple_add ((*j)->when, (*j)->value);
4002 /* Update earliest MIDI start time in beats */
4003 earliest = std::min(earliest, Evoral::MusicalTime((*j)->when));
4005 /* Update earliest session start time in frames */
4006 start = std::min(start, (*i)->line().session_position(j));
4010 /* Snap start time backwards, so copy/paste is snap aligned. */
4012 if (earliest == Evoral::MusicalTime::max()) {
4013 earliest = Evoral::MusicalTime(); // Weird... don't offset
4015 earliest.round_down_to_beat();
4017 if (start == std::numeric_limits<double>::max()) {
4018 start = 0; // Weird... don't offset
4020 snap_to(start, RoundDownMaybe);
4023 const double line_offset = midi ? earliest.to_double() : start;
4024 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
4025 /* Correct this copy list so that it is relative to the earliest
4026 start time, so relative ordering between points is preserved
4027 when copying from several lists and the paste starts at the
4028 earliest copied piece of data. */
4029 for (AutomationList::iterator j = i->second.copy->begin(); j != i->second.copy->end(); ++j) {
4030 (*j)->when -= line_offset;
4033 /* And add it to the cut buffer */
4034 cut_buffer->add (i->second.copy);
4038 if (op == Delete || op == Cut) {
4039 /* This operation needs to remove things from the main AutomationList, so do that now */
4041 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
4042 i->first->freeze ();
4045 /* Remove each selected point from its AutomationList */
4046 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
4047 boost::shared_ptr<AutomationList> al = (*i)->line().the_list();
4048 al->erase ((*i)->model ());
4051 /* Thaw the lists and add undo records for them */
4052 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
4053 boost::shared_ptr<AutomationList> al = i->first;
4055 _session->add_command (new MementoCommand<AutomationList> (*al.get(), i->second.state, &(al->get_state ())));
4060 /** Cut, copy or clear selected automation points.
4061 * @param op Operation (Cut, Copy or Clear)
4064 Editor::cut_copy_midi (CutCopyOp op)
4066 Evoral::MusicalTime earliest = Evoral::MusicalTime::max();
4067 for (MidiRegionSelection::iterator i = selection->midi_regions.begin(); i != selection->midi_regions.end(); ++i) {
4068 MidiRegionView* mrv = dynamic_cast<MidiRegionView*>(*i);
4070 if (!mrv->selection().empty()) {
4071 earliest = std::min(earliest, (*mrv->selection().begin())->note()->time());
4073 mrv->cut_copy_clear (op);
4075 /* XXX: not ideal, as there may be more than one track involved in the selection */
4076 _last_cut_copy_source_track = &mrv->get_time_axis_view();
4080 if (!selection->points.empty()) {
4081 cut_copy_points (op, earliest, true);
4082 if (op == Cut || op == Delete) {
4083 selection->clear_points ();
4088 struct lt_playlist {
4089 bool operator () (const PlaylistState& a, const PlaylistState& b) {
4090 return a.playlist < b.playlist;
4094 struct PlaylistMapping {
4096 boost::shared_ptr<Playlist> pl;
4098 PlaylistMapping (TimeAxisView* tvp) : tv (tvp) {}
4101 /** Remove `clicked_regionview' */
4103 Editor::remove_clicked_region ()
4105 if (clicked_routeview == 0 || clicked_regionview == 0) {
4109 begin_reversible_command (_("remove region"));
4111 boost::shared_ptr<Playlist> playlist = clicked_routeview->playlist();
4113 playlist->clear_changes ();
4114 playlist->clear_owned_changes ();
4115 playlist->remove_region (clicked_regionview->region());
4116 if (Config->get_edit_mode() == Ripple)
4117 playlist->ripple (clicked_regionview->region()->position(), -clicked_regionview->region()->length(), boost::shared_ptr<Region>());
4119 /* We might have removed regions, which alters other regions' layering_index,
4120 so we need to do a recursive diff here.
4122 vector<Command*> cmds;
4123 playlist->rdiff (cmds);
4124 _session->add_commands (cmds);
4126 _session->add_command(new StatefulDiffCommand (playlist));
4127 commit_reversible_command ();
4131 /** Remove the selected regions */
4133 Editor::remove_selected_regions ()
4135 RegionSelection rs = get_regions_from_selection_and_entered ();
4137 if (!_session || rs.empty()) {
4141 begin_reversible_command (_("remove region"));
4143 list<boost::shared_ptr<Region> > regions_to_remove;
4145 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
4146 // we can't just remove the region(s) in this loop because
4147 // this removes them from the RegionSelection, and they thus
4148 // disappear from underneath the iterator, and the ++i above
4149 // SEGVs in a puzzling fashion.
4151 // so, first iterate over the regions to be removed from rs and
4152 // add them to the regions_to_remove list, and then
4153 // iterate over the list to actually remove them.
4155 regions_to_remove.push_back ((*i)->region());
4158 vector<boost::shared_ptr<Playlist> > playlists;
4160 for (list<boost::shared_ptr<Region> >::iterator rl = regions_to_remove.begin(); rl != regions_to_remove.end(); ++rl) {
4162 boost::shared_ptr<Playlist> playlist = (*rl)->playlist();
4165 // is this check necessary?
4169 /* get_regions_from_selection_and_entered() guarantees that
4170 the playlists involved are unique, so there is no need
4174 playlists.push_back (playlist);
4176 playlist->clear_changes ();
4177 playlist->clear_owned_changes ();
4178 playlist->freeze ();
4179 playlist->remove_region (*rl);
4180 if (Config->get_edit_mode() == Ripple)
4181 playlist->ripple ((*rl)->position(), -(*rl)->length(), boost::shared_ptr<Region>());
4185 vector<boost::shared_ptr<Playlist> >::iterator pl;
4187 for (pl = playlists.begin(); pl != playlists.end(); ++pl) {
4190 /* We might have removed regions, which alters other regions' layering_index,
4191 so we need to do a recursive diff here.
4193 vector<Command*> cmds;
4194 (*pl)->rdiff (cmds);
4195 _session->add_commands (cmds);
4197 _session->add_command(new StatefulDiffCommand (*pl));
4200 commit_reversible_command ();
4203 /** Cut, copy or clear selected regions.
4204 * @param op Operation (Cut, Copy or Clear)
4207 Editor::cut_copy_regions (CutCopyOp op, RegionSelection& rs)
4209 /* we can't use a std::map here because the ordering is important, and we can't trivially sort
4210 a map when we want ordered access to both elements. i think.
4213 vector<PlaylistMapping> pmap;
4215 framepos_t first_position = max_framepos;
4217 typedef set<boost::shared_ptr<Playlist> > FreezeList;
4218 FreezeList freezelist;
4220 /* get ordering correct before we cut/copy */
4222 rs.sort_by_position_and_track ();
4224 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
4226 first_position = min ((framepos_t) (*x)->region()->position(), first_position);
4228 if (op == Cut || op == Clear || op == Delete) {
4229 boost::shared_ptr<Playlist> pl = (*x)->region()->playlist();
4232 FreezeList::iterator fl;
4234 // only take state if this is a new playlist.
4235 for (fl = freezelist.begin(); fl != freezelist.end(); ++fl) {
4241 if (fl == freezelist.end()) {
4242 pl->clear_changes();
4243 pl->clear_owned_changes ();
4245 freezelist.insert (pl);
4250 TimeAxisView* tv = &(*x)->get_time_axis_view();
4251 vector<PlaylistMapping>::iterator z;
4253 for (z = pmap.begin(); z != pmap.end(); ++z) {
4254 if ((*z).tv == tv) {
4259 if (z == pmap.end()) {
4260 pmap.push_back (PlaylistMapping (tv));
4264 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ) {
4266 boost::shared_ptr<Playlist> pl = (*x)->region()->playlist();
4269 /* region not yet associated with a playlist (e.g. unfinished
4276 TimeAxisView& tv = (*x)->get_time_axis_view();
4277 boost::shared_ptr<Playlist> npl;
4278 RegionSelection::iterator tmp;
4285 vector<PlaylistMapping>::iterator z;
4287 for (z = pmap.begin(); z != pmap.end(); ++z) {
4288 if ((*z).tv == &tv) {
4293 assert (z != pmap.end());
4296 npl = PlaylistFactory::create (pl->data_type(), *_session, "cutlist", true);
4304 boost::shared_ptr<Region> r = (*x)->region();
4305 boost::shared_ptr<Region> _xx;
4311 pl->remove_region (r);
4312 if (Config->get_edit_mode() == Ripple)
4313 pl->ripple (r->position(), -r->length(), boost::shared_ptr<Region>());
4317 _xx = RegionFactory::create (r);
4318 npl->add_region (_xx, r->position() - first_position);
4319 pl->remove_region (r);
4320 if (Config->get_edit_mode() == Ripple)
4321 pl->ripple (r->position(), -r->length(), boost::shared_ptr<Region>());
4325 /* copy region before adding, so we're not putting same object into two different playlists */
4326 npl->add_region (RegionFactory::create (r), r->position() - first_position);
4330 pl->remove_region (r);
4331 if (Config->get_edit_mode() == Ripple)
4332 pl->ripple (r->position(), -r->length(), boost::shared_ptr<Region>());
4341 list<boost::shared_ptr<Playlist> > foo;
4343 /* the pmap is in the same order as the tracks in which selected regions occured */
4345 for (vector<PlaylistMapping>::iterator i = pmap.begin(); i != pmap.end(); ++i) {
4348 foo.push_back ((*i).pl);
4353 cut_buffer->set (foo);
4357 _last_cut_copy_source_track = 0;
4359 _last_cut_copy_source_track = pmap.front().tv;
4363 for (FreezeList::iterator pl = freezelist.begin(); pl != freezelist.end(); ++pl) {
4366 /* We might have removed regions, which alters other regions' layering_index,
4367 so we need to do a recursive diff here.
4369 vector<Command*> cmds;
4370 (*pl)->rdiff (cmds);
4371 _session->add_commands (cmds);
4373 _session->add_command (new StatefulDiffCommand (*pl));
4378 Editor::cut_copy_ranges (CutCopyOp op)
4380 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4382 /* Sort the track selection now, so that it if is used, the playlists
4383 selected by the calls below to cut_copy_clear are in the order that
4384 their tracks appear in the editor. This makes things like paste
4385 of ranges work properly.
4388 sort_track_selection (ts);
4391 if (!entered_track) {
4394 ts.push_back (entered_track);
4397 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4398 (*i)->cut_copy_clear (*selection, op);
4403 Editor::paste (float times, bool from_context)
4405 DEBUG_TRACE (DEBUG::CutNPaste, "paste to preferred edit pos\n");
4407 paste_internal (get_preferred_edit_position (false, from_context), times);
4411 Editor::mouse_paste ()
4416 if (!mouse_frame (where, ignored)) {
4421 paste_internal (where, 1);
4425 Editor::paste_internal (framepos_t position, float times)
4427 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("apparent paste position is %1\n", position));
4429 if (cut_buffer->empty(internal_editing())) {
4433 if (position == max_framepos) {
4434 position = get_preferred_edit_position();
4435 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("preferred edit position is %1\n", position));
4438 if (position == last_paste_pos) {
4439 /* repeated paste in the same position */
4442 /* paste in new location, reset repeated paste state */
4444 last_paste_pos = position;
4447 /* get everything in the correct order */
4450 if (!selection->tracks.empty()) {
4451 /* If there is a track selection, paste into exactly those tracks and
4452 only those tracks. This allows the user to be explicit and override
4453 the below "do the reasonable thing" logic. */
4454 ts = selection->tracks.filter_to_unique_playlists ();
4455 sort_track_selection (ts);
4457 /* Figure out which track to base the paste at. */
4458 TimeAxisView* base_track = NULL;
4459 if (_edit_point == Editing::EditAtMouse && entered_track) {
4460 /* With the mouse edit point, paste onto the track under the mouse. */
4461 base_track = entered_track;
4462 } else if (_edit_point == Editing::EditAtMouse && entered_regionview) {
4463 /* With the mouse edit point, paste onto the track of the region under the mouse. */
4464 base_track = &entered_regionview->get_time_axis_view();
4465 } else if (_last_cut_copy_source_track) {
4466 /* Paste to the track that the cut/copy came from (see mantis #333). */
4467 base_track = _last_cut_copy_source_track;
4469 /* This is "impossible" since we've copied... well, do nothing. */
4473 /* Walk up to parent if necessary, so base track is a route. */
4474 while (base_track->get_parent()) {
4475 base_track = base_track->get_parent();
4478 /* Add base track and all tracks below it. The paste logic will select
4479 the appropriate object types from the cut buffer in relative order. */
4480 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4481 if ((*i)->order() >= base_track->order()) {
4486 /* Sort tracks so the nth track of type T will pick the nth object of type T. */
4487 sort_track_selection (ts);
4489 /* Add automation children of each track in order, for pasting several lines. */
4490 for (TrackViewList::iterator i = ts.begin(); i != ts.end();) {
4491 /* Add any automation children for pasting several lines */
4492 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*i++);
4497 typedef RouteTimeAxisView::AutomationTracks ATracks;
4498 const ATracks& atracks = rtv->automation_tracks();
4499 for (ATracks::const_iterator a = atracks.begin(); a != atracks.end(); ++a) {
4500 i = ts.insert(i, a->second.get());
4505 /* We now have a list of trackviews starting at base_track, including
4506 automation children, in the order shown in the editor, e.g. R1,
4507 R1.A1, R1.A2, R2, R2.A1, ... */
4510 begin_reversible_command (Operations::paste);
4512 if (ts.size() == 1 && cut_buffer->lines.size() == 1 &&
4513 dynamic_cast<AutomationTimeAxisView*>(ts.front())) {
4514 /* Only one line copied, and one automation track selected. Do a
4515 "greedy" paste from one automation type to another. */
4517 PasteContext ctx(paste_count, times, ItemCounts(), true);
4518 ts.front()->paste (position, *cut_buffer, ctx);
4522 /* Paste into tracks */
4524 PasteContext ctx(paste_count, times, ItemCounts(), false);
4525 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4526 (*i)->paste (position, *cut_buffer, ctx);
4530 commit_reversible_command ();
4534 Editor::duplicate_some_regions (RegionSelection& regions, float times)
4536 boost::shared_ptr<Playlist> playlist;
4537 RegionSelection sel = regions; // clear (below) may clear the argument list if its the current region selection
4538 RegionSelection foo;
4540 framepos_t const start_frame = regions.start ();
4541 framepos_t const end_frame = regions.end_frame ();
4543 begin_reversible_command (Operations::duplicate_region);
4545 selection->clear_regions ();
4547 for (RegionSelection::iterator i = sel.begin(); i != sel.end(); ++i) {
4549 boost::shared_ptr<Region> r ((*i)->region());
4551 TimeAxisView& tv = (*i)->get_time_axis_view();
4552 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (&tv);
4553 latest_regionviews.clear ();
4554 sigc::connection c = rtv->view()->RegionViewAdded.connect (sigc::mem_fun(*this, &Editor::collect_new_region_view));
4556 playlist = (*i)->region()->playlist();
4557 playlist->clear_changes ();
4558 playlist->duplicate (r, end_frame + (r->first_frame() - start_frame), times);
4559 _session->add_command(new StatefulDiffCommand (playlist));
4563 foo.insert (foo.end(), latest_regionviews.begin(), latest_regionviews.end());
4567 selection->set (foo);
4570 commit_reversible_command ();
4574 Editor::duplicate_selection (float times)
4576 if (selection->time.empty() || selection->tracks.empty()) {
4580 boost::shared_ptr<Playlist> playlist;
4581 vector<boost::shared_ptr<Region> > new_regions;
4582 vector<boost::shared_ptr<Region> >::iterator ri;
4584 create_region_from_selection (new_regions);
4586 if (new_regions.empty()) {
4590 begin_reversible_command (_("duplicate selection"));
4592 ri = new_regions.begin();
4594 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4596 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4597 if ((playlist = (*i)->playlist()) == 0) {
4600 playlist->clear_changes ();
4602 if (clicked_selection) {
4603 end = selection->time[clicked_selection].end;
4605 end = selection->time.end_frame();
4607 playlist->duplicate (*ri, end, times);
4608 _session->add_command (new StatefulDiffCommand (playlist));
4611 if (ri == new_regions.end()) {
4616 commit_reversible_command ();
4619 /** Reset all selected points to the relevant default value */
4621 Editor::reset_point_selection ()
4623 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
4624 ARDOUR::AutomationList::iterator j = (*i)->model ();
4625 (*j)->value = (*i)->line().the_list()->default_value ();
4630 Editor::center_playhead ()
4632 float const page = _visible_canvas_width * samples_per_pixel;
4633 center_screen_internal (playhead_cursor->current_frame (), page);
4637 Editor::center_edit_point ()
4639 float const page = _visible_canvas_width * samples_per_pixel;
4640 center_screen_internal (get_preferred_edit_position(), page);
4643 /** Caller must begin and commit a reversible command */
4645 Editor::clear_playlist (boost::shared_ptr<Playlist> playlist)
4647 playlist->clear_changes ();
4649 _session->add_command (new StatefulDiffCommand (playlist));
4653 Editor::nudge_track (bool use_edit, bool forwards)
4655 boost::shared_ptr<Playlist> playlist;
4656 framepos_t distance;
4657 framepos_t next_distance;
4661 start = get_preferred_edit_position();
4666 if ((distance = get_nudge_distance (start, next_distance)) == 0) {
4670 if (selection->tracks.empty()) {
4674 begin_reversible_command (_("nudge track"));
4676 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4678 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4680 if ((playlist = (*i)->playlist()) == 0) {
4684 playlist->clear_changes ();
4685 playlist->clear_owned_changes ();
4687 playlist->nudge_after (start, distance, forwards);
4689 vector<Command*> cmds;
4691 playlist->rdiff (cmds);
4692 _session->add_commands (cmds);
4694 _session->add_command (new StatefulDiffCommand (playlist));
4697 commit_reversible_command ();
4701 Editor::remove_last_capture ()
4703 vector<string> choices;
4710 if (Config->get_verify_remove_last_capture()) {
4711 prompt = _("Do you really want to destroy the last capture?"
4712 "\n(This is destructive and cannot be undone)");
4714 choices.push_back (_("No, do nothing."));
4715 choices.push_back (_("Yes, destroy it."));
4717 Gtkmm2ext::Choice prompter (_("Destroy last capture"), prompt, choices);
4719 if (prompter.run () == 1) {
4720 _session->remove_last_capture ();
4721 _regions->redisplay ();
4725 _session->remove_last_capture();
4726 _regions->redisplay ();
4731 Editor::normalize_region ()
4737 RegionSelection rs = get_regions_from_selection_and_entered ();
4743 NormalizeDialog dialog (rs.size() > 1);
4745 if (dialog.run () == RESPONSE_CANCEL) {
4749 CursorContext::Handle cursor_ctx = CursorContext::create(*this, _cursors->wait);
4752 /* XXX: should really only count audio regions here */
4753 int const regions = rs.size ();
4755 /* Make a list of the selected audio regions' maximum amplitudes, and also
4756 obtain the maximum amplitude of them all.
4758 list<double> max_amps;
4760 for (RegionSelection::const_iterator i = rs.begin(); i != rs.end(); ++i) {
4761 AudioRegionView const * arv = dynamic_cast<AudioRegionView const *> (*i);
4763 dialog.descend (1.0 / regions);
4764 double const a = arv->audio_region()->maximum_amplitude (&dialog);
4767 /* the user cancelled the operation */
4771 max_amps.push_back (a);
4772 max_amp = max (max_amp, a);
4777 begin_reversible_command (_("normalize"));
4779 list<double>::const_iterator a = max_amps.begin ();
4781 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
4782 AudioRegionView* const arv = dynamic_cast<AudioRegionView*> (*r);
4787 arv->region()->clear_changes ();
4789 double const amp = dialog.normalize_individually() ? *a : max_amp;
4791 arv->audio_region()->normalize (amp, dialog.target ());
4792 _session->add_command (new StatefulDiffCommand (arv->region()));
4797 commit_reversible_command ();
4802 Editor::reset_region_scale_amplitude ()
4808 RegionSelection rs = get_regions_from_selection_and_entered ();
4814 begin_reversible_command ("reset gain");
4816 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
4817 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
4820 arv->region()->clear_changes ();
4821 arv->audio_region()->set_scale_amplitude (1.0f);
4822 _session->add_command (new StatefulDiffCommand (arv->region()));
4825 commit_reversible_command ();
4829 Editor::adjust_region_gain (bool up)
4831 RegionSelection rs = get_regions_from_selection_and_entered ();
4833 if (!_session || rs.empty()) {
4837 begin_reversible_command ("adjust region gain");
4839 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
4840 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
4845 arv->region()->clear_changes ();
4847 double dB = accurate_coefficient_to_dB (arv->audio_region()->scale_amplitude ());
4855 arv->audio_region()->set_scale_amplitude (dB_to_coefficient (dB));
4856 _session->add_command (new StatefulDiffCommand (arv->region()));
4859 commit_reversible_command ();
4864 Editor::reverse_region ()
4870 Reverse rev (*_session);
4871 apply_filter (rev, _("reverse regions"));
4875 Editor::strip_region_silence ()
4881 RegionSelection rs = get_regions_from_selection_and_entered ();
4887 std::list<RegionView*> audio_only;
4889 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
4890 AudioRegionView* const arv = dynamic_cast<AudioRegionView*> (*i);
4892 audio_only.push_back (arv);
4896 StripSilenceDialog d (_session, audio_only);
4897 int const r = d.run ();
4901 if (r == Gtk::RESPONSE_OK) {
4902 ARDOUR::AudioIntervalMap silences;
4903 d.silences (silences);
4904 StripSilence s (*_session, silences, d.fade_length());
4905 apply_filter (s, _("strip silence"), &d);
4910 Editor::apply_midi_note_edit_op_to_region (MidiOperator& op, MidiRegionView& mrv)
4912 Evoral::Sequence<Evoral::MusicalTime>::Notes selected;
4913 mrv.selection_as_notelist (selected, true);
4915 vector<Evoral::Sequence<Evoral::MusicalTime>::Notes> v;
4916 v.push_back (selected);
4918 framepos_t pos_frames = mrv.midi_region()->position() - mrv.midi_region()->start();
4919 Evoral::MusicalTime pos_beats = _session->tempo_map().framewalk_to_beats(0, pos_frames);
4921 return op (mrv.midi_region()->model(), pos_beats, v);
4925 Editor::apply_midi_note_edit_op (MidiOperator& op, const RegionSelection& rs)
4931 begin_reversible_command (op.name ());
4933 for (RegionSelection::const_iterator r = rs.begin(); r != rs.end(); ) {
4934 RegionSelection::const_iterator tmp = r;
4937 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*r);
4940 Command* cmd = apply_midi_note_edit_op_to_region (op, *mrv);
4943 _session->add_command (cmd);
4950 commit_reversible_command ();
4954 Editor::fork_region ()
4956 RegionSelection rs = get_regions_from_selection_and_entered ();
4962 begin_reversible_command (_("Fork Region(s)"));
4964 CursorContext::Handle cursor_ctx = CursorContext::create(*this, _cursors->wait);
4967 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
4968 RegionSelection::iterator tmp = r;
4971 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*>(*r);
4975 boost::shared_ptr<Playlist> playlist = mrv->region()->playlist();
4976 boost::shared_ptr<MidiSource> new_source = _session->create_midi_source_by_stealing_name (mrv->midi_view()->track());
4977 boost::shared_ptr<MidiRegion> newregion = mrv->midi_region()->clone (new_source);
4979 playlist->clear_changes ();
4980 playlist->replace_region (mrv->region(), newregion, mrv->region()->position());
4981 _session->add_command(new StatefulDiffCommand (playlist));
4983 error << string_compose (_("Could not unlink %1"), mrv->region()->name()) << endmsg;
4990 commit_reversible_command ();
4994 Editor::quantize_region ()
4997 quantize_regions(get_regions_from_selection_and_entered ());
5002 Editor::quantize_regions (const RegionSelection& rs)
5004 if (rs.n_midi_regions() == 0) {
5008 QuantizeDialog* qd = new QuantizeDialog (*this);
5011 const int r = qd->run ();
5014 if (r == Gtk::RESPONSE_OK) {
5015 Quantize quant (qd->snap_start(), qd->snap_end(),
5016 qd->start_grid_size(), qd->end_grid_size(),
5017 qd->strength(), qd->swing(), qd->threshold());
5019 apply_midi_note_edit_op (quant, rs);
5024 Editor::legatize_region (bool shrink_only)
5027 legatize_regions(get_regions_from_selection_and_entered (), shrink_only);
5032 Editor::legatize_regions (const RegionSelection& rs, bool shrink_only)
5034 if (rs.n_midi_regions() == 0) {
5038 Legatize legatize(shrink_only);
5039 apply_midi_note_edit_op (legatize, rs);
5043 Editor::transform_region ()
5046 transform_regions(get_regions_from_selection_and_entered ());
5051 Editor::transform_regions (const RegionSelection& rs)
5053 if (rs.n_midi_regions() == 0) {
5057 TransformDialog* td = new TransformDialog();
5060 const int r = td->run();
5063 if (r == Gtk::RESPONSE_OK) {
5064 Transform transform(td->get());
5065 apply_midi_note_edit_op(transform, rs);
5070 Editor::insert_patch_change (bool from_context)
5072 RegionSelection rs = get_regions_from_selection_and_entered ();
5078 const framepos_t p = get_preferred_edit_position (false, from_context);
5080 /* XXX: bit of a hack; use the MIDNAM from the first selected region;
5081 there may be more than one, but the PatchChangeDialog can only offer
5082 one set of patch menus.
5084 MidiRegionView* first = dynamic_cast<MidiRegionView*> (rs.front ());
5086 Evoral::PatchChange<Evoral::MusicalTime> empty (Evoral::MusicalTime(), 0, 0, 0);
5087 PatchChangeDialog d (0, _session, empty, first->instrument_info(), Gtk::Stock::ADD);
5089 if (d.run() == RESPONSE_CANCEL) {
5093 for (RegionSelection::iterator i = rs.begin (); i != rs.end(); ++i) {
5094 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*i);
5096 if (p >= mrv->region()->first_frame() && p <= mrv->region()->last_frame()) {
5097 mrv->add_patch_change (p - mrv->region()->position(), d.patch ());
5104 Editor::apply_filter (Filter& filter, string command, ProgressReporter* progress)
5106 RegionSelection rs = get_regions_from_selection_and_entered ();
5112 begin_reversible_command (command);
5114 CursorContext::Handle cursor_ctx = CursorContext::create(*this, _cursors->wait);
5118 int const N = rs.size ();
5120 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
5121 RegionSelection::iterator tmp = r;
5124 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
5126 boost::shared_ptr<Playlist> playlist = arv->region()->playlist();
5129 progress->descend (1.0 / N);
5132 if (arv->audio_region()->apply (filter, progress) == 0) {
5134 playlist->clear_changes ();
5135 playlist->clear_owned_changes ();
5137 if (filter.results.empty ()) {
5139 /* no regions returned; remove the old one */
5140 playlist->remove_region (arv->region ());
5144 std::vector<boost::shared_ptr<Region> >::iterator res = filter.results.begin ();
5146 /* first region replaces the old one */
5147 playlist->replace_region (arv->region(), *res, (*res)->position());
5151 while (res != filter.results.end()) {
5152 playlist->add_region (*res, (*res)->position());
5158 /* We might have removed regions, which alters other regions' layering_index,
5159 so we need to do a recursive diff here.
5161 vector<Command*> cmds;
5162 playlist->rdiff (cmds);
5163 _session->add_commands (cmds);
5165 _session->add_command(new StatefulDiffCommand (playlist));
5171 progress->ascend ();
5179 commit_reversible_command ();
5183 Editor::external_edit_region ()
5189 Editor::reset_region_gain_envelopes ()
5191 RegionSelection rs = get_regions_from_selection_and_entered ();
5193 if (!_session || rs.empty()) {
5197 begin_reversible_command (_("reset region gain"));
5199 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5200 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
5202 boost::shared_ptr<AutomationList> alist (arv->audio_region()->envelope());
5203 XMLNode& before (alist->get_state());
5205 arv->audio_region()->set_default_envelope ();
5206 _session->add_command (new MementoCommand<AutomationList>(*arv->audio_region()->envelope().get(), &before, &alist->get_state()));
5210 commit_reversible_command ();
5214 Editor::set_region_gain_visibility (RegionView* rv)
5216 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (rv);
5218 arv->update_envelope_visibility();
5223 Editor::set_gain_envelope_visibility ()
5229 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5230 AudioTimeAxisView* v = dynamic_cast<AudioTimeAxisView*>(*i);
5232 v->audio_view()->foreach_regionview (sigc::mem_fun (this, &Editor::set_region_gain_visibility));
5238 Editor::toggle_gain_envelope_active ()
5240 if (_ignore_region_action) {
5244 RegionSelection rs = get_regions_from_selection_and_entered ();
5246 if (!_session || rs.empty()) {
5250 begin_reversible_command (_("region gain envelope active"));
5252 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5253 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
5255 arv->region()->clear_changes ();
5256 arv->audio_region()->set_envelope_active (!arv->audio_region()->envelope_active());
5257 _session->add_command (new StatefulDiffCommand (arv->region()));
5261 commit_reversible_command ();
5265 Editor::toggle_region_lock ()
5267 if (_ignore_region_action) {
5271 RegionSelection rs = get_regions_from_selection_and_entered ();
5273 if (!_session || rs.empty()) {
5277 begin_reversible_command (_("toggle region lock"));
5279 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5280 (*i)->region()->clear_changes ();
5281 (*i)->region()->set_locked (!(*i)->region()->locked());
5282 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5285 commit_reversible_command ();
5289 Editor::toggle_region_video_lock ()
5291 if (_ignore_region_action) {
5295 RegionSelection rs = get_regions_from_selection_and_entered ();
5297 if (!_session || rs.empty()) {
5301 begin_reversible_command (_("Toggle Video Lock"));
5303 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5304 (*i)->region()->clear_changes ();
5305 (*i)->region()->set_video_locked (!(*i)->region()->video_locked());
5306 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5309 commit_reversible_command ();
5313 Editor::toggle_region_lock_style ()
5315 if (_ignore_region_action) {
5319 RegionSelection rs = get_regions_from_selection_and_entered ();
5321 if (!_session || rs.empty()) {
5325 begin_reversible_command (_("region lock style"));
5327 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5328 (*i)->region()->clear_changes ();
5329 PositionLockStyle const ns = (*i)->region()->position_lock_style() == AudioTime ? MusicTime : AudioTime;
5330 (*i)->region()->set_position_lock_style (ns);
5331 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5334 commit_reversible_command ();
5338 Editor::toggle_opaque_region ()
5340 if (_ignore_region_action) {
5344 RegionSelection rs = get_regions_from_selection_and_entered ();
5346 if (!_session || rs.empty()) {
5350 begin_reversible_command (_("change region opacity"));
5352 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5353 (*i)->region()->clear_changes ();
5354 (*i)->region()->set_opaque (!(*i)->region()->opaque());
5355 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5358 commit_reversible_command ();
5362 Editor::toggle_record_enable ()
5364 bool new_state = false;
5366 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5367 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5370 if (!rtav->is_track())
5374 new_state = !rtav->track()->record_enabled();
5378 rtav->track()->set_record_enabled (new_state, this);
5383 Editor::toggle_solo ()
5385 bool new_state = false;
5387 boost::shared_ptr<RouteList> rl (new RouteList);
5389 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5390 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5397 new_state = !rtav->route()->soloed ();
5401 rl->push_back (rtav->route());
5404 _session->set_solo (rl, new_state, Session::rt_cleanup, true);
5408 Editor::toggle_mute ()
5410 bool new_state = false;
5412 boost::shared_ptr<RouteList> rl (new RouteList);
5414 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5415 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5422 new_state = !rtav->route()->muted();
5426 rl->push_back (rtav->route());
5429 _session->set_mute (rl, new_state, Session::rt_cleanup, true);
5433 Editor::toggle_solo_isolate ()
5439 Editor::fade_range ()
5441 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
5443 begin_reversible_command (_("fade range"));
5445 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
5446 (*i)->fade_range (selection->time);
5449 commit_reversible_command ();
5454 Editor::set_fade_length (bool in)
5456 RegionSelection rs = get_regions_from_selection_and_entered ();
5462 /* we need a region to measure the offset from the start */
5464 RegionView* rv = rs.front ();
5466 framepos_t pos = get_preferred_edit_position();
5470 if (pos > rv->region()->last_frame() || pos < rv->region()->first_frame()) {
5471 /* edit point is outside the relevant region */
5476 if (pos <= rv->region()->position()) {
5480 len = pos - rv->region()->position();
5481 cmd = _("set fade in length");
5483 if (pos >= rv->region()->last_frame()) {
5487 len = rv->region()->last_frame() - pos;
5488 cmd = _("set fade out length");
5491 begin_reversible_command (cmd);
5493 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5494 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5500 boost::shared_ptr<AutomationList> alist;
5502 alist = tmp->audio_region()->fade_in();
5504 alist = tmp->audio_region()->fade_out();
5507 XMLNode &before = alist->get_state();
5510 tmp->audio_region()->set_fade_in_length (len);
5511 tmp->audio_region()->set_fade_in_active (true);
5513 tmp->audio_region()->set_fade_out_length (len);
5514 tmp->audio_region()->set_fade_out_active (true);
5517 XMLNode &after = alist->get_state();
5518 _session->add_command(new MementoCommand<AutomationList>(*alist, &before, &after));
5521 commit_reversible_command ();
5525 Editor::set_fade_in_shape (FadeShape shape)
5527 RegionSelection rs = get_regions_from_selection_and_entered ();
5533 begin_reversible_command (_("set fade in shape"));
5535 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5536 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5542 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_in();
5543 XMLNode &before = alist->get_state();
5545 tmp->audio_region()->set_fade_in_shape (shape);
5547 XMLNode &after = alist->get_state();
5548 _session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
5551 commit_reversible_command ();
5556 Editor::set_fade_out_shape (FadeShape shape)
5558 RegionSelection rs = get_regions_from_selection_and_entered ();
5564 begin_reversible_command (_("set fade out shape"));
5566 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5567 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5573 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_out();
5574 XMLNode &before = alist->get_state();
5576 tmp->audio_region()->set_fade_out_shape (shape);
5578 XMLNode &after = alist->get_state();
5579 _session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
5582 commit_reversible_command ();
5586 Editor::set_fade_in_active (bool yn)
5588 RegionSelection rs = get_regions_from_selection_and_entered ();
5594 begin_reversible_command (_("set fade in active"));
5596 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5597 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5604 boost::shared_ptr<AudioRegion> ar (tmp->audio_region());
5606 ar->clear_changes ();
5607 ar->set_fade_in_active (yn);
5608 _session->add_command (new StatefulDiffCommand (ar));
5611 commit_reversible_command ();
5615 Editor::set_fade_out_active (bool yn)
5617 RegionSelection rs = get_regions_from_selection_and_entered ();
5623 begin_reversible_command (_("set fade out active"));
5625 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5626 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5632 boost::shared_ptr<AudioRegion> ar (tmp->audio_region());
5634 ar->clear_changes ();
5635 ar->set_fade_out_active (yn);
5636 _session->add_command(new StatefulDiffCommand (ar));
5639 commit_reversible_command ();
5643 Editor::toggle_region_fades (int dir)
5645 if (_ignore_region_action) {
5649 boost::shared_ptr<AudioRegion> ar;
5652 RegionSelection rs = get_regions_from_selection_and_entered ();
5658 RegionSelection::iterator i;
5659 for (i = rs.begin(); i != rs.end(); ++i) {
5660 if ((ar = boost::dynamic_pointer_cast<AudioRegion>((*i)->region())) != 0) {
5662 yn = ar->fade_out_active ();
5664 yn = ar->fade_in_active ();
5670 if (i == rs.end()) {
5674 /* XXX should this undo-able? */
5676 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5677 if ((ar = boost::dynamic_pointer_cast<AudioRegion>((*i)->region())) == 0) {
5680 if (dir == 1 || dir == 0) {
5681 ar->set_fade_in_active (!yn);
5684 if (dir == -1 || dir == 0) {
5685 ar->set_fade_out_active (!yn);
5691 /** Update region fade visibility after its configuration has been changed */
5693 Editor::update_region_fade_visibility ()
5695 bool _fade_visibility = _session->config.get_show_region_fades ();
5697 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5698 AudioTimeAxisView* v = dynamic_cast<AudioTimeAxisView*>(*i);
5700 if (_fade_visibility) {
5701 v->audio_view()->show_all_fades ();
5703 v->audio_view()->hide_all_fades ();
5710 Editor::set_edit_point ()
5715 if (!mouse_frame (where, ignored)) {
5721 if (selection->markers.empty()) {
5723 mouse_add_new_marker (where);
5728 Location* loc = find_location_from_marker (selection->markers.front(), ignored);
5731 loc->move_to (where);
5737 Editor::set_playhead_cursor ()
5739 if (entered_marker) {
5740 _session->request_locate (entered_marker->position(), _session->transport_rolling());
5745 if (!mouse_frame (where, ignored)) {
5752 _session->request_locate (where, _session->transport_rolling());
5756 if (ARDOUR_UI::config()->get_follow_edits()) {
5757 cancel_time_selection();
5762 Editor::split_region ()
5764 if ( !selection->time.empty()) {
5765 separate_regions_between (selection->time);
5769 RegionSelection rs = get_regions_from_selection_and_edit_point ();
5771 framepos_t where = get_preferred_edit_position ();
5777 split_regions_at (where, rs);
5780 struct EditorOrderRouteSorter {
5781 bool operator() (boost::shared_ptr<Route> a, boost::shared_ptr<Route> b) {
5782 return a->order_key () < b->order_key ();
5787 Editor::select_next_route()
5789 if (selection->tracks.empty()) {
5790 selection->set (track_views.front());
5794 TimeAxisView* current = selection->tracks.front();
5798 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5799 if (*i == current) {
5801 if (i != track_views.end()) {
5804 current = (*(track_views.begin()));
5805 //selection->set (*(track_views.begin()));
5810 rui = dynamic_cast<RouteUI *>(current);
5811 } while ( current->hidden() || (rui != NULL && !rui->route()->active()));
5813 selection->set(current);
5815 ensure_time_axis_view_is_visible (*current, false);
5819 Editor::select_prev_route()
5821 if (selection->tracks.empty()) {
5822 selection->set (track_views.front());
5826 TimeAxisView* current = selection->tracks.front();
5830 for (TrackViewList::reverse_iterator i = track_views.rbegin(); i != track_views.rend(); ++i) {
5831 if (*i == current) {
5833 if (i != track_views.rend()) {
5836 current = *(track_views.rbegin());
5841 rui = dynamic_cast<RouteUI *>(current);
5842 } while ( current->hidden() || (rui != NULL && !rui->route()->active()));
5844 selection->set (current);
5846 ensure_time_axis_view_is_visible (*current, false);
5850 Editor::set_loop_from_selection (bool play)
5852 if (_session == 0 || selection->time.empty()) {
5856 framepos_t start = selection->time[clicked_selection].start;
5857 framepos_t end = selection->time[clicked_selection].end;
5859 set_loop_range (start, end, _("set loop range from selection"));
5862 _session->request_locate (start, true);
5863 _session->request_play_loop (true);
5868 Editor::set_loop_from_edit_range (bool play)
5870 if (_session == 0) {
5877 if (!get_edit_op_range (start, end)) {
5881 set_loop_range (start, end, _("set loop range from edit range"));
5884 _session->request_locate (start, true);
5885 _session->request_play_loop (true);
5890 Editor::set_loop_from_region (bool play)
5892 framepos_t start = max_framepos;
5895 RegionSelection rs = get_regions_from_selection_and_entered ();
5901 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5902 if ((*i)->region()->position() < start) {
5903 start = (*i)->region()->position();
5905 if ((*i)->region()->last_frame() + 1 > end) {
5906 end = (*i)->region()->last_frame() + 1;
5910 set_loop_range (start, end, _("set loop range from region"));
5913 _session->request_locate (start, true);
5914 _session->request_play_loop (true);
5919 Editor::set_punch_from_selection ()
5921 if (_session == 0 || selection->time.empty()) {
5925 framepos_t start = selection->time[clicked_selection].start;
5926 framepos_t end = selection->time[clicked_selection].end;
5928 set_punch_range (start, end, _("set punch range from selection"));
5932 Editor::set_session_extents_from_selection ()
5934 if (_session == 0 || selection->time.empty()) {
5938 begin_reversible_command (_("set session start/stop from selection"));
5940 framepos_t start = selection->time[clicked_selection].start;
5941 framepos_t end = selection->time[clicked_selection].end;
5944 if ((loc = _session->locations()->session_range_location()) == 0) {
5945 _session->set_session_extents ( start, end ); // this will create a new session range; no need for UNDO
5947 XMLNode &before = loc->get_state();
5949 _session->set_session_extents ( start, end );
5951 XMLNode &after = loc->get_state();
5953 _session->add_command (new MementoCommand<Location>(*loc, &before, &after));
5955 commit_reversible_command ();
5960 Editor::set_punch_from_edit_range ()
5962 if (_session == 0) {
5969 if (!get_edit_op_range (start, end)) {
5973 set_punch_range (start, end, _("set punch range from edit range"));
5977 Editor::set_punch_from_region ()
5979 framepos_t start = max_framepos;
5982 RegionSelection rs = get_regions_from_selection_and_entered ();
5988 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5989 if ((*i)->region()->position() < start) {
5990 start = (*i)->region()->position();
5992 if ((*i)->region()->last_frame() + 1 > end) {
5993 end = (*i)->region()->last_frame() + 1;
5997 set_punch_range (start, end, _("set punch range from region"));
6001 Editor::pitch_shift_region ()
6003 RegionSelection rs = get_regions_from_selection_and_entered ();
6005 RegionSelection audio_rs;
6006 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
6007 if (dynamic_cast<AudioRegionView*> (*i)) {
6008 audio_rs.push_back (*i);
6012 if (audio_rs.empty()) {
6016 pitch_shift (audio_rs, 1.2);
6020 Editor::transpose_region ()
6022 RegionSelection rs = get_regions_from_selection_and_entered ();
6024 list<MidiRegionView*> midi_region_views;
6025 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
6026 MidiRegionView* mrv = dynamic_cast<MidiRegionView*> (*i);
6028 midi_region_views.push_back (mrv);
6033 int const r = d.run ();
6034 if (r != RESPONSE_ACCEPT) {
6038 for (list<MidiRegionView*>::iterator i = midi_region_views.begin(); i != midi_region_views.end(); ++i) {
6039 (*i)->midi_region()->transpose (d.semitones ());
6044 Editor::set_tempo_from_region ()
6046 RegionSelection rs = get_regions_from_selection_and_entered ();
6048 if (!_session || rs.empty()) {
6052 RegionView* rv = rs.front();
6054 define_one_bar (rv->region()->position(), rv->region()->last_frame() + 1);
6058 Editor::use_range_as_bar ()
6060 framepos_t start, end;
6061 if (get_edit_op_range (start, end)) {
6062 define_one_bar (start, end);
6067 Editor::define_one_bar (framepos_t start, framepos_t end)
6069 framepos_t length = end - start;
6071 const Meter& m (_session->tempo_map().meter_at (start));
6073 /* length = 1 bar */
6075 /* now we want frames per beat.
6076 we have frames per bar, and beats per bar, so ...
6079 /* XXXX METER MATH */
6081 double frames_per_beat = length / m.divisions_per_bar();
6083 /* beats per minute = */
6085 double beats_per_minute = (_session->frame_rate() * 60.0) / frames_per_beat;
6087 /* now decide whether to:
6089 (a) set global tempo
6090 (b) add a new tempo marker
6094 const TempoSection& t (_session->tempo_map().tempo_section_at (start));
6096 bool do_global = false;
6098 if ((_session->tempo_map().n_tempos() == 1) && (_session->tempo_map().n_meters() == 1)) {
6100 /* only 1 tempo & 1 meter: ask if the user wants to set the tempo
6101 at the start, or create a new marker
6104 vector<string> options;
6105 options.push_back (_("Cancel"));
6106 options.push_back (_("Add new marker"));
6107 options.push_back (_("Set global tempo"));
6110 _("Define one bar"),
6111 _("Do you want to set the global tempo or add a new tempo marker?"),
6115 c.set_default_response (2);
6131 /* more than 1 tempo and/or meter section already, go ahead do the "usual":
6132 if the marker is at the region starter, change it, otherwise add
6137 begin_reversible_command (_("set tempo from region"));
6138 XMLNode& before (_session->tempo_map().get_state());
6141 _session->tempo_map().change_initial_tempo (beats_per_minute, t.note_type());
6142 } else if (t.frame() == start) {
6143 _session->tempo_map().change_existing_tempo_at (start, beats_per_minute, t.note_type());
6145 Timecode::BBT_Time bbt;
6146 _session->tempo_map().bbt_time (start, bbt);
6147 _session->tempo_map().add_tempo (Tempo (beats_per_minute, t.note_type()), bbt);
6150 XMLNode& after (_session->tempo_map().get_state());
6152 _session->add_command (new MementoCommand<TempoMap>(_session->tempo_map(), &before, &after));
6153 commit_reversible_command ();
6157 Editor::split_region_at_transients ()
6159 AnalysisFeatureList positions;
6161 RegionSelection rs = get_regions_from_selection_and_entered ();
6163 if (!_session || rs.empty()) {
6167 begin_reversible_command (_("split regions"));
6169 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ) {
6171 RegionSelection::iterator tmp;
6176 boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion> ((*i)->region());
6178 if (ar && (ar->get_transients (positions) == 0)) {
6179 split_region_at_points ((*i)->region(), positions, true);
6186 commit_reversible_command ();
6191 Editor::split_region_at_points (boost::shared_ptr<Region> r, AnalysisFeatureList& positions, bool can_ferret, bool select_new)
6193 bool use_rhythmic_rodent = false;
6195 boost::shared_ptr<Playlist> pl = r->playlist();
6197 list<boost::shared_ptr<Region> > new_regions;
6203 if (positions.empty()) {
6208 if (positions.size() > 20 && can_ferret) {
6209 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);
6210 MessageDialog msg (msgstr,
6213 Gtk::BUTTONS_OK_CANCEL);
6216 msg.add_button (_("Call for the Ferret!"), RESPONSE_APPLY);
6217 msg.set_secondary_text (_("Press OK to continue with this split operation\nor ask the Ferret dialog to tune the analysis"));
6219 msg.set_secondary_text (_("Press OK to continue with this split operation"));
6222 msg.set_title (_("Excessive split?"));
6225 int response = msg.run();
6231 case RESPONSE_APPLY:
6232 use_rhythmic_rodent = true;
6239 if (use_rhythmic_rodent) {
6240 show_rhythm_ferret ();
6244 AnalysisFeatureList::const_iterator x;
6246 pl->clear_changes ();
6247 pl->clear_owned_changes ();
6249 x = positions.begin();
6251 if (x == positions.end()) {
6256 pl->remove_region (r);
6260 while (x != positions.end()) {
6262 /* deal with positons that are out of scope of present region bounds */
6263 if (*x <= 0 || *x > r->length()) {
6268 /* file start = original start + how far we from the initial position ?
6271 framepos_t file_start = r->start() + pos;
6273 /* length = next position - current position
6276 framepos_t len = (*x) - pos;
6278 /* XXX we do we really want to allow even single-sample regions?
6279 shouldn't we have some kind of lower limit on region size?
6288 if (RegionFactory::region_name (new_name, r->name())) {
6292 /* do NOT announce new regions 1 by one, just wait till they are all done */
6296 plist.add (ARDOUR::Properties::start, file_start);
6297 plist.add (ARDOUR::Properties::length, len);
6298 plist.add (ARDOUR::Properties::name, new_name);
6299 plist.add (ARDOUR::Properties::layer, 0);
6301 boost::shared_ptr<Region> nr = RegionFactory::create (r->sources(), plist, false);
6302 /* because we set annouce to false, manually add the new region to the
6305 RegionFactory::map_add (nr);
6307 pl->add_region (nr, r->position() + pos);
6310 new_regions.push_front(nr);
6319 RegionFactory::region_name (new_name, r->name());
6321 /* Add the final region */
6324 plist.add (ARDOUR::Properties::start, r->start() + pos);
6325 plist.add (ARDOUR::Properties::length, r->last_frame() - (r->position() + pos) + 1);
6326 plist.add (ARDOUR::Properties::name, new_name);
6327 plist.add (ARDOUR::Properties::layer, 0);
6329 boost::shared_ptr<Region> nr = RegionFactory::create (r->sources(), plist, false);
6330 /* because we set annouce to false, manually add the new region to the
6333 RegionFactory::map_add (nr);
6334 pl->add_region (nr, r->position() + pos);
6337 new_regions.push_front(nr);
6342 /* We might have removed regions, which alters other regions' layering_index,
6343 so we need to do a recursive diff here.
6345 vector<Command*> cmds;
6347 _session->add_commands (cmds);
6349 _session->add_command (new StatefulDiffCommand (pl));
6353 for (list<boost::shared_ptr<Region> >::iterator i = new_regions.begin(); i != new_regions.end(); ++i){
6354 set_selected_regionview_from_region_list ((*i), Selection::Add);
6360 Editor::place_transient()
6366 RegionSelection rs = get_regions_from_selection_and_edit_point ();
6372 framepos_t where = get_preferred_edit_position();
6374 begin_reversible_command (_("place transient"));
6376 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6377 framepos_t position = (*r)->region()->position();
6378 (*r)->region()->add_transient(where - position);
6381 commit_reversible_command ();
6385 Editor::remove_transient(ArdourCanvas::Item* item)
6391 ArdourCanvas::Line* _line = reinterpret_cast<ArdourCanvas::Line*> (item);
6394 AudioRegionView* _arv = reinterpret_cast<AudioRegionView*> (item->get_data ("regionview"));
6395 _arv->remove_transient (*(float*) _line->get_data ("position"));
6399 Editor::snap_regions_to_grid ()
6401 list <boost::shared_ptr<Playlist > > used_playlists;
6403 RegionSelection rs = get_regions_from_selection_and_entered ();
6405 if (!_session || rs.empty()) {
6409 begin_reversible_command (_("snap regions to grid"));
6411 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6413 boost::shared_ptr<Playlist> pl = (*r)->region()->playlist();
6415 if (!pl->frozen()) {
6416 /* we haven't seen this playlist before */
6418 /* remember used playlists so we can thaw them later */
6419 used_playlists.push_back(pl);
6423 framepos_t start_frame = (*r)->region()->first_frame ();
6424 snap_to (start_frame);
6425 (*r)->region()->set_position (start_frame);
6428 while (used_playlists.size() > 0) {
6429 list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
6431 used_playlists.pop_front();
6434 commit_reversible_command ();
6438 Editor::close_region_gaps ()
6440 list <boost::shared_ptr<Playlist > > used_playlists;
6442 RegionSelection rs = get_regions_from_selection_and_entered ();
6444 if (!_session || rs.empty()) {
6448 Dialog dialog (_("Close Region Gaps"));
6451 table.set_spacings (12);
6452 table.set_border_width (12);
6453 Label* l = manage (left_aligned_label (_("Crossfade length")));
6454 table.attach (*l, 0, 1, 0, 1);
6456 SpinButton spin_crossfade (1, 0);
6457 spin_crossfade.set_range (0, 15);
6458 spin_crossfade.set_increments (1, 1);
6459 spin_crossfade.set_value (5);
6460 table.attach (spin_crossfade, 1, 2, 0, 1);
6462 table.attach (*manage (new Label (_("ms"))), 2, 3, 0, 1);
6464 l = manage (left_aligned_label (_("Pull-back length")));
6465 table.attach (*l, 0, 1, 1, 2);
6467 SpinButton spin_pullback (1, 0);
6468 spin_pullback.set_range (0, 100);
6469 spin_pullback.set_increments (1, 1);
6470 spin_pullback.set_value(30);
6471 table.attach (spin_pullback, 1, 2, 1, 2);
6473 table.attach (*manage (new Label (_("ms"))), 2, 3, 1, 2);
6475 dialog.get_vbox()->pack_start (table);
6476 dialog.add_button (Stock::CANCEL, RESPONSE_CANCEL);
6477 dialog.add_button (_("Ok"), RESPONSE_ACCEPT);
6480 if (dialog.run () == RESPONSE_CANCEL) {
6484 framepos_t crossfade_len = spin_crossfade.get_value();
6485 framepos_t pull_back_frames = spin_pullback.get_value();
6487 crossfade_len = lrintf (crossfade_len * _session->frame_rate()/1000);
6488 pull_back_frames = lrintf (pull_back_frames * _session->frame_rate()/1000);
6490 /* Iterate over the region list and make adjacent regions overlap by crossfade_len_ms */
6492 begin_reversible_command (_("close region gaps"));
6495 boost::shared_ptr<Region> last_region;
6497 rs.sort_by_position_and_track();
6499 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6501 boost::shared_ptr<Playlist> pl = (*r)->region()->playlist();
6503 if (!pl->frozen()) {
6504 /* we haven't seen this playlist before */
6506 /* remember used playlists so we can thaw them later */
6507 used_playlists.push_back(pl);
6511 framepos_t position = (*r)->region()->position();
6513 if (idx == 0 || position < last_region->position()){
6514 last_region = (*r)->region();
6519 (*r)->region()->trim_front( (position - pull_back_frames));
6520 last_region->trim_end( (position - pull_back_frames + crossfade_len));
6522 last_region = (*r)->region();
6527 while (used_playlists.size() > 0) {
6528 list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
6530 used_playlists.pop_front();
6533 commit_reversible_command ();
6537 Editor::tab_to_transient (bool forward)
6539 AnalysisFeatureList positions;
6541 RegionSelection rs = get_regions_from_selection_and_entered ();
6547 framepos_t pos = _session->audible_frame ();
6549 if (!selection->tracks.empty()) {
6551 /* don't waste time searching for transients in duplicate playlists.
6554 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
6556 for (TrackViewList::iterator t = ts.begin(); t != ts.end(); ++t) {
6558 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*t);
6561 boost::shared_ptr<Track> tr = rtv->track();
6563 boost::shared_ptr<Playlist> pl = tr->playlist ();
6565 framepos_t result = pl->find_next_transient (pos, forward ? 1 : -1);
6568 positions.push_back (result);
6581 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6582 (*r)->region()->get_transients (positions);
6586 TransientDetector::cleanup_transients (positions, _session->frame_rate(), 3.0);
6589 AnalysisFeatureList::iterator x;
6591 for (x = positions.begin(); x != positions.end(); ++x) {
6597 if (x != positions.end ()) {
6598 _session->request_locate (*x);
6602 AnalysisFeatureList::reverse_iterator x;
6604 for (x = positions.rbegin(); x != positions.rend(); ++x) {
6610 if (x != positions.rend ()) {
6611 _session->request_locate (*x);
6617 Editor::playhead_forward_to_grid ()
6623 framepos_t pos = playhead_cursor->current_frame ();
6624 if (pos < max_framepos - 1) {
6626 snap_to_internal (pos, RoundUpAlways, false);
6627 _session->request_locate (pos);
6633 Editor::playhead_backward_to_grid ()
6639 framepos_t pos = playhead_cursor->current_frame ();
6642 snap_to_internal (pos, RoundDownAlways, false);
6643 _session->request_locate (pos);
6648 Editor::set_track_height (Height h)
6650 TrackSelection& ts (selection->tracks);
6652 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
6653 (*x)->set_height_enum (h);
6658 Editor::toggle_tracks_active ()
6660 TrackSelection& ts (selection->tracks);
6662 bool target = false;
6668 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
6669 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*x);
6673 target = !rtv->_route->active();
6676 rtv->_route->set_active (target, this);
6682 Editor::remove_tracks ()
6684 TrackSelection& ts (selection->tracks);
6690 vector<string> choices;
6694 const char* trackstr;
6696 vector<boost::shared_ptr<Route> > routes;
6697 bool special_bus = false;
6699 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
6700 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*x);
6704 if (rtv->is_track()) {
6709 routes.push_back (rtv->_route);
6711 if (rtv->route()->is_master() || rtv->route()->is_monitor()) {
6716 if (special_bus && !Config->get_allow_special_bus_removal()) {
6717 MessageDialog msg (_("That would be bad news ...."),
6721 msg.set_secondary_text (string_compose (_(
6722 "Removing the master or monitor bus is such a bad idea\n\
6723 that %1 is not going to allow it.\n\
6725 If you really want to do this sort of thing\n\
6726 edit your ardour.rc file to set the\n\
6727 \"allow-special-bus-removal\" option to be \"yes\""), PROGRAM_NAME));
6734 if (ntracks + nbusses == 0) {
6738 // XXX should be using gettext plural forms, maybe?
6740 trackstr = _("tracks");
6742 trackstr = _("track");
6746 busstr = _("busses");
6753 prompt = string_compose (_("Do you really want to remove %1 %2 and %3 %4?\n"
6754 "(You may also lose the playlists associated with the %2)\n\n"
6755 "This action cannot be undone, and the session file will be overwritten!"),
6756 ntracks, trackstr, nbusses, busstr);
6758 prompt = string_compose (_("Do you really want to remove %1 %2?\n"
6759 "(You may also lose the playlists associated with the %2)\n\n"
6760 "This action cannot be undone, and the session file will be overwritten!"),
6763 } else if (nbusses) {
6764 prompt = string_compose (_("Do you really want to remove %1 %2?\n\n"
6765 "This action cannot be undone, and the session file will be overwritten"),
6769 choices.push_back (_("No, do nothing."));
6770 if (ntracks + nbusses > 1) {
6771 choices.push_back (_("Yes, remove them."));
6773 choices.push_back (_("Yes, remove it."));
6778 title = string_compose (_("Remove %1"), trackstr);
6780 title = string_compose (_("Remove %1"), busstr);
6783 Choice prompter (title, prompt, choices);
6785 if (prompter.run () != 1) {
6790 Session::StateProtector sp (_session);
6791 DisplaySuspender ds;
6792 for (vector<boost::shared_ptr<Route> >::iterator x = routes.begin(); x != routes.end(); ++x) {
6793 _session->remove_route (*x);
6799 Editor::do_insert_time ()
6801 if (selection->tracks.empty()) {
6805 InsertTimeDialog d (*this);
6806 int response = d.run ();
6808 if (response != RESPONSE_OK) {
6812 if (d.distance() == 0) {
6816 InsertTimeOption opt = d.intersected_region_action ();
6819 get_preferred_edit_position(),
6825 d.move_glued_markers(),
6826 d.move_locked_markers(),
6832 Editor::insert_time (
6833 framepos_t pos, framecnt_t frames, InsertTimeOption opt,
6834 bool all_playlists, bool ignore_music_glue, bool markers_too, bool glued_markers_too, bool locked_markers_too, bool tempo_too
6837 bool commit = false;
6839 if (Config->get_edit_mode() == Lock) {
6843 begin_reversible_command (_("insert time"));
6845 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
6847 for (TrackViewList::iterator x = ts.begin(); x != ts.end(); ++x) {
6851 /* don't operate on any playlist more than once, which could
6852 * happen if "all playlists" is enabled, but there is more
6853 * than 1 track using playlists "from" a given track.
6856 set<boost::shared_ptr<Playlist> > pl;
6858 if (all_playlists) {
6859 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*x);
6861 vector<boost::shared_ptr<Playlist> > all = _session->playlists->playlists_for_track (rtav->track ());
6862 for (vector<boost::shared_ptr<Playlist> >::iterator p = all.begin(); p != all.end(); ++p) {
6867 if ((*x)->playlist ()) {
6868 pl.insert ((*x)->playlist ());
6872 for (set<boost::shared_ptr<Playlist> >::iterator i = pl.begin(); i != pl.end(); ++i) {
6874 (*i)->clear_changes ();
6875 (*i)->clear_owned_changes ();
6877 if (opt == SplitIntersected) {
6881 (*i)->shift (pos, frames, (opt == MoveIntersected), ignore_music_glue);
6883 vector<Command*> cmds;
6885 _session->add_commands (cmds);
6887 _session->add_command (new StatefulDiffCommand (*i));
6892 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*x);
6894 rtav->route ()->shift (pos, frames);
6902 XMLNode& before (_session->locations()->get_state());
6903 Locations::LocationList copy (_session->locations()->list());
6905 for (Locations::LocationList::iterator i = copy.begin(); i != copy.end(); ++i) {
6907 Locations::LocationList::const_iterator tmp;
6909 bool const was_locked = (*i)->locked ();
6910 if (locked_markers_too) {
6914 if ((*i)->position_lock_style() == AudioTime || glued_markers_too) {
6916 if ((*i)->start() >= pos) {
6917 (*i)->set_start ((*i)->start() + frames);
6918 if (!(*i)->is_mark()) {
6919 (*i)->set_end ((*i)->end() + frames);
6932 XMLNode& after (_session->locations()->get_state());
6933 _session->add_command (new MementoCommand<Locations>(*_session->locations(), &before, &after));
6938 _session->tempo_map().insert_time (pos, frames);
6942 commit_reversible_command ();
6947 Editor::fit_selected_tracks ()
6949 if (!selection->tracks.empty()) {
6950 fit_tracks (selection->tracks);
6954 /* no selected tracks - use tracks with selected regions */
6956 if (!selection->regions.empty()) {
6957 for (RegionSelection::iterator r = selection->regions.begin(); r != selection->regions.end(); ++r) {
6958 tvl.push_back (&(*r)->get_time_axis_view ());
6964 } else if (internal_editing()) {
6965 /* no selected tracks, or regions, but in internal edit mode, so follow the mouse and use
6968 if (entered_track) {
6969 tvl.push_back (entered_track);
6978 Editor::fit_tracks (TrackViewList & tracks)
6980 if (tracks.empty()) {
6984 uint32_t child_heights = 0;
6985 int visible_tracks = 0;
6987 for (TrackSelection::iterator t = tracks.begin(); t != tracks.end(); ++t) {
6989 if (!(*t)->marked_for_display()) {
6993 child_heights += (*t)->effective_height() - (*t)->current_height();
6997 /* compute the per-track height from:
6999 total canvas visible height -
7000 height that will be taken by visible children of selected
7001 tracks - height of the ruler/hscroll area
7003 uint32_t h = (uint32_t) floor ((trackviews_height() - child_heights) / visible_tracks);
7004 double first_y_pos = DBL_MAX;
7006 if (h < TimeAxisView::preset_height (HeightSmall)) {
7007 MessageDialog msg (*this, _("There are too many tracks to fit in the current window"));
7008 /* too small to be displayed */
7012 undo_visual_stack.push_back (current_visual_state (true));
7013 no_save_visual = true;
7015 /* build a list of all tracks, including children */
7018 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
7020 TimeAxisView::Children c = (*i)->get_child_list ();
7021 for (TimeAxisView::Children::iterator j = c.begin(); j != c.end(); ++j) {
7022 all.push_back (j->get());
7026 bool prev_was_selected = false;
7027 bool is_selected = tracks.contains (all.front());
7028 bool next_is_selected;
7030 for (TrackViewList::iterator t = all.begin(); t != all.end(); ++t) {
7032 TrackViewList::iterator next;
7037 if (next != all.end()) {
7038 next_is_selected = tracks.contains (*next);
7040 next_is_selected = false;
7043 if ((*t)->marked_for_display ()) {
7045 (*t)->set_height (h);
7046 first_y_pos = std::min ((*t)->y_position (), first_y_pos);
7048 if (prev_was_selected && next_is_selected) {
7049 hide_track_in_display (*t);
7054 prev_was_selected = is_selected;
7055 is_selected = next_is_selected;
7059 set the controls_layout height now, because waiting for its size
7060 request signal handler will cause the vertical adjustment setting to fail
7063 controls_layout.property_height () = _full_canvas_height;
7064 vertical_adjustment.set_value (first_y_pos);
7066 redo_visual_stack.push_back (current_visual_state (true));
7068 visible_tracks_selector.set_text (_("Sel"));
7072 Editor::save_visual_state (uint32_t n)
7074 while (visual_states.size() <= n) {
7075 visual_states.push_back (0);
7078 if (visual_states[n] != 0) {
7079 delete visual_states[n];
7082 visual_states[n] = current_visual_state (true);
7087 Editor::goto_visual_state (uint32_t n)
7089 if (visual_states.size() <= n) {
7093 if (visual_states[n] == 0) {
7097 use_visual_state (*visual_states[n]);
7101 Editor::start_visual_state_op (uint32_t n)
7103 save_visual_state (n);
7105 PopUp* pup = new PopUp (WIN_POS_MOUSE, 1000, true);
7107 snprintf (buf, sizeof (buf), _("Saved view %u"), n+1);
7108 pup->set_text (buf);
7113 Editor::cancel_visual_state_op (uint32_t n)
7115 goto_visual_state (n);
7119 Editor::toggle_region_mute ()
7121 if (_ignore_region_action) {
7125 RegionSelection rs = get_regions_from_selection_and_entered ();
7131 if (rs.size() > 1) {
7132 begin_reversible_command (_("mute regions"));
7134 begin_reversible_command (_("mute region"));
7137 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
7139 (*i)->region()->playlist()->clear_changes ();
7140 (*i)->region()->set_muted (!(*i)->region()->muted ());
7141 _session->add_command (new StatefulDiffCommand ((*i)->region()));
7145 commit_reversible_command ();
7149 Editor::combine_regions ()
7151 /* foreach track with selected regions, take all selected regions
7152 and join them into a new region containing the subregions (as a
7156 typedef set<RouteTimeAxisView*> RTVS;
7159 if (selection->regions.empty()) {
7163 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
7164 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(&(*i)->get_time_axis_view());
7167 tracks.insert (rtv);
7171 begin_reversible_command (_("combine regions"));
7173 vector<RegionView*> new_selection;
7175 for (RTVS::iterator i = tracks.begin(); i != tracks.end(); ++i) {
7178 if ((rv = (*i)->combine_regions ()) != 0) {
7179 new_selection.push_back (rv);
7183 selection->clear_regions ();
7184 for (vector<RegionView*>::iterator i = new_selection.begin(); i != new_selection.end(); ++i) {
7185 selection->add (*i);
7188 commit_reversible_command ();
7192 Editor::uncombine_regions ()
7194 typedef set<RouteTimeAxisView*> RTVS;
7197 if (selection->regions.empty()) {
7201 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
7202 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(&(*i)->get_time_axis_view());
7205 tracks.insert (rtv);
7209 begin_reversible_command (_("uncombine regions"));
7211 for (RTVS::iterator i = tracks.begin(); i != tracks.end(); ++i) {
7212 (*i)->uncombine_regions ();
7215 commit_reversible_command ();
7219 Editor::toggle_midi_input_active (bool flip_others)
7222 boost::shared_ptr<RouteList> rl (new RouteList);
7224 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
7225 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
7231 boost::shared_ptr<MidiTrack> mt = rtav->midi_track();
7234 rl->push_back (rtav->route());
7235 onoff = !mt->input_active();
7239 _session->set_exclusive_input_active (rl, onoff, flip_others);
7246 lock_dialog = new Gtk::Dialog (string_compose (_("%1: Locked"), PROGRAM_NAME), true);
7248 Gtk::Image* padlock = manage (new Gtk::Image (ARDOUR_UI_UTILS::get_icon ("padlock_closed")));
7249 lock_dialog->get_vbox()->pack_start (*padlock);
7251 ArdourButton* b = manage (new ArdourButton);
7252 b->set_name ("lock button");
7253 b->set_text (_("Click to unlock"));
7254 b->signal_clicked.connect (sigc::mem_fun (*this, &Editor::unlock));
7255 lock_dialog->get_vbox()->pack_start (*b);
7257 lock_dialog->get_vbox()->show_all ();
7258 lock_dialog->set_size_request (200, 200);
7262 /* The global menu bar continues to be accessible to applications
7263 with modal dialogs, which means that we need to desensitize
7264 all items in the menu bar. Since those items are really just
7265 proxies for actions, that means disabling all actions.
7267 ActionManager::disable_all_actions ();
7269 lock_dialog->present ();
7275 lock_dialog->hide ();
7278 ActionManager::pop_action_state ();
7281 if (ARDOUR_UI::config()->get_lock_gui_after_seconds()) {
7282 start_lock_event_timing ();
7287 Editor::bring_in_callback (Gtk::Label* label, uint32_t n, uint32_t total, string name)
7289 Gtkmm2ext::UI::instance()->call_slot (invalidator (*this), boost::bind (&Editor::update_bring_in_message, this, label, n, total, name));
7293 Editor::update_bring_in_message (Gtk::Label* label, uint32_t n, uint32_t total, string name)
7295 label->set_text (string_compose ("Copying %1, %2 of %3", name, n, total));
7296 Gtkmm2ext::UI::instance()->flush_pending ();
7300 Editor::bring_all_sources_into_session ()
7307 ArdourDialog w (_("Moving embedded files into session folder"));
7308 w.get_vbox()->pack_start (msg);
7311 /* flush all pending GUI events because we're about to start copying
7315 Gtkmm2ext::UI::instance()->flush_pending ();
7319 _session->bring_all_sources_into_session (boost::bind (&Editor::bring_in_callback, this, &msg, _1, _2, _3));