2 Copyright (C) 2000-2004 Paul Davis
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 /* Note: public Editor methods are documented in public_editor.h */
30 #include "pbd/error.h"
31 #include "pbd/basename.h"
32 #include "pbd/pthread_utils.h"
33 #include "pbd/memento_command.h"
34 #include "pbd/unwind.h"
35 #include "pbd/whitespace.h"
36 #include "pbd/stateful_diff_command.h"
38 #include <gtkmm2ext/utils.h>
39 #include <gtkmm2ext/choice.h>
40 #include <gtkmm2ext/popup.h>
42 #include "ardour/audio_track.h"
43 #include "ardour/audioregion.h"
44 #include "ardour/dB.h"
45 #include "ardour/location.h"
46 #include "ardour/midi_region.h"
47 #include "ardour/midi_track.h"
48 #include "ardour/operations.h"
49 #include "ardour/playlist_factory.h"
50 #include "ardour/quantize.h"
51 #include "ardour/region_factory.h"
52 #include "ardour/reverse.h"
53 #include "ardour/session.h"
54 #include "ardour/session_playlists.h"
55 #include "ardour/strip_silence.h"
56 #include "ardour/transient_detector.h"
58 #include "canvas/canvas.h"
61 #include "ardour_ui.h"
62 #include "audio_region_view.h"
63 #include "audio_streamview.h"
64 #include "audio_time_axis.h"
65 #include "automation_time_axis.h"
66 #include "control_point.h"
70 #include "editor_cursors.h"
71 #include "editor_drag.h"
72 #include "editor_regions.h"
73 #include "editor_routes.h"
74 #include "gui_thread.h"
75 #include "insert_time_dialog.h"
76 #include "interthread_progress_window.h"
78 #include "midi_region_view.h"
79 #include "mouse_cursors.h"
80 #include "normalize_dialog.h"
81 #include "patch_change_dialog.h"
82 #include "quantize_dialog.h"
83 #include "region_gain_line.h"
84 #include "rgb_macros.h"
85 #include "route_time_axis.h"
86 #include "selection.h"
87 #include "selection_templates.h"
88 #include "streamview.h"
89 #include "strip_silence_dialog.h"
90 #include "time_axis_view.h"
91 #include "transpose_dialog.h"
96 using namespace ARDOUR;
99 using namespace Gtkmm2ext;
100 using namespace Editing;
101 using Gtkmm2ext::Keyboard;
103 /***********************************************************************
105 ***********************************************************************/
108 Editor::undo (uint32_t n)
110 if (_drags->active ()) {
120 Editor::redo (uint32_t n)
122 if (_drags->active ()) {
132 Editor::split_regions_at (framepos_t where, RegionSelection& regions)
136 RegionSelection pre_selected_regions = selection->regions;
137 bool working_on_selection = !pre_selected_regions.empty();
139 list<boost::shared_ptr<Playlist> > used_playlists;
140 list<RouteTimeAxisView*> used_trackviews;
142 if (regions.empty()) {
146 begin_reversible_command (_("split"));
148 // if splitting a single region, and snap-to is using
149 // region boundaries, don't pay attention to them
151 if (regions.size() == 1) {
152 switch (_snap_type) {
153 case SnapToRegionStart:
154 case SnapToRegionSync:
155 case SnapToRegionEnd:
164 EditorFreeze(); /* Emit Signal */
167 for (RegionSelection::iterator a = regions.begin(); a != regions.end(); ) {
169 RegionSelection::iterator tmp;
171 /* XXX this test needs to be more complicated, to make sure we really
172 have something to split.
175 if (!(*a)->region()->covers (where)) {
183 boost::shared_ptr<Playlist> pl = (*a)->region()->playlist();
191 /* we haven't seen this playlist before */
193 /* remember used playlists so we can thaw them later */
194 used_playlists.push_back(pl);
196 TimeAxisView& tv = (*a)->get_time_axis_view();
197 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (&tv);
199 used_trackviews.push_back (rtv);
206 pl->clear_changes ();
207 pl->split_region ((*a)->region(), where);
208 _session->add_command (new StatefulDiffCommand (pl));
214 vector<sigc::connection> region_added_connections;
216 for (list<RouteTimeAxisView*>::iterator i = used_trackviews.begin(); i != used_trackviews.end(); ++i) {
217 region_added_connections.push_back ((*i)->view()->RegionViewAdded.connect (sigc::mem_fun(*this, &Editor::collect_new_region_view)));
220 latest_regionviews.clear ();
222 while (used_playlists.size() > 0) {
223 list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
225 used_playlists.pop_front();
228 for (vector<sigc::connection>::iterator c = region_added_connections.begin(); c != region_added_connections.end(); ++c) {
232 commit_reversible_command ();
235 EditorThaw(); /* Emit Signal */
238 //IFF we were working on selected regions, try to reinstate the other region selections that existed before the freeze/thaw.
239 _ignore_follow_edits = true; //a split will change the region selection in mysterious ways; its not practical or wanted to follow this edit
240 if( working_on_selection ) {
241 selection->add ( pre_selected_regions );
242 selection->add (latest_regionviews); //these are the new regions created after the split
244 _ignore_follow_edits = false;
248 /** Move one extreme of the current range selection. If more than one range is selected,
249 * the start of the earliest range or the end of the latest range is moved.
251 * @param move_end true to move the end of the current range selection, false to move
253 * @param next true to move the extreme to the next region boundary, false to move to
257 Editor::move_range_selection_start_or_end_to_region_boundary (bool move_end, bool next)
259 if (selection->time.start() == selection->time.end_frame()) {
263 framepos_t start = selection->time.start ();
264 framepos_t end = selection->time.end_frame ();
266 /* the position of the thing we may move */
267 framepos_t pos = move_end ? end : start;
268 int dir = next ? 1 : -1;
270 /* so we don't find the current region again */
271 if (dir > 0 || pos > 0) {
275 framepos_t const target = get_region_boundary (pos, dir, true, false);
290 begin_reversible_command (_("alter selection"));
291 selection->set_preserving_all_ranges (start, end);
292 commit_reversible_command ();
296 Editor::nudge_forward_release (GdkEventButton* ev)
298 if (ev->state & Keyboard::PrimaryModifier) {
299 nudge_forward (false, true);
301 nudge_forward (false, false);
307 Editor::nudge_backward_release (GdkEventButton* ev)
309 if (ev->state & Keyboard::PrimaryModifier) {
310 nudge_backward (false, true);
312 nudge_backward (false, false);
319 Editor::nudge_forward (bool next, bool force_playhead)
322 framepos_t next_distance;
328 RegionSelection rs = get_regions_from_selection_and_entered ();
330 if (!force_playhead && !rs.empty()) {
332 begin_reversible_command (_("nudge regions forward"));
334 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
335 boost::shared_ptr<Region> r ((*i)->region());
337 distance = get_nudge_distance (r->position(), next_distance);
340 distance = next_distance;
344 r->set_position (r->position() + distance);
345 _session->add_command (new StatefulDiffCommand (r));
348 commit_reversible_command ();
351 } else if (!force_playhead && !selection->markers.empty()) {
355 begin_reversible_command (_("nudge location forward"));
357 for (MarkerSelection::iterator i = selection->markers.begin(); i != selection->markers.end(); ++i) {
359 Location* loc = find_location_from_marker ((*i), is_start);
363 XMLNode& before (loc->get_state());
366 distance = get_nudge_distance (loc->start(), next_distance);
368 distance = next_distance;
370 if (max_framepos - distance > loc->start() + loc->length()) {
371 loc->set_start (loc->start() + distance);
373 loc->set_start (max_framepos - loc->length());
376 distance = get_nudge_distance (loc->end(), next_distance);
378 distance = next_distance;
380 if (max_framepos - distance > loc->end()) {
381 loc->set_end (loc->end() + distance);
383 loc->set_end (max_framepos);
386 XMLNode& after (loc->get_state());
387 _session->add_command (new MementoCommand<Location>(*loc, &before, &after));
391 commit_reversible_command ();
394 distance = get_nudge_distance (playhead_cursor->current_frame (), next_distance);
395 _session->request_locate (playhead_cursor->current_frame () + distance);
400 Editor::nudge_backward (bool next, bool force_playhead)
403 framepos_t next_distance;
409 RegionSelection rs = get_regions_from_selection_and_entered ();
411 if (!force_playhead && !rs.empty()) {
413 begin_reversible_command (_("nudge regions backward"));
415 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
416 boost::shared_ptr<Region> r ((*i)->region());
418 distance = get_nudge_distance (r->position(), next_distance);
421 distance = next_distance;
426 if (r->position() > distance) {
427 r->set_position (r->position() - distance);
431 _session->add_command (new StatefulDiffCommand (r));
434 commit_reversible_command ();
436 } else if (!force_playhead && !selection->markers.empty()) {
440 begin_reversible_command (_("nudge location forward"));
442 for (MarkerSelection::iterator i = selection->markers.begin(); i != selection->markers.end(); ++i) {
444 Location* loc = find_location_from_marker ((*i), is_start);
448 XMLNode& before (loc->get_state());
451 distance = get_nudge_distance (loc->start(), next_distance);
453 distance = next_distance;
455 if (distance < loc->start()) {
456 loc->set_start (loc->start() - distance);
461 distance = get_nudge_distance (loc->end(), next_distance);
464 distance = next_distance;
467 if (distance < loc->end() - loc->length()) {
468 loc->set_end (loc->end() - distance);
470 loc->set_end (loc->length());
474 XMLNode& after (loc->get_state());
475 _session->add_command (new MementoCommand<Location>(*loc, &before, &after));
479 commit_reversible_command ();
483 distance = get_nudge_distance (playhead_cursor->current_frame (), next_distance);
485 if (playhead_cursor->current_frame () > distance) {
486 _session->request_locate (playhead_cursor->current_frame () - distance);
488 _session->goto_start();
494 Editor::nudge_forward_capture_offset ()
496 RegionSelection rs = get_regions_from_selection_and_entered ();
498 if (!_session || rs.empty()) {
502 begin_reversible_command (_("nudge forward"));
504 framepos_t const distance = _session->worst_output_latency();
506 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
507 boost::shared_ptr<Region> r ((*i)->region());
510 r->set_position (r->position() + distance);
511 _session->add_command(new StatefulDiffCommand (r));
514 commit_reversible_command ();
518 Editor::nudge_backward_capture_offset ()
520 RegionSelection rs = get_regions_from_selection_and_entered ();
522 if (!_session || rs.empty()) {
526 begin_reversible_command (_("nudge backward"));
528 framepos_t const distance = _session->worst_output_latency();
530 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
531 boost::shared_ptr<Region> r ((*i)->region());
535 if (r->position() > distance) {
536 r->set_position (r->position() - distance);
540 _session->add_command(new StatefulDiffCommand (r));
543 commit_reversible_command ();
546 struct RegionSelectionPositionSorter {
547 bool operator() (RegionView* a, RegionView* b) {
548 return a->region()->position() < b->region()->position();
553 Editor::sequence_regions ()
556 framepos_t r_end_prev;
564 RegionSelection rs = get_regions_from_selection_and_entered ();
565 rs.sort(RegionSelectionPositionSorter());
569 begin_reversible_command (_("sequence regions"));
570 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
571 boost::shared_ptr<Region> r ((*i)->region());
579 if(r->position_locked())
586 r->set_position(r_end_prev);
589 _session->add_command (new StatefulDiffCommand (r));
591 r_end=r->position() + r->length();
595 commit_reversible_command ();
603 Editor::move_to_start ()
605 _session->goto_start ();
609 Editor::move_to_end ()
612 _session->request_locate (_session->current_end_frame());
616 Editor::build_region_boundary_cache ()
619 vector<RegionPoint> interesting_points;
620 boost::shared_ptr<Region> r;
621 TrackViewList tracks;
624 region_boundary_cache.clear ();
630 switch (_snap_type) {
631 case SnapToRegionStart:
632 interesting_points.push_back (Start);
634 case SnapToRegionEnd:
635 interesting_points.push_back (End);
637 case SnapToRegionSync:
638 interesting_points.push_back (SyncPoint);
640 case SnapToRegionBoundary:
641 interesting_points.push_back (Start);
642 interesting_points.push_back (End);
645 fatal << string_compose (_("build_region_boundary_cache called with snap_type = %1"), _snap_type) << endmsg;
650 TimeAxisView *ontrack = 0;
653 if (!selection->tracks.empty()) {
654 tlist = selection->tracks.filter_to_unique_playlists ();
656 tlist = track_views.filter_to_unique_playlists ();
659 while (pos < _session->current_end_frame() && !at_end) {
662 framepos_t lpos = max_framepos;
664 for (vector<RegionPoint>::iterator p = interesting_points.begin(); p != interesting_points.end(); ++p) {
666 if ((r = find_next_region (pos, *p, 1, tlist, &ontrack)) == 0) {
667 if (*p == interesting_points.back()) {
670 /* move to next point type */
676 rpos = r->first_frame();
680 rpos = r->last_frame();
684 rpos = r->sync_position ();
692 RouteTimeAxisView *rtav;
694 if (ontrack != 0 && (rtav = dynamic_cast<RouteTimeAxisView*>(ontrack)) != 0 ) {
695 if (rtav->track() != 0) {
696 speed = rtav->track()->speed();
700 rpos = track_frame_to_session_frame (rpos, speed);
706 /* prevent duplicates, but we don't use set<> because we want to be able
710 vector<framepos_t>::iterator ri;
712 for (ri = region_boundary_cache.begin(); ri != region_boundary_cache.end(); ++ri) {
718 if (ri == region_boundary_cache.end()) {
719 region_boundary_cache.push_back (rpos);
726 /* finally sort to be sure that the order is correct */
728 sort (region_boundary_cache.begin(), region_boundary_cache.end());
731 boost::shared_ptr<Region>
732 Editor::find_next_region (framepos_t frame, RegionPoint point, int32_t dir, TrackViewList& tracks, TimeAxisView **ontrack)
734 TrackViewList::iterator i;
735 framepos_t closest = max_framepos;
736 boost::shared_ptr<Region> ret;
740 framepos_t track_frame;
741 RouteTimeAxisView *rtav;
743 for (i = tracks.begin(); i != tracks.end(); ++i) {
746 boost::shared_ptr<Region> r;
749 if ( (rtav = dynamic_cast<RouteTimeAxisView*>(*i)) != 0 ) {
750 if (rtav->track()!=0)
751 track_speed = rtav->track()->speed();
754 track_frame = session_frame_to_track_frame(frame, track_speed);
756 if ((r = (*i)->find_next_region (track_frame, point, dir)) == 0) {
762 rpos = r->first_frame ();
766 rpos = r->last_frame ();
770 rpos = r->sync_position ();
774 // rpos is a "track frame", converting it to "_session frame"
775 rpos = track_frame_to_session_frame(rpos, track_speed);
778 distance = rpos - frame;
780 distance = frame - rpos;
783 if (distance < closest) {
795 Editor::find_next_region_boundary (framepos_t pos, int32_t dir, const TrackViewList& tracks)
797 framecnt_t distance = max_framepos;
798 framepos_t current_nearest = -1;
800 for (TrackViewList::const_iterator i = tracks.begin(); i != tracks.end(); ++i) {
801 framepos_t contender;
804 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*i);
810 if ((contender = rtv->find_next_region_boundary (pos, dir)) < 0) {
814 d = ::llabs (pos - contender);
817 current_nearest = contender;
822 return current_nearest;
826 Editor::get_region_boundary (framepos_t pos, int32_t dir, bool with_selection, bool only_onscreen)
831 if (with_selection && Config->get_region_boundaries_from_selected_tracks()) {
833 if (!selection->tracks.empty()) {
835 target = find_next_region_boundary (pos, dir, selection->tracks);
839 if (only_onscreen || Config->get_region_boundaries_from_onscreen_tracks()) {
840 get_onscreen_tracks (tvl);
841 target = find_next_region_boundary (pos, dir, tvl);
843 target = find_next_region_boundary (pos, dir, track_views);
849 if (only_onscreen || Config->get_region_boundaries_from_onscreen_tracks()) {
850 get_onscreen_tracks (tvl);
851 target = find_next_region_boundary (pos, dir, tvl);
853 target = find_next_region_boundary (pos, dir, track_views);
861 Editor::cursor_to_region_boundary (bool with_selection, int32_t dir)
863 framepos_t pos = playhead_cursor->current_frame ();
870 // so we don't find the current region again..
871 if (dir > 0 || pos > 0) {
875 if ((target = get_region_boundary (pos, dir, with_selection, false)) < 0) {
879 _session->request_locate (target);
883 Editor::cursor_to_next_region_boundary (bool with_selection)
885 cursor_to_region_boundary (with_selection, 1);
889 Editor::cursor_to_previous_region_boundary (bool with_selection)
891 cursor_to_region_boundary (with_selection, -1);
895 Editor::cursor_to_region_point (EditorCursor* cursor, RegionPoint point, int32_t dir)
897 boost::shared_ptr<Region> r;
898 framepos_t pos = cursor->current_frame ();
904 TimeAxisView *ontrack = 0;
906 // so we don't find the current region again..
910 if (!selection->tracks.empty()) {
912 r = find_next_region (pos, point, dir, selection->tracks, &ontrack);
914 } else if (clicked_axisview) {
917 t.push_back (clicked_axisview);
919 r = find_next_region (pos, point, dir, t, &ontrack);
923 r = find_next_region (pos, point, dir, track_views, &ontrack);
932 pos = r->first_frame ();
936 pos = r->last_frame ();
940 pos = r->sync_position ();
945 RouteTimeAxisView *rtav;
947 if ( ontrack != 0 && (rtav = dynamic_cast<RouteTimeAxisView*>(ontrack)) != 0 ) {
948 if (rtav->track() != 0) {
949 speed = rtav->track()->speed();
953 pos = track_frame_to_session_frame(pos, speed);
955 if (cursor == playhead_cursor) {
956 _session->request_locate (pos);
958 cursor->set_position (pos);
963 Editor::cursor_to_next_region_point (EditorCursor* cursor, RegionPoint point)
965 cursor_to_region_point (cursor, point, 1);
969 Editor::cursor_to_previous_region_point (EditorCursor* cursor, RegionPoint point)
971 cursor_to_region_point (cursor, point, -1);
975 Editor::cursor_to_selection_start (EditorCursor *cursor)
979 switch (mouse_mode) {
981 if (!selection->regions.empty()) {
982 pos = selection->regions.start();
987 if (!selection->time.empty()) {
988 pos = selection->time.start ();
996 if (cursor == playhead_cursor) {
997 _session->request_locate (pos);
999 cursor->set_position (pos);
1004 Editor::cursor_to_selection_end (EditorCursor *cursor)
1008 switch (mouse_mode) {
1010 if (!selection->regions.empty()) {
1011 pos = selection->regions.end_frame();
1016 if (!selection->time.empty()) {
1017 pos = selection->time.end_frame ();
1025 if (cursor == playhead_cursor) {
1026 _session->request_locate (pos);
1028 cursor->set_position (pos);
1033 Editor::selected_marker_to_region_boundary (bool with_selection, int32_t dir)
1043 if (selection->markers.empty()) {
1047 if (!mouse_frame (mouse, ignored)) {
1051 add_location_mark (mouse);
1054 if ((loc = find_location_from_marker (selection->markers.front(), ignored)) == 0) {
1058 framepos_t pos = loc->start();
1060 // so we don't find the current region again..
1061 if (dir > 0 || pos > 0) {
1065 if ((target = get_region_boundary (pos, dir, with_selection, false)) < 0) {
1069 loc->move_to (target);
1073 Editor::selected_marker_to_next_region_boundary (bool with_selection)
1075 selected_marker_to_region_boundary (with_selection, 1);
1079 Editor::selected_marker_to_previous_region_boundary (bool with_selection)
1081 selected_marker_to_region_boundary (with_selection, -1);
1085 Editor::selected_marker_to_region_point (RegionPoint point, int32_t dir)
1087 boost::shared_ptr<Region> r;
1092 if (!_session || selection->markers.empty()) {
1096 if ((loc = find_location_from_marker (selection->markers.front(), ignored)) == 0) {
1100 TimeAxisView *ontrack = 0;
1104 // so we don't find the current region again..
1108 if (!selection->tracks.empty()) {
1110 r = find_next_region (pos, point, dir, selection->tracks, &ontrack);
1114 r = find_next_region (pos, point, dir, track_views, &ontrack);
1123 pos = r->first_frame ();
1127 pos = r->last_frame ();
1131 pos = r->adjust_to_sync (r->first_frame());
1136 RouteTimeAxisView *rtav;
1138 if (ontrack != 0 && (rtav = dynamic_cast<RouteTimeAxisView*>(ontrack)) != 0) {
1139 if (rtav->track() != 0) {
1140 speed = rtav->track()->speed();
1144 pos = track_frame_to_session_frame(pos, speed);
1150 Editor::selected_marker_to_next_region_point (RegionPoint point)
1152 selected_marker_to_region_point (point, 1);
1156 Editor::selected_marker_to_previous_region_point (RegionPoint point)
1158 selected_marker_to_region_point (point, -1);
1162 Editor::selected_marker_to_selection_start ()
1168 if (!_session || selection->markers.empty()) {
1172 if ((loc = find_location_from_marker (selection->markers.front(), ignored)) == 0) {
1176 switch (mouse_mode) {
1178 if (!selection->regions.empty()) {
1179 pos = selection->regions.start();
1184 if (!selection->time.empty()) {
1185 pos = selection->time.start ();
1197 Editor::selected_marker_to_selection_end ()
1203 if (!_session || selection->markers.empty()) {
1207 if ((loc = find_location_from_marker (selection->markers.front(), ignored)) == 0) {
1211 switch (mouse_mode) {
1213 if (!selection->regions.empty()) {
1214 pos = selection->regions.end_frame();
1219 if (!selection->time.empty()) {
1220 pos = selection->time.end_frame ();
1232 Editor::scroll_playhead (bool forward)
1234 framepos_t pos = playhead_cursor->current_frame ();
1235 framecnt_t delta = (framecnt_t) floor (current_page_samples() / 0.8);
1238 if (pos == max_framepos) {
1242 if (pos < max_framepos - delta) {
1261 _session->request_locate (pos);
1265 Editor::cursor_align (bool playhead_to_edit)
1271 if (playhead_to_edit) {
1273 if (selection->markers.empty()) {
1277 _session->request_locate (selection->markers.front()->position(), _session->transport_rolling());
1280 /* move selected markers to playhead */
1282 for (MarkerSelection::iterator i = selection->markers.begin(); i != selection->markers.end(); ++i) {
1285 Location* loc = find_location_from_marker (*i, ignored);
1287 if (loc->is_mark()) {
1288 loc->set_start (playhead_cursor->current_frame ());
1290 loc->set (playhead_cursor->current_frame (),
1291 playhead_cursor->current_frame () + loc->length());
1298 Editor::scroll_backward (float pages)
1300 framepos_t const one_page = (framepos_t) rint (_visible_canvas_width * samples_per_pixel);
1301 framepos_t const cnt = (framepos_t) floor (pages * one_page);
1304 if (leftmost_frame < cnt) {
1307 frame = leftmost_frame - cnt;
1310 reset_x_origin (frame);
1314 Editor::scroll_forward (float pages)
1316 framepos_t const one_page = (framepos_t) rint (_visible_canvas_width * samples_per_pixel);
1317 framepos_t const cnt = (framepos_t) floor (pages * one_page);
1320 if (max_framepos - cnt < leftmost_frame) {
1321 frame = max_framepos - cnt;
1323 frame = leftmost_frame + cnt;
1326 reset_x_origin (frame);
1330 Editor::scroll_tracks_down ()
1332 double vert_value = vertical_adjustment.get_value() + vertical_adjustment.get_page_size();
1333 if (vert_value > vertical_adjustment.get_upper() - _visible_canvas_height) {
1334 vert_value = vertical_adjustment.get_upper() - _visible_canvas_height;
1337 vertical_adjustment.set_value (vert_value);
1341 Editor::scroll_tracks_up ()
1343 vertical_adjustment.set_value (vertical_adjustment.get_value() - vertical_adjustment.get_page_size());
1347 Editor::scroll_tracks_down_line ()
1349 double vert_value = vertical_adjustment.get_value() + 60;
1351 if (vert_value > vertical_adjustment.get_upper() - _visible_canvas_height) {
1352 vert_value = vertical_adjustment.get_upper() - _visible_canvas_height;
1355 vertical_adjustment.set_value (vert_value);
1359 Editor::scroll_tracks_up_line ()
1361 reset_y_origin (vertical_adjustment.get_value() - 60);
1365 Editor::scroll_down_one_track ()
1367 TrackViewList::reverse_iterator next = track_views.rbegin();
1368 std::pair<TimeAxisView*,double> res;
1369 const double top_of_trackviews = vertical_adjustment.get_value();
1371 for (TrackViewList::reverse_iterator t = track_views.rbegin(); t != track_views.rend(); ++t) {
1372 if ((*t)->hidden()) {
1377 if (next != track_views.rbegin()) {
1378 --next; // moves "next" towards the lower/later tracks since it is a reverse iterator
1381 /* If this is the upper-most visible trackview, we want to display
1382 the one above it (next)
1385 res = (*t)->covers_y_position (top_of_trackviews);
1392 /* move to the track below the first one that covers the */
1394 if (next != track_views.rbegin()) {
1395 ensure_time_axis_view_is_visible (**next, true);
1403 Editor::scroll_up_one_track ()
1405 TrackViewList::iterator prev = track_views.end();
1406 std::pair<TimeAxisView*,double> res;
1407 double top_of_trackviews = vertical_adjustment.get_value ();
1409 for (TrackViewList::iterator t = track_views.begin(); t != track_views.end(); ++t) {
1411 if ((*t)->hidden()) {
1415 /* find the trackview at the top of the trackview group */
1416 res = (*t)->covers_y_position (top_of_trackviews);
1425 if (prev != track_views.end()) {
1426 ensure_time_axis_view_is_visible (**prev, true);
1436 Editor::tav_zoom_step (bool coarser)
1438 DisplaySuspender ds;
1442 if (selection->tracks.empty()) {
1445 ts = &selection->tracks;
1448 for (TrackViewList::iterator i = ts->begin(); i != ts->end(); ++i) {
1449 TimeAxisView *tv = (static_cast<TimeAxisView*>(*i));
1450 tv->step_height (coarser);
1455 Editor::tav_zoom_smooth (bool coarser, bool force_all)
1457 DisplaySuspender ds;
1461 if (selection->tracks.empty() || force_all) {
1464 ts = &selection->tracks;
1467 for (TrackViewList::iterator i = ts->begin(); i != ts->end(); ++i) {
1468 TimeAxisView *tv = (static_cast<TimeAxisView*>(*i));
1469 uint32_t h = tv->current_height ();
1474 if (h >= TimeAxisView::preset_height (HeightSmall)) {
1479 tv->set_height (h + 5);
1486 Editor::temporal_zoom_step (bool coarser)
1488 ENSURE_GUI_THREAD (*this, &Editor::temporal_zoom_step, coarser)
1490 framecnt_t nspp = samples_per_pixel;
1498 temporal_zoom (nspp);
1502 Editor::temporal_zoom (framecnt_t fpp)
1508 framepos_t current_page = current_page_samples();
1509 framepos_t current_leftmost = leftmost_frame;
1510 framepos_t current_rightmost;
1511 framepos_t current_center;
1512 framepos_t new_page_size;
1513 framepos_t half_page_size;
1514 framepos_t leftmost_after_zoom = 0;
1516 bool in_track_canvas;
1520 if (fpp == samples_per_pixel) {
1524 // Imposing an arbitrary limit to zoom out as too much zoom out produces
1525 // segfaults for lack of memory. If somebody decides this is not high enough I
1526 // believe it can be raisen to higher values but some limit must be in place.
1528 // This constant represents 1 day @ 48kHz on a 1600 pixel wide display
1529 // all of which is used for the editor track displays. The whole day
1530 // would be 4147200000 samples, so 2592000 samples per pixel.
1532 nfpp = min (fpp, (framecnt_t) 2592000);
1533 nfpp = max ((framecnt_t) 1, fpp);
1535 new_page_size = (framepos_t) floor (_visible_canvas_width * nfpp);
1536 half_page_size = new_page_size / 2;
1538 switch (zoom_focus) {
1540 leftmost_after_zoom = current_leftmost;
1543 case ZoomFocusRight:
1544 current_rightmost = leftmost_frame + current_page;
1545 if (current_rightmost < new_page_size) {
1546 leftmost_after_zoom = 0;
1548 leftmost_after_zoom = current_rightmost - new_page_size;
1552 case ZoomFocusCenter:
1553 current_center = current_leftmost + (current_page/2);
1554 if (current_center < half_page_size) {
1555 leftmost_after_zoom = 0;
1557 leftmost_after_zoom = current_center - half_page_size;
1561 case ZoomFocusPlayhead:
1562 /* centre playhead */
1563 l = playhead_cursor->current_frame () - (new_page_size * 0.5);
1566 leftmost_after_zoom = 0;
1567 } else if (l > max_framepos) {
1568 leftmost_after_zoom = max_framepos - new_page_size;
1570 leftmost_after_zoom = (framepos_t) l;
1574 case ZoomFocusMouse:
1575 /* try to keep the mouse over the same point in the display */
1577 if (!mouse_frame (where, in_track_canvas)) {
1578 /* use playhead instead */
1579 where = playhead_cursor->current_frame ();
1581 if (where < half_page_size) {
1582 leftmost_after_zoom = 0;
1584 leftmost_after_zoom = where - half_page_size;
1589 l = - ((new_page_size * ((where - current_leftmost)/(double)current_page)) - where);
1592 leftmost_after_zoom = 0;
1593 } else if (l > max_framepos) {
1594 leftmost_after_zoom = max_framepos - new_page_size;
1596 leftmost_after_zoom = (framepos_t) l;
1603 /* try to keep the edit point in the same place */
1604 where = get_preferred_edit_position ();
1608 double l = - ((new_page_size * ((where - current_leftmost)/(double)current_page)) - where);
1611 leftmost_after_zoom = 0;
1612 } else if (l > max_framepos) {
1613 leftmost_after_zoom = max_framepos - new_page_size;
1615 leftmost_after_zoom = (framepos_t) l;
1619 /* edit point not defined */
1626 // leftmost_after_zoom = min (leftmost_after_zoom, _session->current_end_frame());
1628 reposition_and_zoom (leftmost_after_zoom, nfpp);
1632 Editor::temporal_zoom_region (bool both_axes)
1634 framepos_t start = max_framepos;
1636 set<TimeAxisView*> tracks;
1638 RegionSelection rs = get_regions_from_selection_and_entered ();
1644 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
1646 if ((*i)->region()->position() < start) {
1647 start = (*i)->region()->position();
1650 if ((*i)->region()->last_frame() + 1 > end) {
1651 end = (*i)->region()->last_frame() + 1;
1654 tracks.insert (&((*i)->get_time_axis_view()));
1657 /* now comes an "interesting" hack ... make sure we leave a little space
1658 at each end of the editor so that the zoom doesn't fit the region
1659 precisely to the screen.
1662 GdkScreen* screen = gdk_screen_get_default ();
1663 gint pixwidth = gdk_screen_get_width (screen);
1664 gint mmwidth = gdk_screen_get_width_mm (screen);
1665 double pix_per_mm = (double) pixwidth/ (double) mmwidth;
1666 double one_centimeter_in_pixels = pix_per_mm * 10.0;
1668 if ((start == 0 && end == 0) || end < start) {
1672 framepos_t range = end - start;
1673 double new_fpp = (double) range / (double) _visible_canvas_width;
1674 framepos_t extra_samples = (framepos_t) floor (one_centimeter_in_pixels * new_fpp);
1676 if (start > extra_samples) {
1677 start -= extra_samples;
1682 if (max_framepos - extra_samples > end) {
1683 end += extra_samples;
1688 /* if we're zooming on both axes we need to save track heights etc.
1691 undo_visual_stack.push_back (current_visual_state (both_axes));
1693 PBD::Unwinder<bool> nsv (no_save_visual, true);
1695 temporal_zoom_by_frame (start, end);
1698 uint32_t per_track_height = (uint32_t) floor ((_visible_canvas_height - 10.0) / tracks.size());
1700 /* set visible track heights appropriately */
1702 for (set<TimeAxisView*>::iterator t = tracks.begin(); t != tracks.end(); ++t) {
1703 (*t)->set_height (per_track_height);
1706 /* hide irrelevant tracks */
1708 DisplaySuspender ds;
1710 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1711 if (find (tracks.begin(), tracks.end(), (*i)) == tracks.end()) {
1712 hide_track_in_display (*i);
1716 vertical_adjustment.set_value (0.0);
1719 redo_visual_stack.push_back (current_visual_state (both_axes));
1723 Editor::zoom_to_region (bool both_axes)
1725 temporal_zoom_region (both_axes);
1729 Editor::temporal_zoom_selection ()
1731 if (!selection) return;
1733 if (selection->time.empty()) {
1737 framepos_t start = selection->time[clicked_selection].start;
1738 framepos_t end = selection->time[clicked_selection].end;
1740 temporal_zoom_by_frame (start, end);
1744 Editor::temporal_zoom_session ()
1746 ENSURE_GUI_THREAD (*this, &Editor::temporal_zoom_session)
1749 framecnt_t const l = _session->current_end_frame() - _session->current_start_frame();
1750 double s = _session->current_start_frame() - l * 0.01;
1754 framecnt_t const e = _session->current_end_frame() + l * 0.01;
1755 temporal_zoom_by_frame (framecnt_t (s), e);
1760 Editor::temporal_zoom_by_frame (framepos_t start, framepos_t end)
1762 if (!_session) return;
1764 if ((start == 0 && end == 0) || end < start) {
1768 framepos_t range = end - start;
1770 double const new_fpp = (double) range / (double) _visible_canvas_width;
1772 framepos_t new_page = (framepos_t) floor (_visible_canvas_width * new_fpp);
1773 framepos_t middle = (framepos_t) floor ((double) start + ((double) range / 2.0f));
1774 framepos_t new_leftmost = (framepos_t) floor ((double) middle - ((double) new_page / 2.0f));
1776 if (new_leftmost > middle) {
1780 if (new_leftmost < 0) {
1784 reposition_and_zoom (new_leftmost, new_fpp);
1788 Editor::temporal_zoom_to_frame (bool coarser, framepos_t frame)
1794 framecnt_t range_before = frame - leftmost_frame;
1798 if (samples_per_pixel <= 1) {
1801 new_spp = samples_per_pixel + (samples_per_pixel/2);
1803 range_before += range_before/2;
1805 if (samples_per_pixel >= 1) {
1806 new_spp = samples_per_pixel - (samples_per_pixel/2);
1808 /* could bail out here since we cannot zoom any finer,
1809 but leave that to the equality test below
1811 new_spp = samples_per_pixel;
1814 range_before -= range_before/2;
1817 if (new_spp == samples_per_pixel) {
1821 /* zoom focus is automatically taken as @param frame when this
1825 framepos_t new_leftmost = frame - (framepos_t)range_before;
1827 if (new_leftmost > frame) {
1831 if (new_leftmost < 0) {
1835 reposition_and_zoom (new_leftmost, new_spp);
1840 Editor::choose_new_marker_name(string &name) {
1842 if (!Config->get_name_new_markers()) {
1843 /* don't prompt user for a new name */
1847 ArdourPrompter dialog (true);
1849 dialog.set_prompt (_("New Name:"));
1851 dialog.set_title (_("New Location Marker"));
1853 dialog.set_name ("MarkNameWindow");
1854 dialog.set_size_request (250, -1);
1855 dialog.set_position (Gtk::WIN_POS_MOUSE);
1857 dialog.add_button (Stock::OK, RESPONSE_ACCEPT);
1858 dialog.set_initial_text (name);
1862 switch (dialog.run ()) {
1863 case RESPONSE_ACCEPT:
1869 dialog.get_result(name);
1876 Editor::add_location_from_selection ()
1880 if (selection->time.empty()) {
1884 if (_session == 0 || clicked_axisview == 0) {
1888 framepos_t start = selection->time[clicked_selection].start;
1889 framepos_t end = selection->time[clicked_selection].end;
1891 _session->locations()->next_available_name(rangename,"selection");
1892 Location *location = new Location (*_session, start, end, rangename, Location::IsRangeMarker);
1894 _session->begin_reversible_command (_("add marker"));
1895 XMLNode &before = _session->locations()->get_state();
1896 _session->locations()->add (location, true);
1897 XMLNode &after = _session->locations()->get_state();
1898 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
1899 _session->commit_reversible_command ();
1903 Editor::add_location_mark (framepos_t where)
1907 select_new_marker = true;
1909 _session->locations()->next_available_name(markername,"mark");
1910 if (!choose_new_marker_name(markername)) {
1913 Location *location = new Location (*_session, where, where, markername, Location::IsMark);
1914 _session->begin_reversible_command (_("add marker"));
1915 XMLNode &before = _session->locations()->get_state();
1916 _session->locations()->add (location, true);
1917 XMLNode &after = _session->locations()->get_state();
1918 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
1919 _session->commit_reversible_command ();
1923 Editor::add_location_from_playhead_cursor ()
1925 add_location_mark (_session->audible_frame());
1929 Editor::remove_location_at_playhead_cursor ()
1934 _session->begin_reversible_command (_("remove marker"));
1935 XMLNode &before = _session->locations()->get_state();
1936 bool removed = false;
1938 //find location(s) at this time
1939 Locations::LocationList locs;
1940 _session->locations()->find_all_between (_session->audible_frame(), _session->audible_frame()+1, locs, Location::Flags(0));
1941 for (Locations::LocationList::iterator i = locs.begin(); i != locs.end(); ++i) {
1942 if ((*i)->is_mark()) {
1943 _session->locations()->remove (*i);
1950 XMLNode &after = _session->locations()->get_state();
1951 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
1952 _session->commit_reversible_command ();
1957 /** Add a range marker around each selected region */
1959 Editor::add_locations_from_region ()
1961 RegionSelection rs = get_regions_from_selection_and_entered ();
1967 _session->begin_reversible_command (selection->regions.size () > 1 ? _("add markers") : _("add marker"));
1968 XMLNode &before = _session->locations()->get_state();
1970 for (RegionSelection::iterator i = rs.begin (); i != rs.end (); ++i) {
1972 boost::shared_ptr<Region> region = (*i)->region ();
1974 Location *location = new Location (*_session, region->position(), region->last_frame(), region->name(), Location::IsRangeMarker);
1976 _session->locations()->add (location, true);
1979 XMLNode &after = _session->locations()->get_state();
1980 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
1981 _session->commit_reversible_command ();
1984 /** Add a single range marker around all selected regions */
1986 Editor::add_location_from_region ()
1988 RegionSelection rs = get_regions_from_selection_and_entered ();
1994 _session->begin_reversible_command (_("add marker"));
1995 XMLNode &before = _session->locations()->get_state();
1999 if (rs.size() > 1) {
2000 _session->locations()->next_available_name(markername, "regions");
2002 RegionView* rv = *(rs.begin());
2003 boost::shared_ptr<Region> region = rv->region();
2004 markername = region->name();
2007 if (!choose_new_marker_name(markername)) {
2011 // single range spanning all selected
2012 Location *location = new Location (*_session, selection->regions.start(), selection->regions.end_frame(), markername, Location::IsRangeMarker);
2013 _session->locations()->add (location, true);
2015 XMLNode &after = _session->locations()->get_state();
2016 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2017 _session->commit_reversible_command ();
2023 Editor::jump_forward_to_mark ()
2029 framepos_t pos = _session->locations()->first_mark_after (playhead_cursor->current_frame());
2035 _session->request_locate (pos, _session->transport_rolling());
2039 Editor::jump_backward_to_mark ()
2045 framepos_t pos = _session->locations()->first_mark_before (playhead_cursor->current_frame());
2051 _session->request_locate (pos, _session->transport_rolling());
2057 framepos_t const pos = _session->audible_frame ();
2060 _session->locations()->next_available_name (markername, "mark");
2062 if (!choose_new_marker_name (markername)) {
2066 _session->locations()->add (new Location (*_session, pos, 0, markername, Location::IsMark), true);
2070 Editor::clear_markers ()
2073 _session->begin_reversible_command (_("clear markers"));
2074 XMLNode &before = _session->locations()->get_state();
2075 _session->locations()->clear_markers ();
2076 XMLNode &after = _session->locations()->get_state();
2077 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2078 _session->commit_reversible_command ();
2083 Editor::clear_ranges ()
2086 _session->begin_reversible_command (_("clear ranges"));
2087 XMLNode &before = _session->locations()->get_state();
2089 Location * looploc = _session->locations()->auto_loop_location();
2090 Location * punchloc = _session->locations()->auto_punch_location();
2091 Location * sessionloc = _session->locations()->session_range_location();
2093 _session->locations()->clear_ranges ();
2095 if (looploc) _session->locations()->add (looploc);
2096 if (punchloc) _session->locations()->add (punchloc);
2097 if (sessionloc) _session->locations()->add (sessionloc);
2099 XMLNode &after = _session->locations()->get_state();
2100 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2101 _session->commit_reversible_command ();
2106 Editor::clear_locations ()
2108 _session->begin_reversible_command (_("clear locations"));
2109 XMLNode &before = _session->locations()->get_state();
2110 _session->locations()->clear ();
2111 XMLNode &after = _session->locations()->get_state();
2112 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2113 _session->commit_reversible_command ();
2114 _session->locations()->clear ();
2118 Editor::unhide_markers ()
2120 for (LocationMarkerMap::iterator i = location_markers.begin(); i != location_markers.end(); ++i) {
2121 Location *l = (*i).first;
2122 if (l->is_hidden() && l->is_mark()) {
2123 l->set_hidden(false, this);
2129 Editor::unhide_ranges ()
2131 for (LocationMarkerMap::iterator i = location_markers.begin(); i != location_markers.end(); ++i) {
2132 Location *l = (*i).first;
2133 if (l->is_hidden() && l->is_range_marker()) {
2134 l->set_hidden(false, this);
2139 /* INSERT/REPLACE */
2142 Editor::insert_region_list_selection (float times)
2144 RouteTimeAxisView *tv = 0;
2145 boost::shared_ptr<Playlist> playlist;
2147 if (clicked_routeview != 0) {
2148 tv = clicked_routeview;
2149 } else if (!selection->tracks.empty()) {
2150 if ((tv = dynamic_cast<RouteTimeAxisView*>(selection->tracks.front())) == 0) {
2153 } else if (entered_track != 0) {
2154 if ((tv = dynamic_cast<RouteTimeAxisView*>(entered_track)) == 0) {
2161 if ((playlist = tv->playlist()) == 0) {
2165 boost::shared_ptr<Region> region = _regions->get_single_selection ();
2170 begin_reversible_command (_("insert region"));
2171 playlist->clear_changes ();
2172 playlist->add_region ((RegionFactory::create (region, true)), get_preferred_edit_position(), times);
2173 if (Config->get_edit_mode() == Ripple)
2174 playlist->ripple (get_preferred_edit_position(), region->length() * times, boost::shared_ptr<Region>());
2176 _session->add_command(new StatefulDiffCommand (playlist));
2177 commit_reversible_command ();
2180 /* BUILT-IN EFFECTS */
2183 Editor::reverse_selection ()
2188 /* GAIN ENVELOPE EDITING */
2191 Editor::edit_envelope ()
2198 Editor::transition_to_rolling (bool fwd)
2204 if (_session->config.get_external_sync()) {
2205 switch (Config->get_sync_source()) {
2209 /* transport controlled by the master */
2214 if (_session->is_auditioning()) {
2215 _session->cancel_audition ();
2219 _session->request_transport_speed (fwd ? 1.0f : -1.0f);
2223 Editor::play_from_start ()
2225 _session->request_locate (_session->current_start_frame(), true);
2229 Editor::play_from_edit_point ()
2231 _session->request_locate (get_preferred_edit_position(), true);
2235 Editor::play_from_edit_point_and_return ()
2237 framepos_t start_frame;
2238 framepos_t return_frame;
2240 start_frame = get_preferred_edit_position (true);
2242 if (_session->transport_rolling()) {
2243 _session->request_locate (start_frame, false);
2247 /* don't reset the return frame if its already set */
2249 if ((return_frame = _session->requested_return_frame()) < 0) {
2250 return_frame = _session->audible_frame();
2253 if (start_frame >= 0) {
2254 _session->request_roll_at_and_return (start_frame, return_frame);
2259 Editor::play_selection ()
2261 if (selection->time.empty()) {
2265 _session->request_play_range (&selection->time, true);
2269 Editor::get_preroll ()
2271 return 1.0 /*Config->get_edit_preroll_seconds()*/ * _session->frame_rate();
2276 Editor::maybe_locate_with_edit_preroll ( framepos_t location )
2278 if ( _session->transport_rolling() || !Config->get_follow_edits() || _ignore_follow_edits )
2281 location -= get_preroll();
2283 //don't try to locate before the beginning of time
2287 //if follow_playhead is on, keep the playhead on the screen
2288 if ( _follow_playhead )
2289 if ( location < leftmost_frame )
2290 location = leftmost_frame;
2292 _session->request_locate( location );
2296 Editor::play_with_preroll ()
2298 if (selection->time.empty()) {
2301 framepos_t preroll = get_preroll();
2303 framepos_t start = 0;
2304 if (selection->time[clicked_selection].start > preroll)
2305 start = selection->time[clicked_selection].start - preroll;
2307 framepos_t end = selection->time[clicked_selection].end + preroll;
2309 AudioRange ar (start, end, 0);
2310 list<AudioRange> lar;
2313 _session->request_play_range (&lar, true);
2318 Editor::play_location (Location& location)
2320 if (location.start() <= location.end()) {
2324 _session->request_bounded_roll (location.start(), location.end());
2328 Editor::loop_location (Location& location)
2330 if (location.start() <= location.end()) {
2336 if ((tll = transport_loop_location()) != 0) {
2337 tll->set (location.start(), location.end());
2339 // enable looping, reposition and start rolling
2340 _session->request_play_loop (true);
2341 _session->request_locate (tll->start(), true);
2346 Editor::do_layer_operation (LayerOperation op)
2348 if (selection->regions.empty ()) {
2352 bool const multiple = selection->regions.size() > 1;
2356 begin_reversible_command (_("raise regions"));
2358 begin_reversible_command (_("raise region"));
2364 begin_reversible_command (_("raise regions to top"));
2366 begin_reversible_command (_("raise region to top"));
2372 begin_reversible_command (_("lower regions"));
2374 begin_reversible_command (_("lower region"));
2380 begin_reversible_command (_("lower regions to bottom"));
2382 begin_reversible_command (_("lower region"));
2387 set<boost::shared_ptr<Playlist> > playlists = selection->regions.playlists ();
2388 for (set<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
2389 (*i)->clear_owned_changes ();
2392 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
2393 boost::shared_ptr<Region> r = (*i)->region ();
2405 r->lower_to_bottom ();
2409 for (set<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
2410 vector<Command*> cmds;
2412 _session->add_commands (cmds);
2415 commit_reversible_command ();
2419 Editor::raise_region ()
2421 do_layer_operation (Raise);
2425 Editor::raise_region_to_top ()
2427 do_layer_operation (RaiseToTop);
2431 Editor::lower_region ()
2433 do_layer_operation (Lower);
2437 Editor::lower_region_to_bottom ()
2439 do_layer_operation (LowerToBottom);
2442 /** Show the region editor for the selected regions */
2444 Editor::show_region_properties ()
2446 selection->foreach_regionview (&RegionView::show_region_editor);
2449 /** Show the midi list editor for the selected MIDI regions */
2451 Editor::show_midi_list_editor ()
2453 selection->foreach_midi_regionview (&MidiRegionView::show_list_editor);
2457 Editor::rename_region ()
2459 RegionSelection rs = get_regions_from_selection_and_entered ();
2465 ArdourDialog d (*this, _("Rename Region"), true, false);
2467 Label label (_("New name:"));
2470 hbox.set_spacing (6);
2471 hbox.pack_start (label, false, false);
2472 hbox.pack_start (entry, true, true);
2474 d.get_vbox()->set_border_width (12);
2475 d.get_vbox()->pack_start (hbox, false, false);
2477 d.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
2478 d.add_button(Gtk::Stock::OK, Gtk::RESPONSE_OK);
2480 d.set_size_request (300, -1);
2482 entry.set_text (rs.front()->region()->name());
2483 entry.select_region (0, -1);
2485 entry.signal_activate().connect (sigc::bind (sigc::mem_fun (d, &Dialog::response), RESPONSE_OK));
2491 int const ret = d.run();
2495 if (ret != RESPONSE_OK) {
2499 std::string str = entry.get_text();
2500 strip_whitespace_edges (str);
2502 rs.front()->region()->set_name (str);
2503 _regions->redisplay ();
2508 Editor::audition_playlist_region_via_route (boost::shared_ptr<Region> region, Route& route)
2510 if (_session->is_auditioning()) {
2511 _session->cancel_audition ();
2514 // note: some potential for creativity here, because region doesn't
2515 // have to belong to the playlist that Route is handling
2517 // bool was_soloed = route.soloed();
2519 route.set_solo (true, this);
2521 _session->request_bounded_roll (region->position(), region->position() + region->length());
2523 /* XXX how to unset the solo state ? */
2526 /** Start an audition of the first selected region */
2528 Editor::play_edit_range ()
2530 framepos_t start, end;
2532 if (get_edit_op_range (start, end)) {
2533 _session->request_bounded_roll (start, end);
2538 Editor::play_selected_region ()
2540 framepos_t start = max_framepos;
2543 RegionSelection rs = get_regions_from_selection_and_entered ();
2549 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
2550 if ((*i)->region()->position() < start) {
2551 start = (*i)->region()->position();
2553 if ((*i)->region()->last_frame() + 1 > end) {
2554 end = (*i)->region()->last_frame() + 1;
2558 _session->request_bounded_roll (start, end);
2562 Editor::audition_playlist_region_standalone (boost::shared_ptr<Region> region)
2564 _session->audition_region (region);
2568 Editor::region_from_selection ()
2570 if (clicked_axisview == 0) {
2574 if (selection->time.empty()) {
2578 framepos_t start = selection->time[clicked_selection].start;
2579 framepos_t end = selection->time[clicked_selection].end;
2581 TrackViewList tracks = get_tracks_for_range_action ();
2583 framepos_t selection_cnt = end - start + 1;
2585 for (TrackSelection::iterator i = tracks.begin(); i != tracks.end(); ++i) {
2586 boost::shared_ptr<Region> current;
2587 boost::shared_ptr<Playlist> pl;
2588 framepos_t internal_start;
2591 if ((pl = (*i)->playlist()) == 0) {
2595 if ((current = pl->top_region_at (start)) == 0) {
2599 internal_start = start - current->position();
2600 RegionFactory::region_name (new_name, current->name(), true);
2604 plist.add (ARDOUR::Properties::start, current->start() + internal_start);
2605 plist.add (ARDOUR::Properties::length, selection_cnt);
2606 plist.add (ARDOUR::Properties::name, new_name);
2607 plist.add (ARDOUR::Properties::layer, 0);
2609 boost::shared_ptr<Region> region (RegionFactory::create (current, plist));
2614 Editor::create_region_from_selection (vector<boost::shared_ptr<Region> >& new_regions)
2616 if (selection->time.empty() || selection->tracks.empty()) {
2620 framepos_t start = selection->time[clicked_selection].start;
2621 framepos_t end = selection->time[clicked_selection].end;
2623 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
2624 sort_track_selection (ts);
2626 for (TrackSelection::iterator i = ts.begin(); i != ts.end(); ++i) {
2627 boost::shared_ptr<Region> current;
2628 boost::shared_ptr<Playlist> playlist;
2629 framepos_t internal_start;
2632 if ((playlist = (*i)->playlist()) == 0) {
2636 if ((current = playlist->top_region_at(start)) == 0) {
2640 internal_start = start - current->position();
2641 RegionFactory::region_name (new_name, current->name(), true);
2645 plist.add (ARDOUR::Properties::start, current->start() + internal_start);
2646 plist.add (ARDOUR::Properties::length, end - start + 1);
2647 plist.add (ARDOUR::Properties::name, new_name);
2649 new_regions.push_back (RegionFactory::create (current, plist));
2654 Editor::split_multichannel_region ()
2656 RegionSelection rs = get_regions_from_selection_and_entered ();
2662 vector< boost::shared_ptr<Region> > v;
2664 for (list<RegionView*>::iterator x = rs.begin(); x != rs.end(); ++x) {
2665 (*x)->region()->separate_by_channel (*_session, v);
2670 Editor::new_region_from_selection ()
2672 region_from_selection ();
2673 cancel_selection ();
2677 add_if_covered (RegionView* rv, const AudioRange* ar, RegionSelection* rs)
2679 switch (rv->region()->coverage (ar->start, ar->end - 1)) {
2680 case Evoral::OverlapNone:
2688 * - selected tracks, or if there are none...
2689 * - tracks containing selected regions, or if there are none...
2694 Editor::get_tracks_for_range_action () const
2698 if (selection->tracks.empty()) {
2700 /* use tracks with selected regions */
2702 RegionSelection rs = selection->regions;
2704 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
2705 TimeAxisView* tv = &(*i)->get_time_axis_view();
2707 if (!t.contains (tv)) {
2713 /* no regions and no tracks: use all tracks */
2719 t = selection->tracks;
2722 return t.filter_to_unique_playlists();
2726 Editor::separate_regions_between (const TimeSelection& ts)
2728 bool in_command = false;
2729 boost::shared_ptr<Playlist> playlist;
2730 RegionSelection new_selection;
2732 TrackViewList tmptracks = get_tracks_for_range_action ();
2733 sort_track_selection (tmptracks);
2735 for (TrackSelection::iterator i = tmptracks.begin(); i != tmptracks.end(); ++i) {
2737 RouteTimeAxisView* rtv;
2739 if ((rtv = dynamic_cast<RouteTimeAxisView*> ((*i))) != 0) {
2741 if (rtv->is_track()) {
2743 /* no edits to destructive tracks */
2745 if (rtv->track()->destructive()) {
2749 if ((playlist = rtv->playlist()) != 0) {
2751 playlist->clear_changes ();
2753 /* XXX need to consider musical time selections here at some point */
2755 double speed = rtv->track()->speed();
2758 for (list<AudioRange>::const_iterator t = ts.begin(); t != ts.end(); ++t) {
2760 sigc::connection c = rtv->view()->RegionViewAdded.connect (
2761 sigc::mem_fun(*this, &Editor::collect_new_region_view));
2763 latest_regionviews.clear ();
2765 playlist->partition ((framepos_t)((*t).start * speed),
2766 (framepos_t)((*t).end * speed), false);
2770 if (!latest_regionviews.empty()) {
2772 rtv->view()->foreach_regionview (sigc::bind (
2773 sigc::ptr_fun (add_if_covered),
2774 &(*t), &new_selection));
2777 begin_reversible_command (_("separate"));
2781 /* pick up changes to existing regions */
2783 vector<Command*> cmds;
2784 playlist->rdiff (cmds);
2785 _session->add_commands (cmds);
2787 /* pick up changes to the playlist itself (adds/removes)
2790 _session->add_command(new StatefulDiffCommand (playlist));
2799 // selection->set (new_selection);
2801 commit_reversible_command ();
2805 struct PlaylistState {
2806 boost::shared_ptr<Playlist> playlist;
2810 /** Take tracks from get_tracks_for_range_action and cut any regions
2811 * on those tracks so that the tracks are empty over the time
2815 Editor::separate_region_from_selection ()
2817 /* preferentially use *all* ranges in the time selection if we're in range mode
2818 to allow discontiguous operation, since get_edit_op_range() currently
2819 returns a single range.
2822 if (!selection->time.empty()) {
2824 separate_regions_between (selection->time);
2831 if (get_edit_op_range (start, end)) {
2833 AudioRange ar (start, end, 1);
2837 separate_regions_between (ts);
2843 Editor::separate_region_from_punch ()
2845 Location* loc = _session->locations()->auto_punch_location();
2847 separate_regions_using_location (*loc);
2852 Editor::separate_region_from_loop ()
2854 Location* loc = _session->locations()->auto_loop_location();
2856 separate_regions_using_location (*loc);
2861 Editor::separate_regions_using_location (Location& loc)
2863 if (loc.is_mark()) {
2867 AudioRange ar (loc.start(), loc.end(), 1);
2872 separate_regions_between (ts);
2875 /** Separate regions under the selected region */
2877 Editor::separate_under_selected_regions ()
2879 vector<PlaylistState> playlists;
2883 rs = get_regions_from_selection_and_entered();
2885 if (!_session || rs.empty()) {
2889 begin_reversible_command (_("separate region under"));
2891 list<boost::shared_ptr<Region> > regions_to_remove;
2893 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
2894 // we can't just remove the region(s) in this loop because
2895 // this removes them from the RegionSelection, and they thus
2896 // disappear from underneath the iterator, and the ++i above
2897 // SEGVs in a puzzling fashion.
2899 // so, first iterate over the regions to be removed from rs and
2900 // add them to the regions_to_remove list, and then
2901 // iterate over the list to actually remove them.
2903 regions_to_remove.push_back ((*i)->region());
2906 for (list<boost::shared_ptr<Region> >::iterator rl = regions_to_remove.begin(); rl != regions_to_remove.end(); ++rl) {
2908 boost::shared_ptr<Playlist> playlist = (*rl)->playlist();
2911 // is this check necessary?
2915 vector<PlaylistState>::iterator i;
2917 //only take state if this is a new playlist.
2918 for (i = playlists.begin(); i != playlists.end(); ++i) {
2919 if ((*i).playlist == playlist) {
2924 if (i == playlists.end()) {
2926 PlaylistState before;
2927 before.playlist = playlist;
2928 before.before = &playlist->get_state();
2930 playlist->freeze ();
2931 playlists.push_back(before);
2934 //Partition on the region bounds
2935 playlist->partition ((*rl)->first_frame() - 1, (*rl)->last_frame() + 1, true);
2937 //Re-add region that was just removed due to the partition operation
2938 playlist->add_region( (*rl), (*rl)->first_frame() );
2941 vector<PlaylistState>::iterator pl;
2943 for (pl = playlists.begin(); pl != playlists.end(); ++pl) {
2944 (*pl).playlist->thaw ();
2945 _session->add_command(new MementoCommand<Playlist>(*(*pl).playlist, (*pl).before, &(*pl).playlist->get_state()));
2948 commit_reversible_command ();
2952 Editor::crop_region_to_selection ()
2954 if (!selection->time.empty()) {
2956 crop_region_to (selection->time.start(), selection->time.end_frame());
2963 if (get_edit_op_range (start, end)) {
2964 crop_region_to (start, end);
2971 Editor::crop_region_to (framepos_t start, framepos_t end)
2973 vector<boost::shared_ptr<Playlist> > playlists;
2974 boost::shared_ptr<Playlist> playlist;
2977 if (selection->tracks.empty()) {
2978 ts = track_views.filter_to_unique_playlists();
2980 ts = selection->tracks.filter_to_unique_playlists ();
2983 sort_track_selection (ts);
2985 for (TrackSelection::iterator i = ts.begin(); i != ts.end(); ++i) {
2987 RouteTimeAxisView* rtv;
2989 if ((rtv = dynamic_cast<RouteTimeAxisView*> ((*i))) != 0) {
2991 boost::shared_ptr<Track> t = rtv->track();
2993 if (t != 0 && ! t->destructive()) {
2995 if ((playlist = rtv->playlist()) != 0) {
2996 playlists.push_back (playlist);
3002 if (playlists.empty()) {
3006 framepos_t the_start;
3010 begin_reversible_command (_("trim to selection"));
3012 for (vector<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
3014 boost::shared_ptr<Region> region;
3018 if ((region = (*i)->top_region_at(the_start)) == 0) {
3022 /* now adjust lengths to that we do the right thing
3023 if the selection extends beyond the region
3026 the_start = max (the_start, (framepos_t) region->position());
3027 if (max_framepos - the_start < region->length()) {
3028 the_end = the_start + region->length() - 1;
3030 the_end = max_framepos;
3032 the_end = min (end, the_end);
3033 cnt = the_end - the_start + 1;
3035 region->clear_changes ();
3036 region->trim_to (the_start, cnt);
3037 _session->add_command (new StatefulDiffCommand (region));
3040 commit_reversible_command ();
3044 Editor::region_fill_track ()
3046 RegionSelection rs = get_regions_from_selection_and_entered ();
3048 if (!_session || rs.empty()) {
3052 framepos_t const end = _session->current_end_frame ();
3054 begin_reversible_command (Operations::region_fill);
3056 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3058 boost::shared_ptr<Region> region ((*i)->region());
3060 boost::shared_ptr<Playlist> pl = region->playlist();
3062 if (end <= region->last_frame()) {
3066 double times = (double) (end - region->last_frame()) / (double) region->length();
3072 pl->clear_changes ();
3073 pl->add_region (RegionFactory::create (region, true), region->last_frame(), times);
3074 _session->add_command (new StatefulDiffCommand (pl));
3077 commit_reversible_command ();
3081 Editor::region_fill_selection ()
3083 if (clicked_routeview == 0 || !clicked_routeview->is_audio_track()) {
3087 if (selection->time.empty()) {
3091 boost::shared_ptr<Region> region = _regions->get_single_selection ();
3096 framepos_t start = selection->time[clicked_selection].start;
3097 framepos_t end = selection->time[clicked_selection].end;
3099 boost::shared_ptr<Playlist> playlist;
3101 if (selection->tracks.empty()) {
3105 framepos_t selection_length = end - start;
3106 float times = (float)selection_length / region->length();
3108 begin_reversible_command (Operations::fill_selection);
3110 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
3112 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
3114 if ((playlist = (*i)->playlist()) == 0) {
3118 playlist->clear_changes ();
3119 playlist->add_region (RegionFactory::create (region, true), start, times);
3120 _session->add_command (new StatefulDiffCommand (playlist));
3123 commit_reversible_command ();
3127 Editor::set_region_sync_position ()
3129 set_sync_point (get_preferred_edit_position (), get_regions_from_selection_and_edit_point ());
3133 Editor::set_sync_point (framepos_t where, const RegionSelection& rs)
3135 bool in_command = false;
3137 for (RegionSelection::const_iterator r = rs.begin(); r != rs.end(); ++r) {
3139 if (!(*r)->region()->covers (where)) {
3143 boost::shared_ptr<Region> region ((*r)->region());
3146 begin_reversible_command (_("set sync point"));
3150 region->clear_changes ();
3151 region->set_sync_position (where);
3152 _session->add_command(new StatefulDiffCommand (region));
3156 commit_reversible_command ();
3160 /** Remove the sync positions of the selection */
3162 Editor::remove_region_sync ()
3164 RegionSelection rs = get_regions_from_selection_and_entered ();
3170 begin_reversible_command (_("remove region sync"));
3172 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3174 (*i)->region()->clear_changes ();
3175 (*i)->region()->clear_sync_position ();
3176 _session->add_command(new StatefulDiffCommand ((*i)->region()));
3179 commit_reversible_command ();
3183 Editor::naturalize_region ()
3185 RegionSelection rs = get_regions_from_selection_and_entered ();
3191 if (rs.size() > 1) {
3192 begin_reversible_command (_("move regions to original position"));
3194 begin_reversible_command (_("move region to original position"));
3197 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3198 (*i)->region()->clear_changes ();
3199 (*i)->region()->move_to_natural_position ();
3200 _session->add_command (new StatefulDiffCommand ((*i)->region()));
3203 commit_reversible_command ();
3207 Editor::align_regions (RegionPoint what)
3209 RegionSelection const rs = get_regions_from_selection_and_edit_point ();
3215 begin_reversible_command (_("align selection"));
3217 framepos_t const position = get_preferred_edit_position ();
3219 for (RegionSelection::const_iterator i = rs.begin(); i != rs.end(); ++i) {
3220 align_region_internal ((*i)->region(), what, position);
3223 commit_reversible_command ();
3226 struct RegionSortByTime {
3227 bool operator() (const RegionView* a, const RegionView* b) {
3228 return a->region()->position() < b->region()->position();
3233 Editor::align_regions_relative (RegionPoint point)
3235 RegionSelection const rs = get_regions_from_selection_and_edit_point ();
3241 framepos_t const position = get_preferred_edit_position ();
3243 framepos_t distance = 0;
3247 list<RegionView*> sorted;
3248 rs.by_position (sorted);
3250 boost::shared_ptr<Region> r ((*sorted.begin())->region());
3255 if (position > r->position()) {
3256 distance = position - r->position();
3258 distance = r->position() - position;
3264 if (position > r->last_frame()) {
3265 distance = position - r->last_frame();
3266 pos = r->position() + distance;
3268 distance = r->last_frame() - position;
3269 pos = r->position() - distance;
3275 pos = r->adjust_to_sync (position);
3276 if (pos > r->position()) {
3277 distance = pos - r->position();
3279 distance = r->position() - pos;
3285 if (pos == r->position()) {
3289 begin_reversible_command (_("align selection (relative)"));
3291 /* move first one specially */
3293 r->clear_changes ();
3294 r->set_position (pos);
3295 _session->add_command(new StatefulDiffCommand (r));
3297 /* move rest by the same amount */
3301 for (list<RegionView*>::iterator i = sorted.begin(); i != sorted.end(); ++i) {
3303 boost::shared_ptr<Region> region ((*i)->region());
3305 region->clear_changes ();
3308 region->set_position (region->position() + distance);
3310 region->set_position (region->position() - distance);
3313 _session->add_command(new StatefulDiffCommand (region));
3317 commit_reversible_command ();
3321 Editor::align_region (boost::shared_ptr<Region> region, RegionPoint point, framepos_t position)
3323 begin_reversible_command (_("align region"));
3324 align_region_internal (region, point, position);
3325 commit_reversible_command ();
3329 Editor::align_region_internal (boost::shared_ptr<Region> region, RegionPoint point, framepos_t position)
3331 region->clear_changes ();
3335 region->set_position (region->adjust_to_sync (position));
3339 if (position > region->length()) {
3340 region->set_position (position - region->length());
3345 region->set_position (position);
3349 _session->add_command(new StatefulDiffCommand (region));
3353 Editor::trim_region_front ()
3359 Editor::trim_region_back ()
3361 trim_region (false);
3365 Editor::trim_region (bool front)
3367 framepos_t where = get_preferred_edit_position();
3368 RegionSelection rs = get_regions_from_selection_and_edit_point ();
3374 begin_reversible_command (front ? _("trim front") : _("trim back"));
3376 for (list<RegionView*>::const_iterator i = rs.by_layer().begin(); i != rs.by_layer().end(); ++i) {
3377 if (!(*i)->region()->locked()) {
3379 (*i)->region()->clear_changes ();
3382 (*i)->region()->trim_front (where);
3383 maybe_locate_with_edit_preroll ( where );
3385 (*i)->region()->trim_end (where);
3386 maybe_locate_with_edit_preroll ( where );
3389 _session->add_command (new StatefulDiffCommand ((*i)->region()));
3393 commit_reversible_command ();
3396 /** Trim the end of the selected regions to the position of the edit cursor */
3398 Editor::trim_region_to_loop ()
3400 Location* loc = _session->locations()->auto_loop_location();
3404 trim_region_to_location (*loc, _("trim to loop"));
3408 Editor::trim_region_to_punch ()
3410 Location* loc = _session->locations()->auto_punch_location();
3414 trim_region_to_location (*loc, _("trim to punch"));
3418 Editor::trim_region_to_location (const Location& loc, const char* str)
3420 RegionSelection rs = get_regions_from_selection_and_entered ();
3422 begin_reversible_command (str);
3424 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
3425 RegionView* rv = (*x);
3427 /* require region to span proposed trim */
3428 switch (rv->region()->coverage (loc.start(), loc.end())) {
3429 case Evoral::OverlapInternal:
3435 RouteTimeAxisView* tav = dynamic_cast<RouteTimeAxisView*> (&rv->get_time_axis_view());
3444 if (tav->track() != 0) {
3445 speed = tav->track()->speed();
3448 start = session_frame_to_track_frame (loc.start(), speed);
3449 end = session_frame_to_track_frame (loc.end(), speed);
3451 rv->region()->clear_changes ();
3452 rv->region()->trim_to (start, (end - start));
3453 _session->add_command(new StatefulDiffCommand (rv->region()));
3456 commit_reversible_command ();
3460 Editor::trim_region_to_previous_region_end ()
3462 return trim_to_region(false);
3466 Editor::trim_region_to_next_region_start ()
3468 return trim_to_region(true);
3472 Editor::trim_to_region(bool forward)
3474 RegionSelection rs = get_regions_from_selection_and_entered ();
3476 begin_reversible_command (_("trim to region"));
3478 boost::shared_ptr<Region> next_region;
3480 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
3482 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*x);
3488 AudioTimeAxisView* atav = dynamic_cast<AudioTimeAxisView*> (&arv->get_time_axis_view());
3496 if (atav->track() != 0) {
3497 speed = atav->track()->speed();
3501 boost::shared_ptr<Region> region = arv->region();
3502 boost::shared_ptr<Playlist> playlist (region->playlist());
3504 region->clear_changes ();
3508 next_region = playlist->find_next_region (region->first_frame(), Start, 1);
3514 region->trim_end((framepos_t) ( (next_region->first_frame() - 1) * speed));
3515 arv->region_changed (PropertyChange (ARDOUR::Properties::length));
3519 next_region = playlist->find_next_region (region->first_frame(), Start, 0);
3525 region->trim_front((framepos_t) ((next_region->last_frame() + 1) * speed));
3527 arv->region_changed (ARDOUR::bounds_change);
3530 _session->add_command(new StatefulDiffCommand (region));
3533 commit_reversible_command ();
3537 Editor::unfreeze_route ()
3539 if (clicked_routeview == 0 || !clicked_routeview->is_track()) {
3543 clicked_routeview->track()->unfreeze ();
3547 Editor::_freeze_thread (void* arg)
3549 return static_cast<Editor*>(arg)->freeze_thread ();
3553 Editor::freeze_thread ()
3555 /* create event pool because we may need to talk to the session */
3556 SessionEvent::create_per_thread_pool ("freeze events", 64);
3557 /* create per-thread buffers for process() tree to use */
3558 clicked_routeview->audio_track()->freeze_me (*current_interthread_info);
3559 current_interthread_info->done = true;
3564 Editor::freeze_route ()
3570 /* stop transport before we start. this is important */
3572 _session->request_transport_speed (0.0);
3574 /* wait for just a little while, because the above call is asynchronous */
3576 Glib::usleep (250000);
3578 if (clicked_routeview == 0 || !clicked_routeview->is_audio_track()) {
3582 if (!clicked_routeview->track()->bounceable (clicked_routeview->track()->main_outs(), true)) {
3584 _("This track/bus cannot be frozen because the signal adds or loses channels before reaching the outputs.\n"
3585 "This is typically caused by plugins that generate stereo output from mono input or vice versa.")
3587 d.set_title (_("Cannot freeze"));
3592 if (clicked_routeview->track()->has_external_redirects()) {
3593 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"
3594 "Freezing will only process the signal as far as the first send/insert/return."),
3595 clicked_routeview->track()->name()), true, MESSAGE_INFO, BUTTONS_NONE, true);
3597 d.add_button (_("Freeze anyway"), Gtk::RESPONSE_OK);
3598 d.add_button (_("Don't freeze"), Gtk::RESPONSE_CANCEL);
3599 d.set_title (_("Freeze Limits"));
3601 int response = d.run ();
3604 case Gtk::RESPONSE_CANCEL:
3611 InterThreadInfo itt;
3612 current_interthread_info = &itt;
3614 InterthreadProgressWindow ipw (current_interthread_info, _("Freeze"), _("Cancel Freeze"));
3616 pthread_create_and_store (X_("freezer"), &itt.thread, _freeze_thread, this);
3618 set_canvas_cursor (_cursors->wait);
3620 while (!itt.done && !itt.cancel) {
3621 gtk_main_iteration ();
3624 current_interthread_info = 0;
3625 set_canvas_cursor (current_canvas_cursor);
3629 Editor::bounce_range_selection (bool replace, bool enable_processing)
3631 if (selection->time.empty()) {
3635 TrackSelection views = selection->tracks;
3637 for (TrackViewList::iterator i = views.begin(); i != views.end(); ++i) {
3639 if (enable_processing) {
3641 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*i);
3643 if (rtv && rtv->track() && replace && enable_processing && !rtv->track()->bounceable (rtv->track()->main_outs(), false)) {
3645 _("You can't perform this operation because the processing of the signal "
3646 "will cause one or more of the tracks to end up with a region with more channels than this track has inputs.\n\n"
3647 "You can do this without processing, which is a different operation.")
3649 d.set_title (_("Cannot bounce"));
3656 framepos_t start = selection->time[clicked_selection].start;
3657 framepos_t end = selection->time[clicked_selection].end;
3658 framepos_t cnt = end - start + 1;
3660 begin_reversible_command (_("bounce range"));
3662 for (TrackViewList::iterator i = views.begin(); i != views.end(); ++i) {
3664 RouteTimeAxisView* rtv;
3666 if ((rtv = dynamic_cast<RouteTimeAxisView*> (*i)) == 0) {
3670 boost::shared_ptr<Playlist> playlist;
3672 if ((playlist = rtv->playlist()) == 0) {
3676 InterThreadInfo itt;
3678 playlist->clear_changes ();
3679 playlist->clear_owned_changes ();
3681 boost::shared_ptr<Region> r;
3683 if (enable_processing) {
3684 r = rtv->track()->bounce_range (start, start+cnt, itt, rtv->track()->main_outs(), false);
3686 r = rtv->track()->bounce_range (start, start+cnt, itt, boost::shared_ptr<Processor>(), false);
3694 list<AudioRange> ranges;
3695 ranges.push_back (AudioRange (start, start+cnt, 0));
3696 playlist->cut (ranges); // discard result
3697 playlist->add_region (r, start);
3700 vector<Command*> cmds;
3701 playlist->rdiff (cmds);
3702 _session->add_commands (cmds);
3704 _session->add_command (new StatefulDiffCommand (playlist));
3707 commit_reversible_command ();
3710 /** Delete selected regions, automation points or a time range */
3717 /** Cut selected regions, automation points or a time range */
3724 /** Copy selected regions, automation points or a time range */
3732 /** @return true if a Cut, Copy or Clear is possible */
3734 Editor::can_cut_copy () const
3736 if (!selection->time.empty() || !selection->regions.empty() || !selection->points.empty())
3743 /** Cut, copy or clear selected regions, automation points or a time range.
3744 * @param op Operation (Delete, Cut, Copy or Clear)
3747 Editor::cut_copy (CutCopyOp op)
3749 /* only cancel selection if cut/copy is successful.*/
3755 opname = _("delete");
3764 opname = _("clear");
3768 /* if we're deleting something, and the mouse is still pressed,
3769 the thing we started a drag for will be gone when we release
3770 the mouse button(s). avoid this. see part 2 at the end of
3774 if (op == Delete || op == Cut || op == Clear) {
3775 if (_drags->active ()) {
3780 if ( op != Delete ) //"Delete" doesn't change copy/paste buf
3781 cut_buffer->clear ();
3783 if (entered_marker) {
3785 /* cut/delete op while pointing at a marker */
3788 Location* loc = find_location_from_marker (entered_marker, ignored);
3790 if (_session && loc) {
3791 Glib::signal_idle().connect (sigc::bind (sigc::mem_fun(*this, &Editor::really_remove_marker), loc));
3798 if (internal_editing()) {
3800 switch (effective_mouse_mode()) {
3803 begin_reversible_command (opname + ' ' + X_("MIDI"));
3805 commit_reversible_command ();
3814 bool did_edit = false;
3816 if (!selection->points.empty()) {
3817 begin_reversible_command (opname + _(" points"));
3819 cut_copy_points (op);
3820 if (op == Cut || op == Delete) {
3821 selection->clear_points ();
3823 } else if (!selection->regions.empty() || !selection->points.empty()) {
3827 if (selection->regions.empty()) {
3828 thing_name = _("points");
3829 } else if (selection->points.empty()) {
3830 thing_name = _("regions");
3832 thing_name = _("objects");
3835 begin_reversible_command (opname + ' ' + thing_name);
3838 if (!selection->regions.empty()) {
3839 cut_copy_regions (op, selection->regions);
3841 if (op == Cut || op == Delete) {
3842 selection->clear_regions ();
3846 if (!selection->points.empty()) {
3847 cut_copy_points (op);
3849 if (op == Cut || op == Delete) {
3850 selection->clear_points ();
3853 } else if (selection->time.empty()) {
3854 framepos_t start, end;
3855 /* no time selection, see if we can get an edit range
3858 if (get_edit_op_range (start, end)) {
3859 selection->set (start, end);
3861 } else if (!selection->time.empty()) {
3862 begin_reversible_command (opname + _(" range"));
3865 cut_copy_ranges (op);
3867 if (op == Cut || op == Delete) {
3868 selection->clear_time ();
3873 commit_reversible_command ();
3876 if (op == Delete || op == Cut || op == Clear) {
3881 struct AutomationRecord {
3882 AutomationRecord () : state (0) {}
3883 AutomationRecord (XMLNode* s) : state (s) {}
3885 XMLNode* state; ///< state before any operation
3886 boost::shared_ptr<Evoral::ControlList> copy; ///< copied events for the cut buffer
3889 /** Cut, copy or clear selected automation points.
3890 * @param op Operation (Cut, Copy or Clear)
3893 Editor::cut_copy_points (CutCopyOp op)
3895 if (selection->points.empty ()) {
3899 /* XXX: not ideal, as there may be more than one track involved in the point selection */
3900 _last_cut_copy_source_track = &selection->points.front()->line().trackview;
3902 /* Keep a record of the AutomationLists that we end up using in this operation */
3903 typedef std::map<boost::shared_ptr<AutomationList>, AutomationRecord> Lists;
3906 /* Go through all selected points, making an AutomationRecord for each distinct AutomationList */
3907 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
3908 boost::shared_ptr<AutomationList> al = (*i)->line().the_list();
3909 if (lists.find (al) == lists.end ()) {
3910 /* We haven't seen this list yet, so make a record for it. This includes
3911 taking a copy of its current state, in case this is needed for undo later.
3913 lists[al] = AutomationRecord (&al->get_state ());
3917 if (op == Cut || op == Copy) {
3918 /* This operation will involve putting things in the cut buffer, so create an empty
3919 ControlList for each of our source lists to put the cut buffer data in.
3921 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
3922 i->second.copy = i->first->create (i->first->parameter ());
3925 /* Add all selected points to the relevant copy ControlLists */
3926 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
3927 boost::shared_ptr<AutomationList> al = (*i)->line().the_list();
3928 AutomationList::const_iterator j = (*i)->model ();
3929 lists[al].copy->add ((*j)->when, (*j)->value);
3932 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
3933 /* Correct this copy list so that it starts at time 0 */
3934 double const start = i->second.copy->front()->when;
3935 for (AutomationList::iterator j = i->second.copy->begin(); j != i->second.copy->end(); ++j) {
3936 (*j)->when -= start;
3939 /* And add it to the cut buffer */
3940 cut_buffer->add (i->second.copy);
3944 if (op == Delete || op == Cut) {
3945 /* This operation needs to remove things from the main AutomationList, so do that now */
3947 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
3948 i->first->freeze ();
3951 /* Remove each selected point from its AutomationList */
3952 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
3953 boost::shared_ptr<AutomationList> al = (*i)->line().the_list();
3954 al->erase ((*i)->model ());
3957 /* Thaw the lists and add undo records for them */
3958 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
3959 boost::shared_ptr<AutomationList> al = i->first;
3961 _session->add_command (new MementoCommand<AutomationList> (*al.get(), i->second.state, &(al->get_state ())));
3966 /** Cut, copy or clear selected automation points.
3967 * @param op Operation (Cut, Copy or Clear)
3970 Editor::cut_copy_midi (CutCopyOp op)
3972 for (MidiRegionSelection::iterator i = selection->midi_regions.begin(); i != selection->midi_regions.end(); ++i) {
3973 MidiRegionView* mrv = *i;
3974 mrv->cut_copy_clear (op);
3980 struct lt_playlist {
3981 bool operator () (const PlaylistState& a, const PlaylistState& b) {
3982 return a.playlist < b.playlist;
3986 struct PlaylistMapping {
3988 boost::shared_ptr<Playlist> pl;
3990 PlaylistMapping (TimeAxisView* tvp) : tv (tvp) {}
3993 /** Remove `clicked_regionview' */
3995 Editor::remove_clicked_region ()
3997 if (clicked_routeview == 0 || clicked_regionview == 0) {
4001 boost::shared_ptr<Playlist> playlist = clicked_routeview->playlist();
4003 playlist->clear_changes ();
4004 playlist->clear_owned_changes ();
4005 playlist->remove_region (clicked_regionview->region());
4006 if (Config->get_edit_mode() == Ripple)
4007 playlist->ripple (clicked_regionview->region()->position(), -clicked_regionview->region()->length(), boost::shared_ptr<Region>());
4009 /* We might have removed regions, which alters other regions' layering_index,
4010 so we need to do a recursive diff here.
4012 vector<Command*> cmds;
4013 playlist->rdiff (cmds);
4014 _session->add_commands (cmds);
4016 _session->add_command(new StatefulDiffCommand (playlist));
4017 commit_reversible_command ();
4021 /** Remove the selected regions */
4023 Editor::remove_selected_regions ()
4025 RegionSelection rs = get_regions_from_selection_and_entered ();
4027 if (!_session || rs.empty()) {
4031 begin_reversible_command (_("remove region"));
4033 list<boost::shared_ptr<Region> > regions_to_remove;
4035 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
4036 // we can't just remove the region(s) in this loop because
4037 // this removes them from the RegionSelection, and they thus
4038 // disappear from underneath the iterator, and the ++i above
4039 // SEGVs in a puzzling fashion.
4041 // so, first iterate over the regions to be removed from rs and
4042 // add them to the regions_to_remove list, and then
4043 // iterate over the list to actually remove them.
4045 regions_to_remove.push_back ((*i)->region());
4048 vector<boost::shared_ptr<Playlist> > playlists;
4050 for (list<boost::shared_ptr<Region> >::iterator rl = regions_to_remove.begin(); rl != regions_to_remove.end(); ++rl) {
4052 boost::shared_ptr<Playlist> playlist = (*rl)->playlist();
4055 // is this check necessary?
4059 /* get_regions_from_selection_and_entered() guarantees that
4060 the playlists involved are unique, so there is no need
4064 playlists.push_back (playlist);
4066 playlist->clear_changes ();
4067 playlist->clear_owned_changes ();
4068 playlist->freeze ();
4069 playlist->remove_region (*rl);
4070 if (Config->get_edit_mode() == Ripple)
4071 playlist->ripple ((*rl)->position(), -(*rl)->length(), boost::shared_ptr<Region>());
4075 vector<boost::shared_ptr<Playlist> >::iterator pl;
4077 for (pl = playlists.begin(); pl != playlists.end(); ++pl) {
4080 /* We might have removed regions, which alters other regions' layering_index,
4081 so we need to do a recursive diff here.
4083 vector<Command*> cmds;
4084 (*pl)->rdiff (cmds);
4085 _session->add_commands (cmds);
4087 _session->add_command(new StatefulDiffCommand (*pl));
4090 commit_reversible_command ();
4093 /** Cut, copy or clear selected regions.
4094 * @param op Operation (Cut, Copy or Clear)
4097 Editor::cut_copy_regions (CutCopyOp op, RegionSelection& rs)
4099 /* we can't use a std::map here because the ordering is important, and we can't trivially sort
4100 a map when we want ordered access to both elements. i think.
4103 vector<PlaylistMapping> pmap;
4105 framepos_t first_position = max_framepos;
4107 typedef set<boost::shared_ptr<Playlist> > FreezeList;
4108 FreezeList freezelist;
4110 /* get ordering correct before we cut/copy */
4112 rs.sort_by_position_and_track ();
4114 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
4116 first_position = min ((framepos_t) (*x)->region()->position(), first_position);
4118 if (op == Cut || op == Clear || op == Delete) {
4119 boost::shared_ptr<Playlist> pl = (*x)->region()->playlist();
4122 FreezeList::iterator fl;
4124 // only take state if this is a new playlist.
4125 for (fl = freezelist.begin(); fl != freezelist.end(); ++fl) {
4131 if (fl == freezelist.end()) {
4132 pl->clear_changes();
4133 pl->clear_owned_changes ();
4135 freezelist.insert (pl);
4140 TimeAxisView* tv = &(*x)->get_time_axis_view();
4141 vector<PlaylistMapping>::iterator z;
4143 for (z = pmap.begin(); z != pmap.end(); ++z) {
4144 if ((*z).tv == tv) {
4149 if (z == pmap.end()) {
4150 pmap.push_back (PlaylistMapping (tv));
4154 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ) {
4156 boost::shared_ptr<Playlist> pl = (*x)->region()->playlist();
4159 /* region not yet associated with a playlist (e.g. unfinished
4166 TimeAxisView& tv = (*x)->get_time_axis_view();
4167 boost::shared_ptr<Playlist> npl;
4168 RegionSelection::iterator tmp;
4175 vector<PlaylistMapping>::iterator z;
4177 for (z = pmap.begin(); z != pmap.end(); ++z) {
4178 if ((*z).tv == &tv) {
4183 assert (z != pmap.end());
4186 npl = PlaylistFactory::create (pl->data_type(), *_session, "cutlist", true);
4194 boost::shared_ptr<Region> r = (*x)->region();
4195 boost::shared_ptr<Region> _xx;
4201 pl->remove_region (r);
4202 if (Config->get_edit_mode() == Ripple)
4203 pl->ripple (r->position(), -r->length(), boost::shared_ptr<Region>());
4207 _xx = RegionFactory::create (r);
4208 npl->add_region (_xx, r->position() - first_position);
4209 pl->remove_region (r);
4210 if (Config->get_edit_mode() == Ripple)
4211 pl->ripple (r->position(), -r->length(), boost::shared_ptr<Region>());
4215 /* copy region before adding, so we're not putting same object into two different playlists */
4216 npl->add_region (RegionFactory::create (r), r->position() - first_position);
4220 pl->remove_region (r);
4221 if (Config->get_edit_mode() == Ripple)
4222 pl->ripple (r->position(), -r->length(), boost::shared_ptr<Region>());
4231 list<boost::shared_ptr<Playlist> > foo;
4233 /* the pmap is in the same order as the tracks in which selected regions occured */
4235 for (vector<PlaylistMapping>::iterator i = pmap.begin(); i != pmap.end(); ++i) {
4238 foo.push_back ((*i).pl);
4243 cut_buffer->set (foo);
4247 _last_cut_copy_source_track = 0;
4249 _last_cut_copy_source_track = pmap.front().tv;
4253 for (FreezeList::iterator pl = freezelist.begin(); pl != freezelist.end(); ++pl) {
4256 /* We might have removed regions, which alters other regions' layering_index,
4257 so we need to do a recursive diff here.
4259 vector<Command*> cmds;
4260 (*pl)->rdiff (cmds);
4261 _session->add_commands (cmds);
4263 _session->add_command (new StatefulDiffCommand (*pl));
4268 Editor::cut_copy_ranges (CutCopyOp op)
4270 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4272 /* Sort the track selection now, so that it if is used, the playlists
4273 selected by the calls below to cut_copy_clear are in the order that
4274 their tracks appear in the editor. This makes things like paste
4275 of ranges work properly.
4278 sort_track_selection (ts);
4281 if (!entered_track) {
4284 ts.push_back (entered_track);
4287 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4288 (*i)->cut_copy_clear (*selection, op);
4293 Editor::paste (float times, bool from_context)
4295 DEBUG_TRACE (DEBUG::CutNPaste, "paste to preferred edit pos\n");
4297 paste_internal (get_preferred_edit_position (false, from_context), times);
4301 Editor::mouse_paste ()
4306 if (!mouse_frame (where, ignored)) {
4311 paste_internal (where, 1);
4315 Editor::paste_internal (framepos_t position, float times)
4317 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("apparent paste position is %1\n", position));
4319 if (internal_editing()) {
4320 if (cut_buffer->midi_notes.empty()) {
4324 if (cut_buffer->empty()) {
4329 if (position == max_framepos) {
4330 position = get_preferred_edit_position();
4331 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("preferred edit position is %1\n", position));
4335 TrackViewList::iterator i;
4338 /* get everything in the correct order */
4340 if (_edit_point == Editing::EditAtMouse && entered_track) {
4341 /* With the mouse edit point, paste onto the track under the mouse */
4342 ts.push_back (entered_track);
4343 } else if (!selection->tracks.empty()) {
4344 /* Otherwise, if there are some selected tracks, paste to them */
4345 ts = selection->tracks.filter_to_unique_playlists ();
4346 sort_track_selection (ts);
4347 } else if (_last_cut_copy_source_track) {
4348 /* Otherwise paste to the track that the cut/copy came from;
4349 see discussion in mantis #3333.
4351 ts.push_back (_last_cut_copy_source_track);
4354 if (internal_editing ()) {
4356 /* undo/redo is handled by individual tracks/regions */
4358 for (nth = 0, i = ts.begin(); i != ts.end(); ++i, ++nth) {
4361 RegionSelection::iterator r;
4362 MidiNoteSelection::iterator cb;
4364 get_regions_at (rs, position, ts);
4366 for (cb = cut_buffer->midi_notes.begin(), r = rs.begin();
4367 cb != cut_buffer->midi_notes.end() && r != rs.end(); ++r) {
4368 MidiRegionView* mrv = dynamic_cast<MidiRegionView*> (*r);
4370 mrv->paste (position, times, **cb);
4378 /* we do redo (do you do voodoo?) */
4380 begin_reversible_command (Operations::paste);
4382 for (nth = 0, i = ts.begin(); i != ts.end(); ++i, ++nth) {
4383 (*i)->paste (position, times, *cut_buffer, nth);
4386 commit_reversible_command ();
4391 Editor::duplicate_some_regions (RegionSelection& regions, float times)
4393 boost::shared_ptr<Playlist> playlist;
4394 RegionSelection sel = regions; // clear (below) may clear the argument list if its the current region selection
4395 RegionSelection foo;
4397 framepos_t const start_frame = regions.start ();
4398 framepos_t const end_frame = regions.end_frame ();
4400 begin_reversible_command (Operations::duplicate_region);
4402 selection->clear_regions ();
4404 for (RegionSelection::iterator i = sel.begin(); i != sel.end(); ++i) {
4406 boost::shared_ptr<Region> r ((*i)->region());
4408 TimeAxisView& tv = (*i)->get_time_axis_view();
4409 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (&tv);
4410 latest_regionviews.clear ();
4411 sigc::connection c = rtv->view()->RegionViewAdded.connect (sigc::mem_fun(*this, &Editor::collect_new_region_view));
4413 playlist = (*i)->region()->playlist();
4414 playlist->clear_changes ();
4415 playlist->duplicate (r, end_frame + (r->first_frame() - start_frame), times);
4416 _session->add_command(new StatefulDiffCommand (playlist));
4420 foo.insert (foo.end(), latest_regionviews.begin(), latest_regionviews.end());
4423 commit_reversible_command ();
4426 selection->set (foo);
4431 Editor::duplicate_selection (float times)
4433 if (selection->time.empty() || selection->tracks.empty()) {
4437 boost::shared_ptr<Playlist> playlist;
4438 vector<boost::shared_ptr<Region> > new_regions;
4439 vector<boost::shared_ptr<Region> >::iterator ri;
4441 create_region_from_selection (new_regions);
4443 if (new_regions.empty()) {
4447 begin_reversible_command (_("duplicate selection"));
4449 ri = new_regions.begin();
4451 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4453 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4454 if ((playlist = (*i)->playlist()) == 0) {
4457 playlist->clear_changes ();
4458 playlist->duplicate (*ri, selection->time[clicked_selection].end, times);
4459 _session->add_command (new StatefulDiffCommand (playlist));
4462 if (ri == new_regions.end()) {
4467 commit_reversible_command ();
4470 /** Reset all selected points to the relevant default value */
4472 Editor::reset_point_selection ()
4474 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
4475 ARDOUR::AutomationList::iterator j = (*i)->model ();
4476 (*j)->value = (*i)->line().the_list()->default_value ();
4481 Editor::center_playhead ()
4483 float const page = _visible_canvas_width * samples_per_pixel;
4484 center_screen_internal (playhead_cursor->current_frame (), page);
4488 Editor::center_edit_point ()
4490 float const page = _visible_canvas_width * samples_per_pixel;
4491 center_screen_internal (get_preferred_edit_position(), page);
4494 /** Caller must begin and commit a reversible command */
4496 Editor::clear_playlist (boost::shared_ptr<Playlist> playlist)
4498 playlist->clear_changes ();
4500 _session->add_command (new StatefulDiffCommand (playlist));
4504 Editor::nudge_track (bool use_edit, bool forwards)
4506 boost::shared_ptr<Playlist> playlist;
4507 framepos_t distance;
4508 framepos_t next_distance;
4512 start = get_preferred_edit_position();
4517 if ((distance = get_nudge_distance (start, next_distance)) == 0) {
4521 if (selection->tracks.empty()) {
4525 begin_reversible_command (_("nudge track"));
4527 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4529 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4531 if ((playlist = (*i)->playlist()) == 0) {
4535 playlist->clear_changes ();
4536 playlist->clear_owned_changes ();
4538 playlist->nudge_after (start, distance, forwards);
4540 vector<Command*> cmds;
4542 playlist->rdiff (cmds);
4543 _session->add_commands (cmds);
4545 _session->add_command (new StatefulDiffCommand (playlist));
4548 commit_reversible_command ();
4552 Editor::remove_last_capture ()
4554 vector<string> choices;
4561 if (Config->get_verify_remove_last_capture()) {
4562 prompt = _("Do you really want to destroy the last capture?"
4563 "\n(This is destructive and cannot be undone)");
4565 choices.push_back (_("No, do nothing."));
4566 choices.push_back (_("Yes, destroy it."));
4568 Gtkmm2ext::Choice prompter (_("Destroy last capture"), prompt, choices);
4570 if (prompter.run () == 1) {
4571 _session->remove_last_capture ();
4572 _regions->redisplay ();
4576 _session->remove_last_capture();
4577 _regions->redisplay ();
4582 Editor::normalize_region ()
4588 RegionSelection rs = get_regions_from_selection_and_entered ();
4594 NormalizeDialog dialog (rs.size() > 1);
4596 if (dialog.run () == RESPONSE_CANCEL) {
4600 set_canvas_cursor (_cursors->wait);
4603 /* XXX: should really only count audio regions here */
4604 int const regions = rs.size ();
4606 /* Make a list of the selected audio regions' maximum amplitudes, and also
4607 obtain the maximum amplitude of them all.
4609 list<double> max_amps;
4611 for (RegionSelection::const_iterator i = rs.begin(); i != rs.end(); ++i) {
4612 AudioRegionView const * arv = dynamic_cast<AudioRegionView const *> (*i);
4614 dialog.descend (1.0 / regions);
4615 double const a = arv->audio_region()->maximum_amplitude (&dialog);
4618 /* the user cancelled the operation */
4619 set_canvas_cursor (current_canvas_cursor);
4623 max_amps.push_back (a);
4624 max_amp = max (max_amp, a);
4629 begin_reversible_command (_("normalize"));
4631 list<double>::const_iterator a = max_amps.begin ();
4633 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
4634 AudioRegionView* const arv = dynamic_cast<AudioRegionView*> (*r);
4639 arv->region()->clear_changes ();
4641 double const amp = dialog.normalize_individually() ? *a : max_amp;
4643 arv->audio_region()->normalize (amp, dialog.target ());
4644 _session->add_command (new StatefulDiffCommand (arv->region()));
4649 commit_reversible_command ();
4650 set_canvas_cursor (current_canvas_cursor);
4655 Editor::reset_region_scale_amplitude ()
4661 RegionSelection rs = get_regions_from_selection_and_entered ();
4667 begin_reversible_command ("reset gain");
4669 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
4670 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
4673 arv->region()->clear_changes ();
4674 arv->audio_region()->set_scale_amplitude (1.0f);
4675 _session->add_command (new StatefulDiffCommand (arv->region()));
4678 commit_reversible_command ();
4682 Editor::adjust_region_gain (bool up)
4684 RegionSelection rs = get_regions_from_selection_and_entered ();
4686 if (!_session || rs.empty()) {
4690 begin_reversible_command ("adjust region gain");
4692 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
4693 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
4698 arv->region()->clear_changes ();
4700 double dB = accurate_coefficient_to_dB (arv->audio_region()->scale_amplitude ());
4708 arv->audio_region()->set_scale_amplitude (dB_to_coefficient (dB));
4709 _session->add_command (new StatefulDiffCommand (arv->region()));
4712 commit_reversible_command ();
4717 Editor::reverse_region ()
4723 Reverse rev (*_session);
4724 apply_filter (rev, _("reverse regions"));
4728 Editor::strip_region_silence ()
4734 RegionSelection rs = get_regions_from_selection_and_entered ();
4740 std::list<RegionView*> audio_only;
4742 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
4743 AudioRegionView* const arv = dynamic_cast<AudioRegionView*> (*i);
4745 audio_only.push_back (arv);
4749 StripSilenceDialog d (_session, audio_only);
4750 int const r = d.run ();
4754 if (r == Gtk::RESPONSE_OK) {
4755 ARDOUR::AudioIntervalMap silences;
4756 d.silences (silences);
4757 StripSilence s (*_session, silences, d.fade_length());
4758 apply_filter (s, _("strip silence"), &d);
4763 Editor::apply_midi_note_edit_op_to_region (MidiOperator& op, MidiRegionView& mrv)
4765 Evoral::Sequence<Evoral::MusicalTime>::Notes selected;
4766 mrv.selection_as_notelist (selected, true);
4768 vector<Evoral::Sequence<Evoral::MusicalTime>::Notes> v;
4769 v.push_back (selected);
4771 framepos_t pos_frames = mrv.midi_region()->position() - mrv.midi_region()->start();
4772 double pos_beats = _session->tempo_map().framewalk_to_beats(0, pos_frames);
4774 return op (mrv.midi_region()->model(), pos_beats, v);
4778 Editor::apply_midi_note_edit_op (MidiOperator& op)
4782 RegionSelection rs = get_regions_from_selection_and_entered ();
4788 begin_reversible_command (op.name ());
4790 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
4791 RegionSelection::iterator tmp = r;
4794 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*r);
4797 cmd = apply_midi_note_edit_op_to_region (op, *mrv);
4800 _session->add_command (cmd);
4807 commit_reversible_command ();
4811 Editor::fork_region ()
4813 RegionSelection rs = get_regions_from_selection_and_entered ();
4819 begin_reversible_command (_("Fork Region(s)"));
4821 set_canvas_cursor (_cursors->wait);
4824 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
4825 RegionSelection::iterator tmp = r;
4828 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*>(*r);
4832 boost::shared_ptr<Playlist> playlist = mrv->region()->playlist();
4833 boost::shared_ptr<MidiSource> new_source = _session->create_midi_source_by_stealing_name (mrv->midi_view()->track());
4834 boost::shared_ptr<MidiRegion> newregion = mrv->midi_region()->clone (new_source);
4836 playlist->clear_changes ();
4837 playlist->replace_region (mrv->region(), newregion, mrv->region()->position());
4838 _session->add_command(new StatefulDiffCommand (playlist));
4840 error << string_compose (_("Could not unlink %1"), mrv->region()->name()) << endmsg;
4847 commit_reversible_command ();
4849 set_canvas_cursor (current_canvas_cursor);
4853 Editor::quantize_region ()
4855 int selected_midi_region_cnt = 0;
4861 RegionSelection rs = get_regions_from_selection_and_entered ();
4867 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
4868 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*r);
4870 selected_midi_region_cnt++;
4874 if (selected_midi_region_cnt == 0) {
4878 QuantizeDialog* qd = new QuantizeDialog (*this);
4881 const int r = qd->run ();
4884 if (r == Gtk::RESPONSE_OK) {
4885 Quantize quant (*_session, qd->snap_start(), qd->snap_end(),
4886 qd->start_grid_size(), qd->end_grid_size(),
4887 qd->strength(), qd->swing(), qd->threshold());
4889 apply_midi_note_edit_op (quant);
4894 Editor::insert_patch_change (bool from_context)
4896 RegionSelection rs = get_regions_from_selection_and_entered ();
4902 const framepos_t p = get_preferred_edit_position (false, from_context);
4904 /* XXX: bit of a hack; use the MIDNAM from the first selected region;
4905 there may be more than one, but the PatchChangeDialog can only offer
4906 one set of patch menus.
4908 MidiRegionView* first = dynamic_cast<MidiRegionView*> (rs.front ());
4910 Evoral::PatchChange<Evoral::MusicalTime> empty (0, 0, 0, 0);
4911 PatchChangeDialog d (0, _session, empty, first->instrument_info(), Gtk::Stock::ADD);
4913 if (d.run() == RESPONSE_CANCEL) {
4917 for (RegionSelection::iterator i = rs.begin (); i != rs.end(); ++i) {
4918 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*i);
4920 if (p >= mrv->region()->first_frame() && p <= mrv->region()->last_frame()) {
4921 mrv->add_patch_change (p - mrv->region()->position(), d.patch ());
4928 Editor::apply_filter (Filter& filter, string command, ProgressReporter* progress)
4930 RegionSelection rs = get_regions_from_selection_and_entered ();
4936 begin_reversible_command (command);
4938 set_canvas_cursor (_cursors->wait);
4942 int const N = rs.size ();
4944 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
4945 RegionSelection::iterator tmp = r;
4948 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
4950 boost::shared_ptr<Playlist> playlist = arv->region()->playlist();
4953 progress->descend (1.0 / N);
4956 if (arv->audio_region()->apply (filter, progress) == 0) {
4958 playlist->clear_changes ();
4959 playlist->clear_owned_changes ();
4961 if (filter.results.empty ()) {
4963 /* no regions returned; remove the old one */
4964 playlist->remove_region (arv->region ());
4968 std::vector<boost::shared_ptr<Region> >::iterator res = filter.results.begin ();
4970 /* first region replaces the old one */
4971 playlist->replace_region (arv->region(), *res, (*res)->position());
4975 while (res != filter.results.end()) {
4976 playlist->add_region (*res, (*res)->position());
4982 /* We might have removed regions, which alters other regions' layering_index,
4983 so we need to do a recursive diff here.
4985 vector<Command*> cmds;
4986 playlist->rdiff (cmds);
4987 _session->add_commands (cmds);
4989 _session->add_command(new StatefulDiffCommand (playlist));
4995 progress->ascend ();
5003 commit_reversible_command ();
5006 set_canvas_cursor (current_canvas_cursor);
5010 Editor::external_edit_region ()
5016 Editor::reset_region_gain_envelopes ()
5018 RegionSelection rs = get_regions_from_selection_and_entered ();
5020 if (!_session || rs.empty()) {
5024 _session->begin_reversible_command (_("reset region gain"));
5026 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5027 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
5029 boost::shared_ptr<AutomationList> alist (arv->audio_region()->envelope());
5030 XMLNode& before (alist->get_state());
5032 arv->audio_region()->set_default_envelope ();
5033 _session->add_command (new MementoCommand<AutomationList>(*arv->audio_region()->envelope().get(), &before, &alist->get_state()));
5037 _session->commit_reversible_command ();
5041 Editor::set_region_gain_visibility (RegionView* rv)
5043 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (rv);
5045 arv->update_envelope_visibility();
5050 Editor::set_gain_envelope_visibility ()
5056 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5057 AudioTimeAxisView* v = dynamic_cast<AudioTimeAxisView*>(*i);
5059 v->audio_view()->foreach_regionview (sigc::mem_fun (this, &Editor::set_region_gain_visibility));
5065 Editor::toggle_gain_envelope_active ()
5067 if (_ignore_region_action) {
5071 RegionSelection rs = get_regions_from_selection_and_entered ();
5073 if (!_session || rs.empty()) {
5077 _session->begin_reversible_command (_("region gain envelope active"));
5079 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5080 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
5082 arv->region()->clear_changes ();
5083 arv->audio_region()->set_envelope_active (!arv->audio_region()->envelope_active());
5084 _session->add_command (new StatefulDiffCommand (arv->region()));
5088 _session->commit_reversible_command ();
5092 Editor::toggle_region_lock ()
5094 if (_ignore_region_action) {
5098 RegionSelection rs = get_regions_from_selection_and_entered ();
5100 if (!_session || rs.empty()) {
5104 _session->begin_reversible_command (_("toggle region lock"));
5106 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5107 (*i)->region()->clear_changes ();
5108 (*i)->region()->set_locked (!(*i)->region()->locked());
5109 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5112 _session->commit_reversible_command ();
5116 Editor::toggle_region_video_lock ()
5118 if (_ignore_region_action) {
5122 RegionSelection rs = get_regions_from_selection_and_entered ();
5124 if (!_session || rs.empty()) {
5128 _session->begin_reversible_command (_("Toggle Video Lock"));
5130 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5131 (*i)->region()->clear_changes ();
5132 (*i)->region()->set_video_locked (!(*i)->region()->video_locked());
5133 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5136 _session->commit_reversible_command ();
5140 Editor::toggle_region_lock_style ()
5142 if (_ignore_region_action) {
5146 RegionSelection rs = get_regions_from_selection_and_entered ();
5148 if (!_session || rs.empty()) {
5152 _session->begin_reversible_command (_("region lock style"));
5154 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5155 (*i)->region()->clear_changes ();
5156 PositionLockStyle const ns = (*i)->region()->position_lock_style() == AudioTime ? MusicTime : AudioTime;
5157 (*i)->region()->set_position_lock_style (ns);
5158 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5161 _session->commit_reversible_command ();
5165 Editor::toggle_opaque_region ()
5167 if (_ignore_region_action) {
5171 RegionSelection rs = get_regions_from_selection_and_entered ();
5173 if (!_session || rs.empty()) {
5177 _session->begin_reversible_command (_("change region opacity"));
5179 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5180 (*i)->region()->clear_changes ();
5181 (*i)->region()->set_opaque (!(*i)->region()->opaque());
5182 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5185 _session->commit_reversible_command ();
5189 Editor::toggle_record_enable ()
5191 bool new_state = false;
5193 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5194 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5197 if (!rtav->is_track())
5201 new_state = !rtav->track()->record_enabled();
5205 rtav->track()->set_record_enabled (new_state, this);
5210 Editor::toggle_solo ()
5212 bool new_state = false;
5214 boost::shared_ptr<RouteList> rl (new RouteList);
5216 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5217 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5224 new_state = !rtav->route()->soloed ();
5228 rl->push_back (rtav->route());
5231 _session->set_solo (rl, new_state, Session::rt_cleanup, true);
5235 Editor::toggle_mute ()
5237 bool new_state = false;
5239 boost::shared_ptr<RouteList> rl (new RouteList);
5241 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5242 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5249 new_state = !rtav->route()->muted();
5253 rl->push_back (rtav->route());
5256 _session->set_mute (rl, new_state, Session::rt_cleanup, true);
5260 Editor::toggle_solo_isolate ()
5266 Editor::fade_range ()
5268 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
5270 begin_reversible_command (_("fade range"));
5272 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
5273 (*i)->fade_range (selection->time);
5276 commit_reversible_command ();
5281 Editor::set_fade_length (bool in)
5283 RegionSelection rs = get_regions_from_selection_and_entered ();
5289 /* we need a region to measure the offset from the start */
5291 RegionView* rv = rs.front ();
5293 framepos_t pos = get_preferred_edit_position();
5297 if (pos > rv->region()->last_frame() || pos < rv->region()->first_frame()) {
5298 /* edit point is outside the relevant region */
5303 if (pos <= rv->region()->position()) {
5307 len = pos - rv->region()->position();
5308 cmd = _("set fade in length");
5310 if (pos >= rv->region()->last_frame()) {
5314 len = rv->region()->last_frame() - pos;
5315 cmd = _("set fade out length");
5318 begin_reversible_command (cmd);
5320 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5321 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5327 boost::shared_ptr<AutomationList> alist;
5329 alist = tmp->audio_region()->fade_in();
5331 alist = tmp->audio_region()->fade_out();
5334 XMLNode &before = alist->get_state();
5337 tmp->audio_region()->set_fade_in_length (len);
5338 tmp->audio_region()->set_fade_in_active (true);
5340 tmp->audio_region()->set_fade_out_length (len);
5341 tmp->audio_region()->set_fade_out_active (true);
5344 XMLNode &after = alist->get_state();
5345 _session->add_command(new MementoCommand<AutomationList>(*alist, &before, &after));
5348 commit_reversible_command ();
5352 Editor::set_fade_in_shape (FadeShape shape)
5354 RegionSelection rs = get_regions_from_selection_and_entered ();
5360 begin_reversible_command (_("set fade in shape"));
5362 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5363 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5369 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_in();
5370 XMLNode &before = alist->get_state();
5372 tmp->audio_region()->set_fade_in_shape (shape);
5374 XMLNode &after = alist->get_state();
5375 _session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
5378 commit_reversible_command ();
5383 Editor::set_fade_out_shape (FadeShape shape)
5385 RegionSelection rs = get_regions_from_selection_and_entered ();
5391 begin_reversible_command (_("set fade out shape"));
5393 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5394 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5400 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_out();
5401 XMLNode &before = alist->get_state();
5403 tmp->audio_region()->set_fade_out_shape (shape);
5405 XMLNode &after = alist->get_state();
5406 _session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
5409 commit_reversible_command ();
5413 Editor::set_fade_in_active (bool yn)
5415 RegionSelection rs = get_regions_from_selection_and_entered ();
5421 begin_reversible_command (_("set fade in active"));
5423 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5424 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5431 boost::shared_ptr<AudioRegion> ar (tmp->audio_region());
5433 ar->clear_changes ();
5434 ar->set_fade_in_active (yn);
5435 _session->add_command (new StatefulDiffCommand (ar));
5438 commit_reversible_command ();
5442 Editor::set_fade_out_active (bool yn)
5444 RegionSelection rs = get_regions_from_selection_and_entered ();
5450 begin_reversible_command (_("set fade out active"));
5452 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5453 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5459 boost::shared_ptr<AudioRegion> ar (tmp->audio_region());
5461 ar->clear_changes ();
5462 ar->set_fade_out_active (yn);
5463 _session->add_command(new StatefulDiffCommand (ar));
5466 commit_reversible_command ();
5470 Editor::toggle_region_fades (int dir)
5472 if (_ignore_region_action) {
5476 boost::shared_ptr<AudioRegion> ar;
5479 RegionSelection rs = get_regions_from_selection_and_entered ();
5485 RegionSelection::iterator i;
5486 for (i = rs.begin(); i != rs.end(); ++i) {
5487 if ((ar = boost::dynamic_pointer_cast<AudioRegion>((*i)->region())) != 0) {
5489 yn = ar->fade_out_active ();
5491 yn = ar->fade_in_active ();
5497 if (i == rs.end()) {
5501 /* XXX should this undo-able? */
5503 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5504 if ((ar = boost::dynamic_pointer_cast<AudioRegion>((*i)->region())) == 0) {
5507 if (dir == 1 || dir == 0) {
5508 ar->set_fade_in_active (!yn);
5511 if (dir == -1 || dir == 0) {
5512 ar->set_fade_out_active (!yn);
5518 /** Update region fade visibility after its configuration has been changed */
5520 Editor::update_region_fade_visibility ()
5522 bool _fade_visibility = _session->config.get_show_region_fades ();
5524 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5525 AudioTimeAxisView* v = dynamic_cast<AudioTimeAxisView*>(*i);
5527 if (_fade_visibility) {
5528 v->audio_view()->show_all_fades ();
5530 v->audio_view()->hide_all_fades ();
5537 Editor::set_edit_point ()
5542 if (!mouse_frame (where, ignored)) {
5548 if (selection->markers.empty()) {
5550 mouse_add_new_marker (where);
5555 Location* loc = find_location_from_marker (selection->markers.front(), ignored);
5558 loc->move_to (where);
5564 Editor::set_playhead_cursor ()
5566 if (entered_marker) {
5567 _session->request_locate (entered_marker->position(), _session->transport_rolling());
5572 if (!mouse_frame (where, ignored)) {
5579 _session->request_locate (where, _session->transport_rolling());
5583 if ( Config->get_follow_edits() )
5584 cancel_time_selection();
5588 Editor::split_region ()
5590 if ( !selection->time.empty()) {
5591 separate_regions_between (selection->time);
5595 RegionSelection rs = get_regions_from_selection_and_edit_point ();
5597 framepos_t where = get_preferred_edit_position ();
5603 split_regions_at (where, rs);
5606 struct EditorOrderRouteSorter {
5607 bool operator() (boost::shared_ptr<Route> a, boost::shared_ptr<Route> b) {
5608 return a->order_key () < b->order_key ();
5613 Editor::select_next_route()
5615 if (selection->tracks.empty()) {
5616 selection->set (track_views.front());
5620 TimeAxisView* current = selection->tracks.front();
5624 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5625 if (*i == current) {
5627 if (i != track_views.end()) {
5630 current = (*(track_views.begin()));
5631 //selection->set (*(track_views.begin()));
5636 rui = dynamic_cast<RouteUI *>(current);
5637 } while ( current->hidden() || (rui != NULL && !rui->route()->active()));
5639 selection->set(current);
5641 ensure_time_axis_view_is_visible (*current, false);
5645 Editor::select_prev_route()
5647 if (selection->tracks.empty()) {
5648 selection->set (track_views.front());
5652 TimeAxisView* current = selection->tracks.front();
5656 for (TrackViewList::reverse_iterator i = track_views.rbegin(); i != track_views.rend(); ++i) {
5657 if (*i == current) {
5659 if (i != track_views.rend()) {
5662 current = *(track_views.rbegin());
5667 rui = dynamic_cast<RouteUI *>(current);
5668 } while ( current->hidden() || (rui != NULL && !rui->route()->active()));
5670 selection->set (current);
5672 ensure_time_axis_view_is_visible (*current, false);
5676 Editor::set_loop_from_selection (bool play)
5678 if (_session == 0 || selection->time.empty()) {
5682 framepos_t start = selection->time[clicked_selection].start;
5683 framepos_t end = selection->time[clicked_selection].end;
5685 set_loop_range (start, end, _("set loop range from selection"));
5688 _session->request_play_loop (true);
5689 _session->request_locate (start, true);
5694 Editor::set_loop_from_edit_range (bool play)
5696 if (_session == 0) {
5703 if (!get_edit_op_range (start, end)) {
5707 set_loop_range (start, end, _("set loop range from edit range"));
5710 _session->request_play_loop (true);
5711 _session->request_locate (start, true);
5716 Editor::set_loop_from_region (bool play)
5718 framepos_t start = max_framepos;
5721 RegionSelection rs = get_regions_from_selection_and_entered ();
5727 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5728 if ((*i)->region()->position() < start) {
5729 start = (*i)->region()->position();
5731 if ((*i)->region()->last_frame() + 1 > end) {
5732 end = (*i)->region()->last_frame() + 1;
5736 set_loop_range (start, end, _("set loop range from region"));
5739 _session->request_play_loop (true);
5740 _session->request_locate (start, true);
5745 Editor::set_punch_from_selection ()
5747 if (_session == 0 || selection->time.empty()) {
5751 framepos_t start = selection->time[clicked_selection].start;
5752 framepos_t end = selection->time[clicked_selection].end;
5754 set_punch_range (start, end, _("set punch range from selection"));
5758 Editor::set_punch_from_edit_range ()
5760 if (_session == 0) {
5767 if (!get_edit_op_range (start, end)) {
5771 set_punch_range (start, end, _("set punch range from edit range"));
5775 Editor::set_punch_from_region ()
5777 framepos_t start = max_framepos;
5780 RegionSelection rs = get_regions_from_selection_and_entered ();
5786 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5787 if ((*i)->region()->position() < start) {
5788 start = (*i)->region()->position();
5790 if ((*i)->region()->last_frame() + 1 > end) {
5791 end = (*i)->region()->last_frame() + 1;
5795 set_punch_range (start, end, _("set punch range from region"));
5799 Editor::pitch_shift_region ()
5801 RegionSelection rs = get_regions_from_selection_and_entered ();
5803 RegionSelection audio_rs;
5804 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5805 if (dynamic_cast<AudioRegionView*> (*i)) {
5806 audio_rs.push_back (*i);
5810 if (audio_rs.empty()) {
5814 pitch_shift (audio_rs, 1.2);
5818 Editor::transpose_region ()
5820 RegionSelection rs = get_regions_from_selection_and_entered ();
5822 list<MidiRegionView*> midi_region_views;
5823 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5824 MidiRegionView* mrv = dynamic_cast<MidiRegionView*> (*i);
5826 midi_region_views.push_back (mrv);
5831 int const r = d.run ();
5832 if (r != RESPONSE_ACCEPT) {
5836 for (list<MidiRegionView*>::iterator i = midi_region_views.begin(); i != midi_region_views.end(); ++i) {
5837 (*i)->midi_region()->transpose (d.semitones ());
5842 Editor::set_tempo_from_region ()
5844 RegionSelection rs = get_regions_from_selection_and_entered ();
5846 if (!_session || rs.empty()) {
5850 RegionView* rv = rs.front();
5852 define_one_bar (rv->region()->position(), rv->region()->last_frame() + 1);
5856 Editor::use_range_as_bar ()
5858 framepos_t start, end;
5859 if (get_edit_op_range (start, end)) {
5860 define_one_bar (start, end);
5865 Editor::define_one_bar (framepos_t start, framepos_t end)
5867 framepos_t length = end - start;
5869 const Meter& m (_session->tempo_map().meter_at (start));
5871 /* length = 1 bar */
5873 /* now we want frames per beat.
5874 we have frames per bar, and beats per bar, so ...
5877 /* XXXX METER MATH */
5879 double frames_per_beat = length / m.divisions_per_bar();
5881 /* beats per minute = */
5883 double beats_per_minute = (_session->frame_rate() * 60.0) / frames_per_beat;
5885 /* now decide whether to:
5887 (a) set global tempo
5888 (b) add a new tempo marker
5892 const TempoSection& t (_session->tempo_map().tempo_section_at (start));
5894 bool do_global = false;
5896 if ((_session->tempo_map().n_tempos() == 1) && (_session->tempo_map().n_meters() == 1)) {
5898 /* only 1 tempo & 1 meter: ask if the user wants to set the tempo
5899 at the start, or create a new marker
5902 vector<string> options;
5903 options.push_back (_("Cancel"));
5904 options.push_back (_("Add new marker"));
5905 options.push_back (_("Set global tempo"));
5908 _("Define one bar"),
5909 _("Do you want to set the global tempo or add a new tempo marker?"),
5913 c.set_default_response (2);
5929 /* more than 1 tempo and/or meter section already, go ahead do the "usual":
5930 if the marker is at the region starter, change it, otherwise add
5935 begin_reversible_command (_("set tempo from region"));
5936 XMLNode& before (_session->tempo_map().get_state());
5939 _session->tempo_map().change_initial_tempo (beats_per_minute, t.note_type());
5940 } else if (t.frame() == start) {
5941 _session->tempo_map().change_existing_tempo_at (start, beats_per_minute, t.note_type());
5943 Timecode::BBT_Time bbt;
5944 _session->tempo_map().bbt_time (start, bbt);
5945 _session->tempo_map().add_tempo (Tempo (beats_per_minute, t.note_type()), bbt);
5948 XMLNode& after (_session->tempo_map().get_state());
5950 _session->add_command (new MementoCommand<TempoMap>(_session->tempo_map(), &before, &after));
5951 commit_reversible_command ();
5955 Editor::split_region_at_transients ()
5957 AnalysisFeatureList positions;
5959 RegionSelection rs = get_regions_from_selection_and_entered ();
5961 if (!_session || rs.empty()) {
5965 _session->begin_reversible_command (_("split regions"));
5967 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ) {
5969 RegionSelection::iterator tmp;
5974 boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion> ((*i)->region());
5976 if (ar && (ar->get_transients (positions) == 0)) {
5977 split_region_at_points ((*i)->region(), positions, true);
5984 _session->commit_reversible_command ();
5989 Editor::split_region_at_points (boost::shared_ptr<Region> r, AnalysisFeatureList& positions, bool can_ferret, bool select_new)
5991 bool use_rhythmic_rodent = false;
5993 boost::shared_ptr<Playlist> pl = r->playlist();
5995 list<boost::shared_ptr<Region> > new_regions;
6001 if (positions.empty()) {
6006 if (positions.size() > 20 && can_ferret) {
6007 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);
6008 MessageDialog msg (msgstr,
6011 Gtk::BUTTONS_OK_CANCEL);
6014 msg.add_button (_("Call for the Ferret!"), RESPONSE_APPLY);
6015 msg.set_secondary_text (_("Press OK to continue with this split operation\nor ask the Ferret dialog to tune the analysis"));
6017 msg.set_secondary_text (_("Press OK to continue with this split operation"));
6020 msg.set_title (_("Excessive split?"));
6023 int response = msg.run();
6029 case RESPONSE_APPLY:
6030 use_rhythmic_rodent = true;
6037 if (use_rhythmic_rodent) {
6038 show_rhythm_ferret ();
6042 AnalysisFeatureList::const_iterator x;
6044 pl->clear_changes ();
6045 pl->clear_owned_changes ();
6047 x = positions.begin();
6049 if (x == positions.end()) {
6054 pl->remove_region (r);
6058 while (x != positions.end()) {
6060 /* deal with positons that are out of scope of present region bounds */
6061 if (*x <= 0 || *x > r->length()) {
6066 /* file start = original start + how far we from the initial position ?
6069 framepos_t file_start = r->start() + pos;
6071 /* length = next position - current position
6074 framepos_t len = (*x) - pos;
6076 /* XXX we do we really want to allow even single-sample regions?
6077 shouldn't we have some kind of lower limit on region size?
6086 if (RegionFactory::region_name (new_name, r->name())) {
6090 /* do NOT announce new regions 1 by one, just wait till they are all done */
6094 plist.add (ARDOUR::Properties::start, file_start);
6095 plist.add (ARDOUR::Properties::length, len);
6096 plist.add (ARDOUR::Properties::name, new_name);
6097 plist.add (ARDOUR::Properties::layer, 0);
6099 boost::shared_ptr<Region> nr = RegionFactory::create (r->sources(), plist, false);
6100 /* because we set annouce to false, manually add the new region to the
6103 RegionFactory::map_add (nr);
6105 pl->add_region (nr, r->position() + pos);
6108 new_regions.push_front(nr);
6117 RegionFactory::region_name (new_name, r->name());
6119 /* Add the final region */
6122 plist.add (ARDOUR::Properties::start, r->start() + pos);
6123 plist.add (ARDOUR::Properties::length, r->last_frame() - (r->position() + pos) + 1);
6124 plist.add (ARDOUR::Properties::name, new_name);
6125 plist.add (ARDOUR::Properties::layer, 0);
6127 boost::shared_ptr<Region> nr = RegionFactory::create (r->sources(), plist, false);
6128 /* because we set annouce to false, manually add the new region to the
6131 RegionFactory::map_add (nr);
6132 pl->add_region (nr, r->position() + pos);
6135 new_regions.push_front(nr);
6140 /* We might have removed regions, which alters other regions' layering_index,
6141 so we need to do a recursive diff here.
6143 vector<Command*> cmds;
6145 _session->add_commands (cmds);
6147 _session->add_command (new StatefulDiffCommand (pl));
6151 for (list<boost::shared_ptr<Region> >::iterator i = new_regions.begin(); i != new_regions.end(); ++i){
6152 set_selected_regionview_from_region_list ((*i), Selection::Add);
6158 Editor::place_transient()
6164 RegionSelection rs = get_regions_from_selection_and_edit_point ();
6170 framepos_t where = get_preferred_edit_position();
6172 _session->begin_reversible_command (_("place transient"));
6174 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6175 framepos_t position = (*r)->region()->position();
6176 (*r)->region()->add_transient(where - position);
6179 _session->commit_reversible_command ();
6183 Editor::remove_transient(ArdourCanvas::Item* item)
6189 ArdourCanvas::Line* _line = reinterpret_cast<ArdourCanvas::Line*> (item);
6192 AudioRegionView* _arv = reinterpret_cast<AudioRegionView*> (item->get_data ("regionview"));
6193 _arv->remove_transient (*(float*) _line->get_data ("position"));
6197 Editor::snap_regions_to_grid ()
6199 list <boost::shared_ptr<Playlist > > used_playlists;
6201 RegionSelection rs = get_regions_from_selection_and_entered ();
6203 if (!_session || rs.empty()) {
6207 _session->begin_reversible_command (_("snap regions to grid"));
6209 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6211 boost::shared_ptr<Playlist> pl = (*r)->region()->playlist();
6213 if (!pl->frozen()) {
6214 /* we haven't seen this playlist before */
6216 /* remember used playlists so we can thaw them later */
6217 used_playlists.push_back(pl);
6221 framepos_t start_frame = (*r)->region()->first_frame ();
6222 snap_to (start_frame);
6223 (*r)->region()->set_position (start_frame);
6226 while (used_playlists.size() > 0) {
6227 list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
6229 used_playlists.pop_front();
6232 _session->commit_reversible_command ();
6236 Editor::close_region_gaps ()
6238 list <boost::shared_ptr<Playlist > > used_playlists;
6240 RegionSelection rs = get_regions_from_selection_and_entered ();
6242 if (!_session || rs.empty()) {
6246 Dialog dialog (_("Close Region Gaps"));
6249 table.set_spacings (12);
6250 table.set_border_width (12);
6251 Label* l = manage (left_aligned_label (_("Crossfade length")));
6252 table.attach (*l, 0, 1, 0, 1);
6254 SpinButton spin_crossfade (1, 0);
6255 spin_crossfade.set_range (0, 15);
6256 spin_crossfade.set_increments (1, 1);
6257 spin_crossfade.set_value (5);
6258 table.attach (spin_crossfade, 1, 2, 0, 1);
6260 table.attach (*manage (new Label (_("ms"))), 2, 3, 0, 1);
6262 l = manage (left_aligned_label (_("Pull-back length")));
6263 table.attach (*l, 0, 1, 1, 2);
6265 SpinButton spin_pullback (1, 0);
6266 spin_pullback.set_range (0, 100);
6267 spin_pullback.set_increments (1, 1);
6268 spin_pullback.set_value(30);
6269 table.attach (spin_pullback, 1, 2, 1, 2);
6271 table.attach (*manage (new Label (_("ms"))), 2, 3, 1, 2);
6273 dialog.get_vbox()->pack_start (table);
6274 dialog.add_button (Stock::CANCEL, RESPONSE_CANCEL);
6275 dialog.add_button (_("Ok"), RESPONSE_ACCEPT);
6278 if (dialog.run () == RESPONSE_CANCEL) {
6282 framepos_t crossfade_len = spin_crossfade.get_value();
6283 framepos_t pull_back_frames = spin_pullback.get_value();
6285 crossfade_len = lrintf (crossfade_len * _session->frame_rate()/1000);
6286 pull_back_frames = lrintf (pull_back_frames * _session->frame_rate()/1000);
6288 /* Iterate over the region list and make adjacent regions overlap by crossfade_len_ms */
6290 _session->begin_reversible_command (_("close region gaps"));
6293 boost::shared_ptr<Region> last_region;
6295 rs.sort_by_position_and_track();
6297 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6299 boost::shared_ptr<Playlist> pl = (*r)->region()->playlist();
6301 if (!pl->frozen()) {
6302 /* we haven't seen this playlist before */
6304 /* remember used playlists so we can thaw them later */
6305 used_playlists.push_back(pl);
6309 framepos_t position = (*r)->region()->position();
6311 if (idx == 0 || position < last_region->position()){
6312 last_region = (*r)->region();
6317 (*r)->region()->trim_front( (position - pull_back_frames));
6318 last_region->trim_end( (position - pull_back_frames + crossfade_len));
6320 last_region = (*r)->region();
6325 while (used_playlists.size() > 0) {
6326 list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
6328 used_playlists.pop_front();
6331 _session->commit_reversible_command ();
6335 Editor::tab_to_transient (bool forward)
6337 AnalysisFeatureList positions;
6339 RegionSelection rs = get_regions_from_selection_and_entered ();
6345 framepos_t pos = _session->audible_frame ();
6347 if (!selection->tracks.empty()) {
6349 /* don't waste time searching for transients in duplicate playlists.
6352 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
6354 for (TrackViewList::iterator t = ts.begin(); t != ts.end(); ++t) {
6356 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*t);
6359 boost::shared_ptr<Track> tr = rtv->track();
6361 boost::shared_ptr<Playlist> pl = tr->playlist ();
6363 framepos_t result = pl->find_next_transient (pos, forward ? 1 : -1);
6366 positions.push_back (result);
6379 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6380 (*r)->region()->get_transients (positions);
6384 TransientDetector::cleanup_transients (positions, _session->frame_rate(), 3.0);
6387 AnalysisFeatureList::iterator x;
6389 for (x = positions.begin(); x != positions.end(); ++x) {
6395 if (x != positions.end ()) {
6396 _session->request_locate (*x);
6400 AnalysisFeatureList::reverse_iterator x;
6402 for (x = positions.rbegin(); x != positions.rend(); ++x) {
6408 if (x != positions.rend ()) {
6409 _session->request_locate (*x);
6415 Editor::playhead_forward_to_grid ()
6421 framepos_t pos = playhead_cursor->current_frame ();
6422 if (pos < max_framepos - 1) {
6424 snap_to_internal (pos, 1, false);
6425 _session->request_locate (pos);
6431 Editor::playhead_backward_to_grid ()
6437 framepos_t pos = playhead_cursor->current_frame ();
6440 snap_to_internal (pos, -1, false);
6441 _session->request_locate (pos);
6446 Editor::set_track_height (Height h)
6448 TrackSelection& ts (selection->tracks);
6450 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
6451 (*x)->set_height_enum (h);
6456 Editor::toggle_tracks_active ()
6458 TrackSelection& ts (selection->tracks);
6460 bool target = false;
6466 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
6467 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*x);
6471 target = !rtv->_route->active();
6474 rtv->_route->set_active (target, this);
6480 Editor::remove_tracks ()
6482 TrackSelection& ts (selection->tracks);
6488 vector<string> choices;
6492 const char* trackstr;
6494 vector<boost::shared_ptr<Route> > routes;
6495 bool special_bus = false;
6497 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
6498 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*x);
6502 if (rtv->is_track()) {
6507 routes.push_back (rtv->_route);
6509 if (rtv->route()->is_master() || rtv->route()->is_monitor()) {
6514 if (special_bus && !Config->get_allow_special_bus_removal()) {
6515 MessageDialog msg (_("That would be bad news ...."),
6519 msg.set_secondary_text (string_compose (_(
6520 "Removing the master or monitor bus is such a bad idea\n\
6521 that %1 is not going to allow it.\n\
6523 If you really want to do this sort of thing\n\
6524 edit your ardour.rc file to set the\n\
6525 \"allow-special-bus-removal\" option to be \"yes\""), PROGRAM_NAME));
6532 if (ntracks + nbusses == 0) {
6537 trackstr = _("tracks");
6539 trackstr = _("track");
6543 busstr = _("busses");
6550 prompt = string_compose (_("Do you really want to remove %1 %2 and %3 %4?\n"
6551 "(You may also lose the playlists associated with the %2)\n\n"
6552 "This action cannot be undone, and the session file will be overwritten!"),
6553 ntracks, trackstr, nbusses, busstr);
6555 prompt = string_compose (_("Do you really want to remove %1 %2?\n"
6556 "(You may also lose the playlists associated with the %2)\n\n"
6557 "This action cannot be undone, and the session file will be overwritten!"),
6560 } else if (nbusses) {
6561 prompt = string_compose (_("Do you really want to remove %1 %2?\n\n"
6562 "This action cannot be undon, and the session file will be overwritten"),
6566 choices.push_back (_("No, do nothing."));
6567 if (ntracks + nbusses > 1) {
6568 choices.push_back (_("Yes, remove them."));
6570 choices.push_back (_("Yes, remove it."));
6575 title = string_compose (_("Remove %1"), trackstr);
6577 title = string_compose (_("Remove %1"), busstr);
6580 Choice prompter (title, prompt, choices);
6582 if (prompter.run () != 1) {
6587 Session::StateProtector sp (_session);
6588 for (vector<boost::shared_ptr<Route> >::iterator x = routes.begin(); x != routes.end(); ++x) {
6589 _session->remove_route (*x);
6595 Editor::do_insert_time ()
6597 if (selection->tracks.empty()) {
6601 InsertTimeDialog d (*this);
6602 int response = d.run ();
6604 if (response != RESPONSE_OK) {
6608 if (d.distance() == 0) {
6612 InsertTimeOption opt = d.intersected_region_action ();
6615 get_preferred_edit_position(),
6621 d.move_glued_markers(),
6622 d.move_locked_markers(),
6628 Editor::insert_time (
6629 framepos_t pos, framecnt_t frames, InsertTimeOption opt,
6630 bool all_playlists, bool ignore_music_glue, bool markers_too, bool glued_markers_too, bool locked_markers_too, bool tempo_too
6633 bool commit = false;
6635 if (Config->get_edit_mode() == Lock) {
6639 begin_reversible_command (_("insert time"));
6641 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
6643 for (TrackViewList::iterator x = ts.begin(); x != ts.end(); ++x) {
6647 /* don't operate on any playlist more than once, which could
6648 * happen if "all playlists" is enabled, but there is more
6649 * than 1 track using playlists "from" a given track.
6652 set<boost::shared_ptr<Playlist> > pl;
6654 if (all_playlists) {
6655 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*x);
6657 vector<boost::shared_ptr<Playlist> > all = _session->playlists->playlists_for_track (rtav->track ());
6658 for (vector<boost::shared_ptr<Playlist> >::iterator p = all.begin(); p != all.end(); ++p) {
6663 if ((*x)->playlist ()) {
6664 pl.insert ((*x)->playlist ());
6668 for (set<boost::shared_ptr<Playlist> >::iterator i = pl.begin(); i != pl.end(); ++i) {
6670 (*i)->clear_changes ();
6671 (*i)->clear_owned_changes ();
6673 if (opt == SplitIntersected) {
6677 (*i)->shift (pos, frames, (opt == MoveIntersected), ignore_music_glue);
6679 vector<Command*> cmds;
6681 _session->add_commands (cmds);
6683 _session->add_command (new StatefulDiffCommand (*i));
6688 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*x);
6690 rtav->route ()->shift (pos, frames);
6698 XMLNode& before (_session->locations()->get_state());
6699 Locations::LocationList copy (_session->locations()->list());
6701 for (Locations::LocationList::iterator i = copy.begin(); i != copy.end(); ++i) {
6703 Locations::LocationList::const_iterator tmp;
6705 bool const was_locked = (*i)->locked ();
6706 if (locked_markers_too) {
6710 if ((*i)->position_lock_style() == AudioTime || glued_markers_too) {
6712 if ((*i)->start() >= pos) {
6713 (*i)->set_start ((*i)->start() + frames);
6714 if (!(*i)->is_mark()) {
6715 (*i)->set_end ((*i)->end() + frames);
6728 XMLNode& after (_session->locations()->get_state());
6729 _session->add_command (new MementoCommand<Locations>(*_session->locations(), &before, &after));
6734 _session->tempo_map().insert_time (pos, frames);
6738 commit_reversible_command ();
6743 Editor::fit_selected_tracks ()
6745 if (!selection->tracks.empty()) {
6746 fit_tracks (selection->tracks);
6750 /* no selected tracks - use tracks with selected regions */
6752 if (!selection->regions.empty()) {
6753 for (RegionSelection::iterator r = selection->regions.begin(); r != selection->regions.end(); ++r) {
6754 tvl.push_back (&(*r)->get_time_axis_view ());
6760 } else if (internal_editing()) {
6761 /* no selected tracks, or regions, but in internal edit mode, so follow the mouse and use
6764 if (entered_track) {
6765 tvl.push_back (entered_track);
6773 Editor::fit_tracks (TrackViewList & tracks)
6775 if (tracks.empty()) {
6779 uint32_t child_heights = 0;
6780 int visible_tracks = 0;
6782 for (TrackSelection::iterator t = tracks.begin(); t != tracks.end(); ++t) {
6784 if (!(*t)->marked_for_display()) {
6788 child_heights += (*t)->effective_height() - (*t)->current_height();
6792 /* compute the per-track height from:
6794 total canvas visible height -
6795 height that will be taken by visible children of selected
6796 tracks - height of the ruler/hscroll area
6798 uint32_t h = (uint32_t) floor ((_visible_canvas_height - (child_heights + _trackview_group->canvas_origin().y)) / visible_tracks);
6799 double first_y_pos = DBL_MAX;
6801 if (h < TimeAxisView::preset_height (HeightSmall)) {
6802 MessageDialog msg (*this, _("There are too many tracks to fit in the current window"));
6803 /* too small to be displayed */
6807 undo_visual_stack.push_back (current_visual_state (true));
6808 no_save_visual = true;
6810 /* build a list of all tracks, including children */
6813 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
6815 TimeAxisView::Children c = (*i)->get_child_list ();
6816 for (TimeAxisView::Children::iterator j = c.begin(); j != c.end(); ++j) {
6817 all.push_back (j->get());
6821 bool prev_was_selected = false;
6822 bool is_selected = tracks.contains (all.front());
6823 bool next_is_selected;
6825 for (TrackViewList::iterator t = all.begin(); t != all.end(); ++t) {
6827 TrackViewList::iterator next;
6832 if (next != all.end()) {
6833 next_is_selected = tracks.contains (*next);
6835 next_is_selected = false;
6838 if ((*t)->marked_for_display ()) {
6840 (*t)->set_height (h);
6841 first_y_pos = std::min ((*t)->y_position (), first_y_pos);
6843 if (prev_was_selected && next_is_selected) {
6844 hide_track_in_display (*t);
6849 prev_was_selected = is_selected;
6850 is_selected = next_is_selected;
6854 set the controls_layout height now, because waiting for its size
6855 request signal handler will cause the vertical adjustment setting to fail
6858 controls_layout.property_height () = _full_canvas_height;
6859 vertical_adjustment.set_value (first_y_pos);
6861 redo_visual_stack.push_back (current_visual_state (true));
6865 Editor::save_visual_state (uint32_t n)
6867 while (visual_states.size() <= n) {
6868 visual_states.push_back (0);
6871 if (visual_states[n] != 0) {
6872 delete visual_states[n];
6875 visual_states[n] = current_visual_state (true);
6880 Editor::goto_visual_state (uint32_t n)
6882 if (visual_states.size() <= n) {
6886 if (visual_states[n] == 0) {
6890 use_visual_state (*visual_states[n]);
6894 Editor::start_visual_state_op (uint32_t n)
6896 save_visual_state (n);
6898 PopUp* pup = new PopUp (WIN_POS_MOUSE, 1000, true);
6900 snprintf (buf, sizeof (buf), _("Saved view %u"), n+1);
6901 pup->set_text (buf);
6906 Editor::cancel_visual_state_op (uint32_t n)
6908 goto_visual_state (n);
6912 Editor::toggle_region_mute ()
6914 if (_ignore_region_action) {
6918 RegionSelection rs = get_regions_from_selection_and_entered ();
6924 if (rs.size() > 1) {
6925 begin_reversible_command (_("mute regions"));
6927 begin_reversible_command (_("mute region"));
6930 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
6932 (*i)->region()->playlist()->clear_changes ();
6933 (*i)->region()->set_muted (!(*i)->region()->muted ());
6934 _session->add_command (new StatefulDiffCommand ((*i)->region()->playlist()));
6938 commit_reversible_command ();
6942 Editor::combine_regions ()
6944 /* foreach track with selected regions, take all selected regions
6945 and join them into a new region containing the subregions (as a
6949 typedef set<RouteTimeAxisView*> RTVS;
6952 if (selection->regions.empty()) {
6956 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
6957 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(&(*i)->get_time_axis_view());
6960 tracks.insert (rtv);
6964 begin_reversible_command (_("combine regions"));
6966 vector<RegionView*> new_selection;
6968 for (RTVS::iterator i = tracks.begin(); i != tracks.end(); ++i) {
6971 if ((rv = (*i)->combine_regions ()) != 0) {
6972 new_selection.push_back (rv);
6976 selection->clear_regions ();
6977 for (vector<RegionView*>::iterator i = new_selection.begin(); i != new_selection.end(); ++i) {
6978 selection->add (*i);
6981 commit_reversible_command ();
6985 Editor::uncombine_regions ()
6987 typedef set<RouteTimeAxisView*> RTVS;
6990 if (selection->regions.empty()) {
6994 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
6995 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(&(*i)->get_time_axis_view());
6998 tracks.insert (rtv);
7002 begin_reversible_command (_("uncombine regions"));
7004 for (RTVS::iterator i = tracks.begin(); i != tracks.end(); ++i) {
7005 (*i)->uncombine_regions ();
7008 commit_reversible_command ();
7012 Editor::toggle_midi_input_active (bool flip_others)
7015 boost::shared_ptr<RouteList> rl (new RouteList);
7017 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
7018 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
7024 boost::shared_ptr<MidiTrack> mt = rtav->midi_track();
7027 rl->push_back (rtav->route());
7028 onoff = !mt->input_active();
7032 _session->set_exclusive_input_active (rl, onoff, flip_others);
7039 lock_dialog = new Gtk::Dialog (string_compose (_("%1: Locked"), PROGRAM_NAME), true);
7041 Gtk::Image* padlock = manage (new Gtk::Image (ARDOUR_UI_UTILS::get_icon ("padlock_closed")));
7042 lock_dialog->get_vbox()->pack_start (*padlock);
7044 ArdourButton* b = manage (new ArdourButton);
7045 b->set_name ("lock button");
7046 b->set_markup (string_compose ("<span size=\"large\" weight=\"bold\">%1</span>", _("Click to unlock")));
7047 b->signal_clicked.connect (sigc::mem_fun (*this, &Editor::unlock));
7048 lock_dialog->get_vbox()->pack_start (*b);
7050 lock_dialog->get_vbox()->show_all ();
7051 lock_dialog->set_size_request (200, 200);
7055 /* The global menu bar continues to be accessible to applications
7056 with modal dialogs, which means that we need to desensitize
7057 all items in the menu bar. Since those items are really just
7058 proxies for actions, that means disabling all actions.
7060 ActionManager::disable_all_actions ();
7062 lock_dialog->present ();
7068 lock_dialog->hide ();
7071 ActionManager::pop_action_state ();
7074 if (ARDOUR_UI::config()->get_lock_gui_after_seconds()) {
7075 start_lock_event_timing ();
7080 Editor::bring_in_callback (Gtk::Label* label, uint32_t n, uint32_t total, string name)
7082 Gtkmm2ext::UI::instance()->call_slot (invalidator (*this), boost::bind (&Editor::update_bring_in_message, this, label, n, total, name));
7086 Editor::update_bring_in_message (Gtk::Label* label, uint32_t n, uint32_t total, string name)
7088 label->set_text (string_compose ("Copying %1, %2 of %3", name, n, total));
7089 Gtkmm2ext::UI::instance()->flush_pending ();
7093 Editor::bring_all_sources_into_session ()
7100 ArdourDialog w (_("Moving embedded files into session folder"));
7101 w.get_vbox()->pack_start (msg);
7104 /* flush all pending GUI events because we're about to start copying
7108 Gtkmm2ext::UI::instance()->flush_pending ();
7112 _session->bring_all_sources_into_session (boost::bind (&Editor::bring_in_callback, this, &msg, _1, _2, _3));